Position computed item below element of flexbox - javascript

I'm loooking for some advice concerning the following problem.
I want to position several elements inside a flexbox since the feature shall adapt to its surroundings.
Below one of these items I want to position a computed element which will use the size of the element above it. So in essence it has a fixed (but calculated) size.
I tried solving the issue by placing the calculated element into the flexbox, but this destroys the overall behavior.
It is supposed to look roughly like this:
<Label w/o shrink> <input element, can grow> <Label w/o shrink>
<some rectangle, calculated size>
desired layout - a link since I'm not allowed to post images
In the attached example jsfiddle example of problem I'm using an input element in combination with two labels and a computed rectangle to describe the behavior. Think of the rectangle as a generic example for the problem.
Resizing of the window in terms of enlarging the window works like a charm.
Issues occur when decreasing the size.
Flex can only decrease the size of elements with a non-fixed size, such as the input element. My computed rectangle has a fixed size. So this size prevents any shrinkage of the input+rectangle container.
Idea 1: Make the calculated item a little smaller than the related input so the container itself can shrink since there is space. The input will shrink and thus the calculated rectangle will shrink as well.
See jsfiddle with a smaller rectangle
This works to some degree. If the mouse moves slowly enough when resizing the window / the changes in size happen slowly, everything is fine.
As soon as the shrinkage happens too fast for the rendering to keep up, the issue as described above occurs again.
Idea 2: Ignore the calculated element by positioning it absolutely.
See here: jsfiddle with relative and absolute positioning
I defined the outer element to be positioned relatively and the inner (the calculated element w/ "constant" width) to be positioned absolutely.
By doing this the element will be taken from the flow and everything works fine.
Almost.
Since now the rectangle is ignored, the remaining layout gets broken as well. This is not acceptable due to the usage of this feature as a component in a bigger context. In the example the last label gets positioned too high up since the div won't take into account the rectangle.
My question now is if you have further advice. If at all possible I want to avoid any calculations in javascript and solve the issue using css-related options. (Otherwise using further info of getBoundingClientRect() - such as the x position - might have been an option in some way (?) -> this way I could remove the rectangle completely from the flexbox and just position it "by hand" at the desired position).
I am happy about any further ideas.

The issue appears to be caused by using the width of the input someInput to calculate the computed-element-container width. If you use the flex item width instead then it should work.
I've updated your jsfiddle to show this - I've created a second flex container above the original, that has the same three items. I then calculate the width based on an element with id: content-box. Hopefully this will assist you with finding a solution:
https://jsfiddle.net/jamarmstrong/h9rz1t4b/

For people who might have a similar issue here's another approach I came up with while trying to adapt James solution.
See this jfiddle: jsfiddle using overflow and min-width
What I changed about my first solution:
The issue with the shrinkage is some chicken-and-egg issue: The flexbox cannot shrink further than the elements inside allow for shrinkage, but then my computed element only shrinks if another element shrinks which in turn is prevented by the flexbox itself being unable to shrink, which brings us back to the beginning.
So in my question I tried to make the flexbox ignore the element by positioning it absolutely - which messes up the overall layout.
A solution I came up with in order to allow shrinkage: Make some of the elements be able to overflow the flexbox and allow for a min-width different to auto.
This way I allow the calculated element to overflow the flexbox (which makes the flexbox kinda ignore the item). Note that you also want to adjust the min-width of certain elements.
So in the end I introduced a second flexbox which encapsulates the computed element. Both this element as well as the items inside allow both for overflow and shrinkage. (One might be able to simplify the elements a little).
The computed element can thus breach/overflow its boundaries and the overall construct can shrink. The shrinkage causes the computed element to resize right away - so temporary overflow gets fixed immediately.
You can compare this approach to James idea and decide which one suits your troubles better.

Related

Having to remove and re-apply a CSS property to make it work. Possible bug with CSS?

UPDATE: Before reading into this post and saying you need more code to replicate the issue, the simple question I am asking is:
"Have you ever had to remove and re-apply a CSS property on an element in order for that style to apply when that property was already on that element and should have been working by default? If so, what was your solution or did you know what was ultimately causing the problem?"
UPDATE 2: I'm not 100% sure but this may only be an issue with the font-size property and it being changed dynamically using Javascript. The CSS for the outer and/or inner elements that are being re-sized in Javascript works as it should, this problem seems to only occur with font sizing, in particular. Perhaps the surrounding HTML's CSS doesn't catch font-size on memory intensive style changes (like our resize function). Just a guess.
The rest of this post is a means to clarify what I am talking about.
This problem might be exclusive to Chrome. To clarify, our app is used internally by our sales team and the project was specced out to focus exclusively on Chrome, both for development and field use. Already, the styling is totally off when opening this in other browsers, since we've only had to create our CSS to be Chrome-compliant (how I got so lucky to land such a position, I don't know, haha).
I've only encountered this issue a few times in my coding career which I believe to be a bug in CSS but could just be a rare bug between Javascript making style changes in the DOM and parent container CSS not adapting to the change due to possible memory constraints or slight processing lag between Javascript applying a style to the HTML and the CSS not updating to accomdate. I think this is an important question as I think every front-end web developer has or will come across this at some point in their career.
Situation
To put it as short as possible, we have a container inside our body that we use Javascript to size to a 16:9 aspect ratio relative to the window size. Took a screenshot of the entire window. As you can see, we have the inner container sizing proportionally inside our browser window (the black area, which is the body). The inner container is where all the content for our app displays:
Our CSS is built using percentages, wherever possible. We built a 'resizeUI' function that's mainly used to change the font-sizes based on the current width/height ratio of the inner screen, though there are other elements in that function that get re-sized too, on window re-size. The window always re-sizes perfectly and anything needing specific sizing based on the inner window's width/height pixel ratio works as expected, with the child elements' percentage-based CSS adjusting appropriately. But....
The Problem
When the browser window is re-sized by clicking and dragging (incremental re-sizing) everything on the page re-sizes perfectly. However, when the window size changes drastically, and instantly, fullscreen (Maximize) to small (Restore Down), or visa versa, the font-sizes in the top menu will change BUT the CSS of the parent li will not adjust to accommodate the new font-size unless I un-check (remove) it's padding attribute and recheck it (add it back in). When I do that, it works fine. The li container really just has a padding:1% and, thus, normally adjusts it's size correctly based on the inner span's size which changes with the font re-sizes.
The parent li should automatically adjust to the change of the inner span font-size. I'm positive of this because the parent li container will automatically re-size itself when I modify the menu's font-sizes or text lengths, on the fly, in the inspector.
Here's what it normally looks like either on load or with incremental window size changes:
And here is what it looks like when I go from a small window size to full-screen using Maximize:
My (hacky) Fix
Only way I've gotten this to work is to remove the padding for the <li> elements at the top of the re-size function, then re-apply it at the bottom of the re-size function AFTER the line that re-sizes the font. However, this works 50% of the time. Only when placing a 100ms timeout at the bottom of the re-size function to re-apply the padding have I gotten it to work 100% of the time now.
To help, here's a very basic code example of what i'm working with. The ul sizes automatically to it's inner elements:
Relevant HTML
<ul>
<li class="menu-items><span>Item 1</span></li>
<li class="menu-items><span>Item 2</span></li>
<li class="menu-items><span>Item 3</span></li>
<li class="menu-items><span>Item 4</span></li>
<li class="menu-items><span>Item 5</span></li>
</ul>
Relevant CSS
ul {
position:absolute;
top:0;
right:2%;
text-align:center;
}
.menu-items {
padding: 1%;
}
Relevant Javascript
What works about 1/2 the time
function resizeUI(){
$('.menu-items').css('padding','0');
//Random other elements being re-sized
$('.menu-items span').css('font-size', properRatio + "px");
//More elements being resized
$('.menu-items').css('padding','1%');
}
Works every time
function resizeUI(){
$('.menu-items').css('padding','0');
//Random other elements being re-sized
$('.menu-items span').css('font-size', properRatio + "px");
//More elements being re-sized
setTimeout(function(){
$('.menu-items').css('padding','1%');
}, 100);
}
Ultimate Question
Has anyone else encountered similar issues when working with CSS that should adapt to the re-sizing of an element? I sense it's a memory issue or bug between Javascript and CSS, given that having to set a timeout is the only reliable way I have gotten it to work 100% of the time, and, again, this ONLY occurs on a vast, instant change in window size (Maximize to Restore down, or visa versa) but not on manual, smaller, incremental resizing. Sorry for such a verbose post/question but I have encountered this weird bug a few times before with having to remove and reapply a CSS attribute to get it to work properly and I have no doubt other developers have too.
The padding is actually working. Each unit (div or whatever you are using) is overlapping the one previous evenly because you are over 100% of the view width in total. They are being built from left to right and when it gets to the end of the max size allowed, they will all equally push over the ones previous. Also padding affects elements inside of the div and will not affect divs outside of itself. So they are all the correct size but you have not established a rule that would stop divs from overlapping. Margin can do that but if they are over 100% of the desired size you will have to deal with over flow in some way. You can try to use auto for padding, but margin may be better. Otherwise you will have to play with the sizes and percentages to make it fit to the max allowed width. Checkout the CSS Box Model here.
Have you ever had an issue of having to remove and re-apply a CSS
property on an element in order for that style to apply when it was
already there and should have been working by default?
Yes: https://stackoverflow.com/a/34245989/1529630
What was your solution?
Unsetting the styles and resetting them immediately after didn't work, probably because the browser hadn't updated the page yet, and then it detected that I resetted so at the end it did nothing.
Unsetting and resetting in a timeout worked, but caused annoying blinks.
In my case, the solution was removing the element and inserting it back immediately.
window.addEventListener('resize', function() {
// Force a rerender
var parent = element.parentNode,
next = element.nextSibling;
parent.removeChild(element);
parent.insertBefore(element, next);
});
Warning: this will force the browser to do layout, paint and composite operations, which is expensive.

Get HTML element size

I spend couple of hours to try to get width of my div container. I read many questions and answers but none of them seem to work in my case - I always got 0. Finally I found that I can get it through scrollWidth property which wasn't even mentioned in this question and similar.
Now I have what I wanted by I still have no idea how this works.
Why all the other methods fail? Why this is named scrollWidth? I don't want to scroll anything - it's so confusing. Can I get the size of an element before I append it to a document - even scrollWidth don't work in that case. Is there any model I should follow to always get what I see on the screen? I can't see any patterns right now, I write someting, see something different on the screen, and get something even more different in the output. Every time I want to do someting it seem to be 10 different methods I can use but usually only one or two work because it depends on which methods I used earlier. When i work with 2d graphics I used to have x,y,width and height but in html I allways got those smarty CSS which seem to know better what I want to do. Sorry if this sound a little officious but I'm a little annoyed when i need to spend so much time on a trivial task like this. I use to draw graphic on canvas and it was much simpler but now I want to make a simple website so it's probably not a good idea to build it this way.
Here is my example
I understand that i get 0 size becouse those properties refer to element independently of its children and my container has 0,0 size, right? I read that if I set display: inline-block; style it will adapt size to match its children automatically - why this in not working?
The container element in fact has no width. This is why you are getting widths of zero. You can see this if you use dev tools element inspector.
The reason for it being that the container element is absolutely positioned and has no set width. Your child elements are also position: absolute and therefore they will not force the container element to 'grow' to their size.
To get the visible width of the menu, instead you could total up the widths of all the child elements (the first-level menu items). This is probably the best approach to use for the way you currently have things set up. Otherwise, I would suggest completely changing your approach with the html elements you are using, to the CSS properties you are using to position elements where it would not be required to use position: absolute.
I would advise you to open up your dev tools element inspector and start looking at how things react when you change the position from 'absolute' to 'relative'.
Understanding how to position elements and how widths/heights are affected using CSS will save you a lot of headaches - like the one you are having now :)
document.getElementById("mydiv").offsetWidth
This will return the width, including padding.

Make a content visible when mouseover on 1/3 width of container without adding subcontainers

I have div container with width 100%. I need to make a content hide and show according to mouse over in container. But this will need to happen with 30% from left of main container and rest(70%) with no show/hide effect. Can we make this effect without adding any additional sub containers?
An Image representation
How to make this effect?
This Fiddle illustrates a very basic solution; it calls the effect every time the mouse moves inside the 30%, so you might need to add some further logic to prevent that happening.
I've used a container of 500px width, and a subcontainer div, but only for illustrative purposes; the JavaScript will manage a single container of any width. You'll need to add any positioning, margin or padding to the 'widthModifier' variable, but you could get those from the container in JavaScript too, if you wanted.
Daniel's answer doesn't solve the problem showing and hiding the content. Take a look at my solution that does exactly what you want. I used CSS features to achieve the result.
Use Chrome to view the example. For other browsers you just have to add their specific implementations of the css features.

Animate page reflow?

I am switching the contents of divs (fading old contents out, then fading new contents in) and because they are slightly different contents, the moment they change there is a jarring reorganization of everything below them.
My question is, is there a way to make this movement smooth?
I suspect that pretty much the only feasible way to do this is to use javascript to determine ahead of time what the heights (in my case I only deal with blocks where the vertical alignment shifts) of the starting and ending elements are, and assign these values directly. Once I do this I am sure CSS3 transition will apply a pleasant animation.
Is there perhaps a way to get this without specifying explicit dimensions? I seem to recall at some point having experienced items getting moved around the page in an animated fashion. This gives me hope that it could be done using just CSS.
I'd normally create a temporary (invisible) element holding new content so as to calculate its height. After that, the original element can be animated from its current height to the newly calculated height.
It is important that the temporary element created is an identical sibling of the original element so that all the necessary styles cascade and get inherited correctly (for instance, calculating new content height is useless if it doesn't have correct font-size applied)
While animating between different heights set explicitly (i.e. with JS as described above) can be accomplished with CSS3 (transition: height .5s ease;), it will not work for different heights set implicitly (i.e. modifying element content with height:auto)

Why isn't z-index working as I'd expect it to here?

A requirement for a current project of mine involves "highlighting" an HTML element in the context of a page. That is, I need to provide some sort of visual effect that decreases the brightness of the surrounding page while leaving the element at full brightness.
To achieve this, I'm trying the following approach:
Determining the highest z-index value of any element on the page (using JavaScript).
Creating an element to function as a "backdrop" on top of the page. This is just a <div> with a translucent gray background image, sized to 100% of the width and height of the <body> element, with position: fixed. I set its z-index to 1 greater than the highest z-index I've found on the page, with the intent that it will overlay every other element on the page.
Change the z-index of the "highlighted" element to 1 greater than the backdrop. The intent is to allow it to sit on top of the backdrop, which in turn sits on top of the rest of the page.
I got it working on a quick test page:
http://troy.onespot.com/static/stack_overflow/z_index_test.html
but when I tried to set it up on a few actual Web pages, it didn't work in all cases. For example:
http://troy.onespot.com/static/stack_overflow/z_index.html
Here, I've inserted two "dummy" elements on a copy of a Jacksonville.com article page, both with a class of test (if you're looking at the page source, they're at lines 169 & 859).
I also added some JavaScript (using jQuery) at the very end of the page that functions as I've described above.
The first <div class="test"> does function as I'd expect it to. However, the second one does not - it seems to still be stuck beneath the "backdrop" element, despite having a higher z-index.
I think this may have something to do with stacking contexts, but after reading through the relevant W3C docs (http://www.w3.org/TR/CSS21/visuren.html#z-index & http://www.w3.org/TR/CSS21/zindex.html), I still can't fathom why this is happening. I'd appreciate anyone more familiar with z-index and stacking order than I to take a look at my examples and let me know if anything looks suspicious.
Please note that I've only tested these examples in Firefox v3.6.
Thanks very much for any help!
The problem is that the second test div is inside a bunch of other HTML elements, one of which must be creating a new stacking context (it may be the #wl-wrapper-tier-1 div). Basically, a new stacking context is created whenever an element is positioned and has a z-index other than auto, see this MDC article for more info on stacking contexts.
Ultimately this means you can't achieve your desired effect reliably with this method. I think you're probably better off composing 4 divs to surround the target element.
If the element that you're highlighting is inside a different element (stacking context) with a z-index lower than the backdrop, it will not appear higher than the backdrop, since the element's z-index only controls stacking order within that parent.
The only good solution is to clone the highlighted element and add the clone to the <body> tag.
Beware of inherited CSS styles, which would be lost.

Categories

Resources