Let's say that I want to make a <p> element that has a fixed height and a width that only grows if the height is not sufficient to display all of the text. By default, <p> is a block level element. This means it has a greedy width and lazy height. I want the opposite, lazy dynamic width and fixed/greedy height. An inline-block element tries to display the text in one line if possible, which is not something I want. I want a pure CSS solution just because. Is it possible?
This is not possible.
9.4.2 Inline formatting contexts
In an inline formatting context, boxes are laid out horizontally
[...]. The rectangular area that contains the boxes that form a line
is called a line box.
The width of a line box is determined by a containing block and the
presence of floats. [...]
In general, the left edge of a line box touches the left edge of its
containing block and the right edge touches the right edge of its
containing block. However, floating boxes may come between the
containing block edge and the line box edge. Thus, although line boxes
in the same inline formatting context generally have the same width
(that of the containing block), they may vary in width if available
horizontal space is reduced due to floats. [...]
Line boxes are created as needed to hold inline-level content within
an inline formatting context. [...]
Therefore, the width of the line boxes will only be affected by the width of the containing block and the presence of floats. And then, there will be as many line boxes as necessary.
Related
Excerpts from the CSS specification (emphasized by me):
9.4.2 Inline formatting contexts
A line box is always tall enough for all of the boxes it
contains.. When several inline-level boxes cannot fit horizontally
within a single line box, they are distributed among two or more
vertically-stacked line boxes.. Line boxes are stacked with no
vertical separation (except as specified elsewhere) and they never
overlap. (ref)
'line-height':
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. (ref)
Keeping it in mind, that line boxes don't allow for bleeding their content away and at once don't overlap with each other, how is it still possible we can get lines of text vertically overlapping? This result may become achievable when a container's line-height is set in ems whereas an inline descendant's font-size computed value is of a comparable number (an example is at the end of this Mozilla doc).
Following the spec I would rather expect to see vertically cropped text in this case, but not overlapped.
Regarding float, MDN says:
The element is removed from the normal flow of the page, though still remaining a part of the flow (in contrast to absolute positioning).
But it does not expand on that at all.
So I did a simple experiment. It seems when the floated element has an inline sibling, it is still part of the normal flow, allowing text and inline elements to wrap around it. But for block siblings, the floated element collapsed to have a zero height.
This behavior is further confirmed in the spec. For content (inline elements I guess?) -
The most interesting characteristic of a float (or "floated" or "floating" box) is that content may flow along its side (or be prohibited from doing so by the 'clear' property). Content flows down the right side of a left-floated box and down the left side of a right-floated box.
And for block boxes -
Since a float is not in the flow, non-positioned block boxes created before and after the float box flow vertically as if the float did not exist.
This does not feel intuitive nor consistent. Why was this design choice?
I am reading CSS specs, the section on Visual Formatting Model and trying to understand what is the difference between these two terms: containing block and block container box.
What confuses me is the variation of words that are used for what seems to be completely different concepts:
box vs block
containing vs container
Is block same as box when talking about visual formatting CSS? If not, what is the difference? Are both of these something that is "visible" on the screen?
In general, how should I think when I see block in the specification? Also what should first come to my mind when I read box in the specs?
Some helpful metaphors or analogies for these concepts would be very helpful to create a mental model.
Let's start at the beginning. CSS is almost entirely about boxes. A box is just a rectangular area of the canvas. The canvas is the entire 2D space on which everything is drawn.
CSS Boxes have a whole range of flavours. Block boxes, block-level boxes, inline boxes, inline-level boxes, content boxes, padding boxes, border boxes, margin boxes, table boxes, line boxes, flex boxes, and so on. They're all just rectangular areas.
So a block is just one type of box. Many of the above boxes are characterized by two behaviours - how they are laid out relative to their containers and peers, and how their content is laid out within them. The CSS-display spec refers to these as display-outside and display-inside respectively
Display-outside refers to the "*-level" nature of the boxes. They're not what we're interested in here.
All block boxes, and some inline-level boxes are block container boxes. A block container box is a box of type "block container", not necessarily a box that contains blocks. Block containers that are not block-level boxes include those that are display:inline-block and display:table-cell
The "block" in "block container" refers to its display-inside behaviour. Block boxes are laid out vertically within them and text flows horizontally, ordinarily limited by its edges of the rectangle.
So a "block container box" is a type of box. In contrast, "containing block" refers to a specific box. Each box defined on the canvas has exactly one containing block, with just one exception, called the initial containing block, which has no containing block.
Only a box of type "block container box" can be a box's containing block.
Time for an example. Let's suppose we have the HTML below: I'm deliberately going to use <span> elements throughout, because this is all about CSS, and I don't want to confuse with HTML behaviour.
<span id="level1">
foo
<span id="level2">
bar
<span id="level3">
baz
<span id="level4">
qux
</span>
</span>
</span>
</span>
The CSS is very simple. Just
#level1 { display:inline-block }
The other spans are the CSS default display setting, "inline".
Now, consider the #level4 span. Its parent is the '#level3' span, which is display:inline so the '#level3' span does not form a block container box. Similarly, the #level2 span also does not form a block container box. But the #level1 element is display:inline-block. That forms an inline-level box, but one that is a block container box. (This is what "inline-block" means).
So the containing block for all the inline boxes formed by the #level2, #level3, #level4 spans and their text content is the block container box formed by the #level1 element's box.
I see the w3c writing
In the case that the ancestor is an inline element, the containing
block is the bounding box around the padding boxes of the first and
the last inline boxes generated for that element. In CSS 2.1, if the
inline element is split across multiple lines, the containing block is
undefined.
I don't quite understand what's this mean, what's the diff from when the containing block is block element, Can someone give me an example?
the containing block is the bounding box around the padding boxes of
the first and the last inline boxes
in other words, width of the inline element will be equal to it's content, while width of the block level element will extend on available area (padding of ancestor reduces this area, see qoute from spec).
Otherwise, the containing block is formed by the padding edge of the
ancestor.
I've a text in side heading with multiple lines. Want the spacing the two lines to increase, so I set a line-height. When I do this, not only does it increase space between the two lines, it also increases spacing above the first line (and maybe below the second). How can I increase spacing between the two lines only, without increasing above and below.
I know it's a behavior of Line-height. but just curious if there is any good solution for this.
This is just en example to what I'm asking.
Jsfiddle: http://jsfiddle.net/jitendravyas/V3eWV/
You can use negative margins for this, although there is something to keep in mind:
line-height is a funny thing. According to CSS2.1 it doesn't specify the line-height but the minimum height of line-blocks:
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. The minimum height consists of a minimum height above the baseline and a minimum depth below it, exactly as if each line box starts with a zero-width inline box with the element's font and line height properties. We call that imaginary box a "strut." (The name is inspired by TeX.).
A line box is defined in 9.4.2 Inline formatting contexts:
In an inline formatting context, boxes are laid out horizontally, one after the other, beginning at the top of a containing block. Horizontal margins, borders, and padding are respected between these boxes. The boxes may be aligned vertically in different ways: their bottoms or tops may be aligned, or the baselines of text within them may be aligned. The rectangular area that contains the boxes that form a line is called a line box.
This doesn't change in CSS3 very much, at least if you don't change the line-stacking. However, there is no property which targets your problem directly: you can't change the line-height of the ::first-line, it will always get applied.
That said, use negative margins for the time being. Even better, wrap your elements in a generic container. By using :first-child and :last-child you can add as many elements as you like.
Example
<div>
<h1>I've a text in side heading with multiple lines. Want the spacing the two lines to increase, so I set a line-height. When I do this, not only does it increase space between the two lines, it also increases spacing above the first line.</h1>
<h1>I've a text in side heading with multiple lines. Want the spacing the two lines to increase, so I set a line-height. When I do this, not only does it increase space between the two lines, it also increases spacing above the first line.</h1>
</div>
body {padding:30px;background:yellow;border:1px solid red;margin:0}
div{background:red;margin:0;padding:0;border:1px solid green;}
h1{line-height:2em;}
div > h1:first-child{
margin-top:-.25em;
}
div > h1:last-child{
margin-bottom:-.25em;
}