How are the widths of nested absolutely positioned elements determined? - css

Example:
<style>
div {
position:absolute; left:auto; right:auto; width:auto;
margin:0; padding:0; border:0;
}
</style>
<div id="containingBlock">
foo
<div id="inner">this is my text</div>
</div>
To determine the widths of both divs, we need the shrink-to-fit algorithm in http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width *
Let's start with #inner:
get the preferred minimum width
this
is
my
text
|----| preferred minimum width
get the preferred width
this is my text
|---------------| preferred width
compare both to available width:
computed width = min(max(preferred minimum width, available width),
preferred width)
Easy. But what is available width? Since we got no margins/paddings/borders, it's simply the width of containingBlock. But now we get an infinite loop, since the same algorithm applies again:
get the preferred minimum width of containingBlock
foo
+-------+
| inner |
+-------+
|--?????--| preferred minimum width
In other words: to get the width of inner, we must know the width of containingBlock and vice versa.
In reality, it looks like browsers just assume available width = 0 in this case: http://jsfiddle.net/pxvJJ/6/.
But this is not covered by the specs, or am I missing something obvious?
* (note that this spec has not yet been superseded by CSS3)

If we read carefully through the specs, we'll find that
CSS 2.1 does not define the exact [shrink-to-fit] algorithm.
It's supposed to be
similar to calculating the width of a table cell using the automatic table layout algorithm
which, in turn, is implementation-dependent.
So, the above example shows that excluding #inner from the calculation of containingBlock's preferred minimum width may be a good idea when implementing a straight-forward algorithm, and we'd end up with this:
|---| preferred minimum width
foo
+-------+
| inner |
+-------+
|--?????--|
which is probably what browsers do.
That being said, the question is: Which elements do actually contribute to containingBlock's preferred minimum width?
Let's see what happens if #inner has position:static; width: auto. This case is even harder. Again, the specs give the constraint
'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block
with no shrink-to-fit allowed this time. And, again, it cannot be solved. Or can it? Funny enough, it can! Let's see what actually happens: http://jsfiddle.net/pxvJJ/12/
Apparently, the statically positioned divs are treated differently. So I suppose the algorithm to determine width of containing block goes like this:
determine the preferred width of all contained block boxes in normal flow.
set width of containing block = maximum of those preferred widths
calculate the width of all contained boxes, now that width of containing block is known
I am still confused as to why (all) browsers do this. There seems to be no reason for treating absolutely positioned elements differently in this regard.

Related

What are the problems of my box size determination?

<html>
<body>
<style>
#div11 {
height: 100%;
}
</style>
<div id="div1">
<div id="div11"></div>
</div>
</body>
</html>
In above case I think heights of div1 and div11 both are 0. Below is my inference.
There is a cyclic dependence of box size between div1 and div11: Generated box b1 of div1 is containing block of generated box b11 of div11. b1's height is initial value auto. So b1's height depends on b11's. b11's height is specified as a percentage value which depends on its containing block that is b1.
The closed dependence is resolved in below way. Section 10.5 of CSS 2.1 prescribes: " If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value (of the element's height) computes to 'auto' ", so b11's height computes to auto.
After resolving closed dependence box size is determined in such way: b11 has not content so its height is 0 according to rule 4 in section 10.6.3 of the specification. Then b1's auto height computes to 0.
But the actual rendering in browser is different. What are the problems of my inference? Do I misunderstand some rules or ignore some semantics in the specification? Thank for your help very much.
You are quoting the correct part of the specification. The reason that's not what you experience is because by not specifying a DOCTYPE. you've put the browser in quirks mode. So the browser is behaving quirkily different from the CSS standand, and what you have to look at instead is the Quirks mode standard.
In this case the relevant quirk is 3.5. The percentage height calculation quirk. Basically, for your example, the algorithm loops until it hits the initial containing block, and then sets div11 to 100% of the height of that, i.e. it takes the height of the viewport.

CSS center an element

Why do 'margin left and right set to auto and max. and min. width' center an element?
#header{
max-width: 1400px;
min-width: 360px;
margin-left: auto;
margin-right: auto;
}
I do not get it.
Since auto in both right and left margins take up the "available" space equally, the element is aligned to the center.
A left or right margin with auto will take up all of the "available" space making the element look like it has been flushed right or left.
Look in this source for more information.
You can easily understand with the following demo:
div{
max-width: 300px;
background-color: red;
margin-left: auto;
}
<div>
auto
</div>
In the above snippet, you can see when you use margin-left auto the div is taking up all the available space so it pushed to right. Now, you can think by using margin-right:auto; will push the element towards the left. So, using both will force it to stay at center by taking up both available space.
It divides the sum of the empty space on the right and left sides of an element by two and uses that as margin-left and margin-right, thus centering it. Another way of thinking about it is subtracting the width of the child from the width of the parent and then dividing that by 2.
In reality, margin-left and margin-right are still set to auto, so if you try to get their values in JavaScript, you are going to get "auto", but that is the logic behind it.
The math behind it is:
marginLeft = (parentWidth - childWidth) / 2
marginRight = marginLeft
As I'm not satisfied with the exhaustiveness of the other answers, here's a more detailed explanation. In general, the w3c Recommendation elaborates on this in great detail and should be consulted for questions requiring a more precise answer.
The typical use case margin: 0 auto (top and bottom set to 0, left and right to auto) works by having the browser calculate the available space and apply it to each auto value of a property, divided equally.
In the attempt to also provide a "math behind it" example (I put this in quotes, as it's a very simplified visualisation of the actual math) is much closer to this:
availableSpace = (parentWidth - childWidth)
marginLeft, marginRight = availableSpace / amountOfAutoValues
This will work under the following conditions (simplified):
it's not absolute- or fixed-positioned
it's not floating
it's not an inline element (This is to be distinguished from "it must be a block element", which is wrong - for example, inline-block won't work)
This is, because those modes already overwrite the object's place within the document, and calculating a margin is likely not advantageous.
The only requirement is just the margin setting for it to technically apply - you only need to set a width (or max-width) smaller than the parent in order to see the effect, as in any other scenario, the available space will simply be 0.
min-width will never have any effect regarding automatic margins in this way.
You could achieve the same result if instead of max-width and min-width you used display:table along with the margin + auto value and rest of the code. If left only with margin-left it will align to the extreme right corner of the page, if left only with margin-right it will align to the extreme left, now what do you think will happen if you leave it with margin-left margin-right? I'm pretty sure you won't create a paradox. :)
-------------------------> margin-left:auto
margin-right:auto <------------------------
margin-left:auto <-------> margin-right:auto

What Is Result Of calc() In CSS

We have now started using calc() in css, for setting widths on a result of calculation.
For example:
<div id='parent'>
<div id='calcWidth'></div>
</div>
#parent{
width:100px;
}
#calcWidth{
width:calc(100% - 3px);
height:100px;
background:red;
}
I know how calc() works, but I just want to know what is returned in css, in the place of calc(100% - 3px); in the example given above.
Whats my confusion?
In the above example width:calc(100% - 3px);
say the 100% width is actually 100px, which will be determined at runtime by css.
So the calculated width will be 100px-3px=97px 97px and if you convert it to % 97% right?
But now, there are two possibilities
97px is returned, which is set as a width.
97% is returned, which is set as a width.
My Question is:
In both cases now the width shall be set to 97px, but what is
returned as a result of width:calc(100% - 3px);, 97px OR 97% ?
you can also see this fiddle:
http://jsfiddle.net/8yspnuuw/1/
EDIT: please read
See friends: Take a simple example:
<div class='parent'>
<div class='child'>
</div>
</div>
.parent{
width:200px;
}
.child{
width:20%
}
I know the width of child will become 160 px when it is rendered.
okay! but thats not what is set in css right? css sets it in %, it is
just rendered in pixels.
So similarly, using calc, does it return % or pixel
Or to explain my question, read BoltClocks answer, what is the computed value, (and not the used value, i know that is in pixels)
The spec does not define very strictly what the computed value of a calc() expression is, however it does say that percentages are never calculated as part of the computed value. How exactly this value is represented is left as an implementation detail.
If you see a pixel length instead of a percentage, then that length is the used value, not the computed value, because the pixel value can only be determined after calculating any percentages and laying out elements.
Note that getComputedStyle() may return results that are inconsistent with the CSS definition of "computed value". This is one of many unfortunate consequences of browsers doing their own thing back in the 90s.
The rendered widths are in pixels.
Whatever the pixels size of the calcWidth div is, the value 3 is reduced from it..for example if the width of parent is 200 the calcWidth div's width will be 197px. so it is px and not %
Demo
document.getElementById('calcWidth').offsetWidth;
CSS does not support dynamic values (bedides simple percentage values like width: 100%;). That means the 100% within calc() are converted one time initially to px and not continiously.
That already answers your question. The %-value gets converted into px end you end up with 97px. You can confirm that with window.getComputedStyle() or by taking a screenshot and measure it.
calc() does not have a computed value; it occurs at time of render -- that is why you can mix units.

CSS - "The sum of the horizontal components of a block-level element box always equals the width of the parent?"

I am reading CSS The Definitive Guide by Eric Meyer. On page 162, it says the following:
Almost as simple is the rule that says that the sum of the horizontal components of a block-level element box in the normal flow always equals the width of the parent.
I find a similar passage in the W3C specification:
The horizontal position and size of a non-floating, block-level element is determined by seven properties: 'margin-left', 'border-left', 'padding-left', 'width', 'padding-right', 'border-right' and 'margin-right'. The sum of these seven is always equal to the 'width' of the parent element.
However, I can think of a very simple case where the above rule does not hold true.
# HTML
<div><p>This is a paragraph.</p></div>
# CSS
div { width: 200px; }
p { width: 300px; }
Obviously I could set overflow to contain the p element. However I just want to know am I interpreting the rule incorrectly?
You shouldn't read the old specifications of CSS1, except for curiosity, as you can read in the red box on the page you linked. CSS2.1 defines well this situation: in paragraph 10.3.3 you can read that such configuration is called over-constrained, and one horizontal margin is ignored and set to a value in order to make the equality true. The right one will be choose if the writing mode is left to right, otherwise it'll be the left one.
I think it means that the "sub element at 100% always equals the width of the parent". Obviously if you set the width to anything smaller/bigger it will differ. But it inherits the same width unless specifically set.

If div has a line-height of 0 and its only child, span, has line-height:0, where's the div's height coming from?

Here's my doubt. I've got a parent div with a child which is a span. Both have line-height set to 0. The span has font-size set to many many pixels (198px).
The problem: the div gets a height. But, from what, if it should come from the spans line-height, which is 0?
I set up a tinkerbin. Check it out if if you're interested.
http://tinkerbin.com/0oCT7PRf
This happens at least in firefox and chrome, so this is almost definitely a standardized behavior.
Note!
This is a css behavior doubt. I'm interested in knowing what's happening, not on "fixing" an "issue".
Thanks in advance.
The text still has a size; the letter 'F' is expanding the div to fit.
Update from the spec:
On a block container element whose content is composed of inline-level elements, 'line-height' specifies the minimal height of line boxes within the element.
http://www.w3.org/TR/CSS21/visudet.html#line-height
So the height of the box really is coming from the font-size, as the line-height is only defined as a minimum of 0, but not explicitly 0.
Yes, the is taking the height of its inner element. If you want it to correctly take its defined height/line height, you have to set it to behave as a block element ( display:block;)
Also, when hiding elements on IE using line height / height :0, IE won't collapse the element unless font-size is set to 0 as well.
The answer I've comeup with:
First facts backed by the spec:
When you have a line height greater than the font-size - what you usually see - it's pretty easy. Take the line height, subtract the font-size, divide it by 2. Apply the result to both the top and the bottom of the "glyphs box", and that's it. So if your font-size is 14px, and your line height 16px:
16px - 14px = 2px
2px / 2 = 1px
Add 1px above the "glyphs box", add 1px below it. The box gets a height of 16px, and that as expected becomes the height of the parent container (assuming, as in the case, that there's only one line-box in it).
When the line-height is less than the font-size (our case) the thing gets trickier. Lets use the same formula for a font-size of 54px and a line-height of 0.
0-154px = -154px (the spec allows a negative value here so we're alright)
-154px / 2 = -77px
So, our font has a size of 154px... and here's something else you need to know. A font has both a distance from the baseline to it's top and from the baseline to it's bottom. Pretty simple. The spec calls the first one height(A) and the second one depth(D). So A+D = distance from top to bottom.
Now here's what I think is happening in the case I presented in the question. This is what I concluded from "my fiddling" and not from the spec (since I couldn't find it there).
Let's continue with our formula.
We got -77px from dividing the result of the difference between the line-height and the font-size.
Our font-size is 154px.
Now we've got to add -77px to the top, and -77px to the bottom. Adding a negative is subtracting - so we're in fact subtracting 77px.
This is easier explained with a drawing.
So yeah, that's where I believe the height is coming from. It's at least related to it.

Resources