In css2.1 spec, w3.org, there is a example explain the way how containing blocks are formed.
<P id="p2">This is text
<EM id="em1">
in the
<STRONG id="strong1">second</STRONG>
paragraph.
</EM>
</P>
when position em as static, strong's containing block is established by p, but when position em as absolute, strong's containing block is established by em.
I look through the chapter about containing block and can't find whether absolute position will form a new containing block or not. Is there something that im missing?
We establish that #strong1 is a non-positioned inline box. Therefore, from the spec,
[...] if the element's position is 'relative' or 'static', the containing block is formed by the content edge of the nearest block container ancestor box.
When #em1 is not absolutely positioned, it remains an inline box. The nearest block container ancestor box to #strong1 is #p2, therefore #p2 is its containing block.
When #em1 is absolutely positioned, it turns into a block box as shown in section 9.7. This makes it the nearest block container ancestor box to #strong1, therefore #em1 becomes its containing block. A block box is defined as a block-level block container box.
So does absolute positioning cause an element to establish a containing block for relatively positioned or non-positioned boxes? Yes, but only when absolute positioning results in the element's box becoming the nearest block container ancestor of those boxes.
Note that this is a rather simplified case, since the only boxes in #em1 are inline boxes (including the two anonymous inlines surrounding #strong1). Besides the fact that not all block-level boxes are block containers (tables being a common example of a block-level box that's not a block container box), even if absolute positioning does result in an element generating a block box, since we're talking about an inline box here, it may very well be that the inline box's block container is an anonymous block box within the absolutely positioned element, if that element happens to contain a mix of both block-level and inline-level boxes. This complicated case is detailed in section 9.2.1.1.
But the complications don't stop there. The reason I say "it may very well be" is because whether or not an anonymous block box is capable of establishing a containing block isn't defined in CSS2.1.
If I understand your question correctly, yes em with absolute positioning will become the new containing block. Try changing the properties in this demo:
p{
//position: absolute;
overflow: hidden;
}
em{
position: absolute;
overflow: hidden;
background: yellow;
padding: 10px;
top: 10px;
}
strong{
padding: 20px;
background: red;
}
https://jsfiddle.net/xvrjve6s/
Related
source spec: Anonymous block boxes.
I'm confused about this sentence.
When such an inline box is affected by relative positioning, any resulting translation also affects the block-level box contained in the inline box.
I don't know whether the "relative positioning" is the general meaning, I mean it can be absolute or fixed, and other properties of display, e.g, inline-block.
Let's see examples.
I know DIV broke the line box, but position: relative seems useless, I can remove it directly.
.father {
position: relative;
border: 1px solid red;
}
<span class="father">
<div>Hi Wick</div>
</span>
But, If I modified relative to absolute, I knew the line box wasn't "broke", so border worked normally. If I added the inline-block property of display, the result is the same.
.father {
position: absolute;
border: 1px solid red;
}
<span class="father">
<div>Hi Wick</div>
</span>
Also, what does any resulting translation mean? I know some behaviors may change containing block, so they will be affected by their descendants. I'm not sure whether it is about the containing block.
Therefore, I need some examples!
A <span> element is inline, which means it has no "box" around it to apply a border to. It's treated the same as a line of text with no container. Imagine it as a horizontal line where the center of each letter inside it is placed on that line. Applying position: absolute; to a <span> causes it to be treated the same as if it was display: block;, which is why the border property works on it then.
In your first example, the inner div is a block level element inside an inline element. If you applied a border to the div, you'd see it stretches across the width of the container to fill the space horizontally. Since the parent span is inline, the border doesn't show like you want it to, but the height of the child div at least gives some level of "size" to the span, if only vertically.
Also, "any resulting translations" just refers to CSS properties that move the element on the screen, such as left, right, top, bottom, or transform: translate();.
I've been having a really hard time figuring out exactly what a Block Formatting Context is.
I've read the CSS specs but it just doesn't make sense to me.
So if given this classic problem
.container {
background-color: green;
border: solid 1px black;
}
.container div {
float: left;
width: 20%;
background-color: lightgreen;
}
<body>
<div class="container">
<div>Sibling</div>
<div>Sibling</div>
</div>
</body>
I've learned to solve it by creating a new Block Formatting Context within .container. This way, the .container div will expand and wrap the siblings floated elements.
.container {
background-color: green;
border: solid 1px black;
overflow: hidden;
}
.container div {
float: left;
width: 20%;
background-color: lightgreen;
}
<body>
<div class="container">
<div>Sibling</div>
<div>Sibling</div>
</div>
</body>
My understanding would be the following :
The root element of my html document (here <body>) creates a root block formatting context.
All subsequent positionned boxes participate in this root block formatting context (given they are not floated or absolutely positionned) and are hereby positionned accordingly to the Block Formatting Context Rules.
This is the normal flow positioning.
Adding float:left to my siblings elements get them out of the normal flow and act accordingly to other rules defined in the float property section of the specs.
Then, adding overflow:hidden to my .container div creates a new block formatting context that wraps the float. Because when a block box establishes a new Block Formatting Context it becomes the reference to which the children are positioned.
Now, this is my question :
Why are the float gotten out of the root block formatting context but are wrapped in my .container block formatting context? Why aren't they out of the flow entirely?
What's the difference between the root block formatting context and the new block formatting context established by the .container div?
The phrase "a box's containing block" means "the containing block in which the box lives," not the one it generates. Visual Formatting Model w3.org
In other words, the floated divs shown have a containing block of the .container div element, and inside of that block, they have been removed from the normal flow.
The next part is a little trickier, and I am not sure why this was done, but here is what was done. Although a div without a width definition can never overflow (it's width will always be 100% of its content width), using overflow:hidden when there is a float involved has some silent implications.
The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself. - Floats w3.org
The result of the "must not overlap" rule here is that the containing box will have to have its height adjusted in an edge case of a "block-level, non-replaced element in the normal flow".
In addition, if the element has any floating descendants whose bottom margin edge is below the element's bottom content edge, then the height is increased to include those edges. Only floats that participate in this block formatting context are taken into account, e.g., floats inside absolutely positioned descendants or other floats are not. - 'Auto' heights for block formatting context roots w3.org
Based on that, the height of the .container div is extended to cover the floated nested div elements and exhibits the difference you are seeing.
In css2.1 spec, it says:
A floated box is shifted to the left or right until its outer edge touches the containing block edge or the outer edge of another float.
I wonder what's the containing block of floated elements, and I test:
body {
position: relative;
margin: 5px;
padding: 10px;
}
p {
float: left;
position: absolute;
margin: 10px;
}
<body>
<p>hehe</p>
</body>
According to css2.1 spec, the absolute positioned element's containing block is the nearest positioned block container's padding box.
But in the code above, the floated element is floated to the content box boundary. I'm confused how to find the containing block of the floated element.
The premise of your question is flawed. An absolutely positioned element cannot float, and a float cannot be absolutely positioned. From section 9.7:
[...] if 'position' has the value 'absolute' or 'fixed', the box is absolutely positioned, the computed value of 'float' is 'none' [...]
So you're not trying to find the containing block of a float here. You're trying to find the containing block of an absposed element.
Having said that, if you really must know, the containing block of a float is the same as for relatively positioned or non-positioned elements as I described in my answer to your previous question, since floats cannot be absposed.
w3.org/TR/CSS2 says:
For other elements, if the element's position is 'relative' or 'static', the containing block is formed by the content edge of the nearest block container ancestor box.
What does it mean? I read it as position: relative doesn't affect an element itself, but actually affects its parent - the containing block.
So, to change CSS of the containing block do I have to apply position to its child?
Isn't it strange? There is a pattern when you apply position: relative to a parent, and position: absolute to some of its child to make that absolutely positioned child be tied to a parent.
...actually affects its parent - the containing block.
The point of
... if the element's position is 'relative' or 'static', the containing
block is formed by the content edge of the nearest block container
ancestor box.
is to explain that its parent is not necessarily its containing block.
Most notably, if it is position:relative and its parent is display:inline, then its parent is not its containing block, but an element further up the DOM tree is instead.
position: relative means that the element which has been given a relative position will adjust itself relative to itself. For example:
An h1 is given the following CSS:
h1 {
position: relative;
top: 20px;
left: 20px;
}
then it will move 20px top and left from its original position. Check my fiddle: https://jsfiddle.net/w6sowku5/
I have two spans inside each other. On the inner span I have overflow-x:hidden. This causes extra space below the inner span. Why?
<span style="" class="yavbc-color-tip"><span style="">Some text</span></span>
Fiddle: http://jsfiddle.net/U92ue/
Note: I have only tested in latest Chrome.
Visual formatting model - 9.4.1 Block formatting contexts
Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.
More specifically, a new block formatting context is established when the overflow property is changed. By default, an element's vertical-align property value is baseline. You can simply change this to something like top in order to fix this.
Updated Example
span.yavbc-color-tip span {
display: inline-block;
padding: 3px;
border-radius: 8px;
border: none;
background-color:#005e8e;
color:#7cd3ff;
overflow-x: hidden; /* This gives extra space under this span. Why? */
vertical-align:top;
}
Notice this doesn't happen when the element's display isn't changed to inline-block? It doesn't occur with inline elements - example demonstrating this.
Despite the above quote in the accepted answer, this behavior has nothing to do with Block Formatting Context and with "block" part of the inline-block value at all. It's all about the "inline" part of it.
All inline-* elements participate in the Inline Formatting Context. That means, they are placed inside the so called "line boxes" along with text and other inline-level elements. These elements and text are aligned with each other, so the height of each line box is calculated from the top of the highest element to the bottom of the lowest one.
By default, inline-level elements are aligned with the baseline of their fonts (see first line in the example below). Even if parent element has no actual text, the position of the baseline and the minimal height of the line box are calculated as if it had text (the spec calls this "imaginary" text the "strut" of the element). That's why the line box always has some space above the baseline (for the font ascenders and diacritics) and below it (for the font descenders) — see the second line of the example.
The tricky part for the inline-block elements is that overflow property changes what is considered the baseline for these elements (end of section 10.8.1 of the spec):
The baseline of an 'inline-block' is the baseline of its last line box in the normal flow, unless it has either no in-flow line boxes or if its 'overflow' property has a computed value other than 'visible', in which case the baseline is the bottom margin edge.
So, while technically the space below the baseline is always reserved, with default overflow: visible, the inline-block element is placed so that its text's baseline is aligned with the parent baseline, and its bottom part is moved below it. In many cases this makes this inline-block the lowest element in the line, so the space reserved for font descenders is not visible. However, changing the overflow value makes the whole element render above the baseline (like an <img> element), making all this space visible.
p {
margin: .5em;
font: 32px/1.5 serif;
color: #fff;
background: #888;
}
span {
display: inline-block;
font: 12px/1 sans-serif;
background: #fff;
color: #000;
padding: 2px;
border: 1px solid green;
}
.ovh {
overflow: hidden;
border-color: red;
}
<p>Text with image <img src="http://via.placeholder.com/30x15"> and <span>two</span> <span>inline-block</span>s</p>
<p><img src="http://via.placeholder.com/30x15"> <span>only</span> <span>inline-blocks</span></p>
<p><img src="http://via.placeholder.com/30x15"> <span>regular</span>, the <span class="ovh">overflowed</span> trick</p>
In general, inline formatting is tricky. You can find a good explanation of some of its gotchas and surprises in this article: http://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align.
I'd say that a good rule of thumb would be not using display: inline-* for its side effects, if you aren't really going to place the element inside the text. In the OPs example, the best solution would be to use display: block for the inner span, that doesn't involve any "magic" like line box calculation.