Why does this flex item have its height limited? - html

I've stumbled across something that happens to my flex child items, illustrated in this JSFiddle.
This is the code:
<div style="position:absolute; top:10px; left:10px; background-color:yellow; height:50px; width:200px; display:flex; flex-direction:column;">
<div style="overflow:hidden;">inner div text<br>inner div text<br>inner div text<br>inner div text<br>inner div text</div>
</div>
<div style="position:absolute; top:10px; left:250px; background-color:green; height:50px; width:200px;">
<div style="overflow:hidden;">inner div text<br>inner div text<br>inner div text<br>inner div text<br>inner div text</div>
</div>
<div style="position:absolute; top:200px; left:100px; border:1px solid black; height:300px; width:300px; overflow:hidden;">
<div style="overflow:hidden;">
Why does the inner div on the yellow left have its height limited to that of its container, but not the inner div on the green right? As far as I can tell there are 4 things combined that trigger this:<br>1) the container has position:absolute<br>
2) the container has a fixed height/width<br>
3) the container is flexbox<br>
4) the flex item has overflow:hidden<br><br>But I can't find anything exactly in the flexbox spec to cause this behaviour. Why is it happening?
</div>
</div>
Basically, the flex item inside a flexbox container with a fixed height is getting its height limited to that of the flexbox container when overflow:hidden is set. On the other hand, an equivalent div inside a fixed height non-flex container just expands to the size of its content.
Where in the flexbox spec is this behaviour specified? Is it just a browser quirk? That seems unlikely as it happens in Firefox, Chrome, and IE. Assuming it is well-defined flexbox behaviour, I'd like to know exactly how and when it is triggered. Also note that when you remove overflow:hidden from the child (not the container), its height stops getting limited.

OK, I think I figured out what's happening.
Up until flexbox, there was no way to cause an element to be smaller than the size of its content without explicitly settings its width/height. With flexbox, there is a second way.
Para 9.11 of the flexbox spec talks about how to calculate a flex-item's cross size. Basically if the flex item has align-self: stretch set (which in my example it does), it will try to fill the container's flex line (in my example the vertical line, ie. height). This is implicitly setting the flex item's height, without explicitly using the height property. The container itself needs to have a definite height, too, to be handed down to the flex item (in my example the container's height is explicitly set through the height CSS attribute, which I guess ultimately needs to be done at some point in the chain).
However, two conditions need to be met: the browser needs to want to resize the item, and the item needs to be resizable.
To make the browser want to resize the item, it needs to be a flex item that meets the conditions mentioned above for its cross size (which ultimately may determine its width or height) to be calculated by the browser with relation to its container's cross size.
To make the item resizable in this context, it needs to both not have flex-shrink set to 0 (note that flex:none is shorthand for setting flex-shrink to 0, amongst other things), and have overflow:hidden set (presumably giving the browser "permission" to resize the flex item such that its content will be larger than it, and get hidden). Only then will the browser actually resize the flex item itself.
This is notably different behaviour to what happens outside the flexbox model, where the child of a fixed height/width container may have it content clipped, but it will retain the necessary size to hold its content. Part of the content will merely be hidden. Here, the flex item really is being (potentially) resized to be smaller than its content, which has quite important implications (particularly if you want a child element to have a scrollbar for its content).

Related

CSS increase width using calc() does not affect parent container

Take a look at the following snippet. How can I increase the width of the red container with 10px?
Is there a way to increase the width of an element in CSS, still affecting the parent container? Or do I have to use a pseudo-element placeholder to accomplish this instead?
<div style="
background:blue;
display:inline-block;
height:50px">
<div style="
font-size:30px;
width:calc(100% + 20px);
background:red">
Inner container</div>
</div>
In the snippet above the blue container is not affected, and the red overflows.
Is there a way to increase width of an element by a certain amount, where the width of the element itself is not known until runtime?
You can only reliably do this using padding; however, padding will affect the layout of the element's contents, which may not be what you want. In your example, padding the child element will affect the layout of the text inside it; the content width is never really increased at all.
You can't change an element's content width by a definite amount when it is not known in advance and depends on external factors such as the amount of content it actually has, which is usually the case with floats, absolutely positioned elements, and inline-blocks. The closest you can get is an auto width, and that only has a meaningful effect on in-flow block boxes — which are none of the above — with respect to their parents, not their children.
In fact, the behavior that you see with calc(100% + 20px) is not governed by the spec, although it's as far as browsers generally go without falling into the cyclic dependency trap:
<percentage>
Specifies a percentage width. The percentage is calculated with respect to the width of the generated box's containing block. If the containing block's width depends on this element's width, then the resulting layout is undefined in CSS 2.1.
(calc() is CSS3, but the box model hasn't changed much from CSS2.1.)
If I understood correctly, you want to increase the child's initial width and add another 10px.
But when you set this property:
The width: 100% will always be relative to its parent, so if you add another 10px in relation to the 100% it will always be 10px bigger than its parent.
You may want to set just a min-width and a max-width instead of setting explicitly its width so that the child will be within some specified ranges, but to increase the width by 10px from the starting witdh using JUST CSS its not possible.
Note: Keep in min that using calc you have to add the according browser-engine property extension i.e:
-webkit-calc()
-moz-calc()
calc()
<div style="
background:blue;
display:inline-block;
height:50px">
<div style="
font-size:30px;
width: 100%;
background:red">
Inner container</div>
</div>
Hope this helps in some way, gl.

Flexbox parent shrinks smaller than children

How can I prevent this flex parent from shrinking to smaller than the height of the children? The grey container is the flex parent, the white boxes are the children.
grey box
display flex
white boxes
display block
height 200px
I discovered the problem; it was caused by a css reset with the rule:
body, html { height: 100%; }
The problem disappeared once I changed this to:
body { height:auto; min-height:100%; }
html { height: 100%; }
I found what may be the real answer. This solved it for me:
At least one of the children of a "display: flex" parent MUST have the attribute "flex: [some number]". In my scenario, once I set flex to 1 for my child, suddenly the other child stopped its odd shrinking.
Trivial answer: add min-height: 200px on the grey box (the container).
(Though: if you're not providing a height for the grey box (the flex container), it should already auto-size to fit its children's height -- though that depends on the context, e.g. if the flex container's parent is another flex container. Anyway, you'll probably have to provide more specifics & a working testcase, if you want a more appropriate answer. :))

Difference between width:auto and width:100% - what is it 100% of? (CSS)

Why does setting an element to be position:fixed change its width? I know that HTML elements by default span the entire width of the browser window, but when I set the position on my header to be fixed, the <div> shrinks to zero width. Why is this?
Trying width:auto does not fix it, the <div> still has zero width!
This example is taken from Code Academy "Build a Resume" project at the end of their Web Fundamentals course.
I have an HTML file like so:
<!DOCTYPE html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="stylesheet.css"/>
<title></title>
</head>
<body>
<div id="header"></div>
<div class="left"></div>
<div class="right"></div>
<div id="footer"></div>
</body>
</html>
and a CSS file like so:
div {
border: 5px solid red;
border-radius: 5px;
}
#header{
height:30px;
background-color:orange;
z-index:1;
}
#footer{
height:30px;
background-color:teal;
clear:both;
}
.left{
height:300px;
width:200px;
float:left;
}
.right{
height:300px;
width:200px;
float:right;
}
UPDATE: I noticed that setting width:100% does keep the width all the way across the browser window. What is going on here? I've read Why does fixed positioning alter the width of an element? but am not sure how that applies here.
Edit: Thought I would move this up from the comments and try answering it here, to give more direction on where I'm confused:
"Yes, it seems like "Whereas the position and dimensions of an element with position:absolute are relative to its containing block, the position and dimensions of an element with position:fixed are always relative to the initial containing block" is the key part. So I see that position:fixed will set the dimensions of my relative to the viewport, but isn't the viewport the whole browser window? So why does its size collapse to zero? And beyond that, why does width:auto not fix it but width:100% does make it span the whole horizontal length again?"
width:auto is different from width:100%. width:auto will expand the width of the element to all horizontal space within its containing block. Since the space is on the inside of the containing block it doesn't count borders/padding/margins.
width:100% does what width:auto does and adds the width of the borders/padding/margins of the containing element. difference between width auto and width 100 percent provides a good visual demonstration.
So, when I set width:auto on my position:fixed element, and the position:fixed shrink-wrapped the element's width to be that of its content (which was nothing), then the width automatically adjusted to be that of the containing element, which in this case was _________ (what? and why did it have a width of zero?).
When I set it to be width:100% then it includes the padding/margins/border of _________ (what? and why did it expand to cover the whole page horizontally?).
The reason is because both fixed and absolute positioning take the element out of the flow of the document. The residual effect of this is that, unless explicitly told otherwise, the element will now grow/shrink according to the size of its content rather than the size of its parent.
As you've already discovered, a simple fix is to give it a width of 100 percent:
.fixed-element{
position:fixed;
width:100%
}
To address the issue of the quote on fixed positioning:
Whereas the position and dimensions of an element with position:absolute are relative to its containing block, the position and dimensions of an element with position:fixed are always relative to the initial containing block. This is normally the viewport: the browser window or the paper’s page box.
I actually find it to be quite poorly worded. It's not meant to say that the dimensions will grow to the size of the viewport. Instead it's trying to distinguish the specific differences between absolute and fixed positioning. More thoroughly put: the dimensions/size of the fixed element will always be relative to the initial element. Whereas the dimensions/size of the absolute element will be relative to the containing element. That doesn't explicitly mean that it will actually take 100% of the viewport by default...
This is the default behavior.
Read http://www.w3.org/wiki/CSS_absolute_and_fixed_positioning#Specifying_dimensions
Absolutely positioned elements will shrink-wrap to fit their contents
unless you specify their dimensions. You can specify the width by
setting the left and right properties, or by setting the width
property. You can specify the height by setting the top and bottom
properties, or by setting the height property.

Assigning CSS width to a position:fixed element

I'd like a fixed element's width to match that of the div placed immediately below it. Imagine a header and a main content div. A problem in matching their widths occurs when the header and content divs are nested inside an outer div. In this scenario the % widths of each no longer match their parents width (e.g.,<body> tag) and the fixed element's width is based on something which is confusing me.
To better explain what I mean, contrast these two js fiddles:
http://jsfiddle.net/2dudX/4/
vs.
http://jsfiddle.net/2dudX/10/
here's the code for each:
<div id="fixed"></div>
<div id="content"></div>​
#fixed{ position:fixed; z-index:2; width:90%;
height:25px; background:yellow;}
#content{ width:90%; height:300px; background:red}
vs.
<div id="main">
<div id="fixed"></div>
<div id="content"></div>
</div >
#main{ width:95%}
#fixed{ position:fixed; z-index:2; width:90%;
height:25px; background:yellow;}
#content{ width:90%; height:300px; background:red}
Note only in jsfiddle #1 do the yellow and red divs widths match up regardless of how you resize the browser. Unfortunately, jsfiddle#2 is more of a real world scenario and I'm wondering how to correct the id="fixed" div such that its width also matches up with id="content" div.
Thoughts?
You can to it this way FIDDLE (to set % relative to the #main)
fixed element's dimensions always is calculated relative to the root element, so you need to reset %-unit accordingly
in this particular case you need to set:
#fixed {
width: 85.5%;
}
It is case #main is 95%, your static element is 90% relative to the main. So you need to calculate its width towards the root element (1 * .95 * .9 = .855)
Easy one my friend. Fixed width elements are yanked from their parents and are now relative in width to the window, so in both situations the fixed div is always relative to the size of the window, but when in a parent container with a width other than 100% the fixed element will remain relative to the window width but the non-fixed position element is now relative to the parent width. So the non-fixed element became 90% of the 95% of the window while the fixed element remained a constant 90% of the window only.
Edit:
If you wish to match the widths you can use jquery like this:
$(function(){
$('#fixed').width($('#content').outerWidth());
});

Making floated div shrink instead of dropping to new line

Is there any way I can force a floated div to shrink instead of going to a new line?
I know I can set implicit widths on the divs but it's on a menu which might have variable amounts of items in it. I'm trying to do this while keeping the site's layout fluid if possible.
#left {
float: left;
border: 1px solid #000;
}
#right {
float: right;
border: 1px solid #000;
}
<div id="left">
<p>This div represents the logo</p>
</div>
<div id="right">
<p>When the window's width is reduced and these divs touch I want this div to shrink instead of falling to the next line.
</p>
</div>
Basically, I want #right to begin shrinking when the browser window is shrunk rather than having it drop a line first, then shrink when the window is further resized.
Have you tried experimenting with giving these two divs relative (such as a percentage) widths?
When you float without explicitly declaring a width, either fixed or relative, the dimensions will default to 'auto'. Auto will force the div to be the width of it's content. When the browser shrinks, the content will still force these boxes to that width, until it is forced to collapse by touching another element.
Using auto widths is not the best way to achieve fluidity in your layout. You'll need to specify some kind of relative dimension somewhere, otherwise this problem will be entirely unavoidable.
There are lots of resources out there which can help you achieve a more fluid layout (a lot of articles on www.alistapart.com discuss this in quite some depth).
CSS's display property, set it to inline and the div will behave like a span.