Understanding CSS2.1 specification regarding height on inline-level boxes
Is the height of inline-level boxes equal to the line-height property set on them (with the minimum being the line-height set on the parent block container element),
Yes it is.
OR is it just determined by the font height (and UA implementation)?
No it isn't
CSS is really about boxes, not elements, and you should try not to confuse the two.
So an inline element has associated with it a number of boxes. A content box, padding box, border box and margin box. It also has zero (if display:none
), one, or multiple inline boxes. The content box, paddings, borders and margins may be divided among the inline boxes so that the inline content can be spread over more than one line.
The inline box's height is the content height adjusted by the leading. It's the leading that does the magic here. The leading is defined as the line-height of the element minus the content height of that inline box.
Simply rearranging that equation tells us that the height of the inline box depends only on the line-height and not on the content box (or padding, border, margin boxes).
Note that none of the above discusses the line box, which is a different thing again and not a direct property of inline elements or their boxes. The line box is constructed by arranging the inline boxes that occur on the same line such that their vertical alignments fit the rules computed for the elements, including the zero width inline box formed by the strut.
Each line box is bounded by the top of uppermost inline box and the bottom of the lowestmost inline box that that line box contains.
Digression: On why the height of the line box can surprise.
Suppose we have a simple case of a containing block which just contains one short inline element (i.e. short enough that it fits in a single line box). Also suppose that everything is aligned on the baseline. Let's say that the line-height is set on the containing box to 20px, and the inline element inherits that. Also suppose that the font-size (em-square) of the containing block is 16px, and that means that the font metrics compute to an ascent (above the baseline) of 14px and a descent (below the baseline) of 4px.
So the content area for the strut is (14px + 4px =) 18px high. The line-height is 20px, so there is 2px leading, 1px goes above the ascent, and 1px below the descent. So the line-height of the strut is made of 15px above the baseline and 5px below the baseline.
Now, suppose that the font-size of the inline element is set to 0.5em (i.e. half that of the containing block). The content area for the inline element will be an ascent of 7px and a descent of 2px. The line-height is still 20px, so the leading is 20px - (7px + 2px) = 11px, meaning that 5.5px goes above the ascent and 5.5px goes below the descent. This results in the line-height for the inline element is made of 12.5px above the baseline and 7.5px below the baseline.
Since the strut and the inline element are aligned vertically to their baselines, the top of the uppermost inline box (the strut) is 15px above the baseline and the bottom of the the lowermost inline box (the inline element) is 7.5px below the baseline, the actual height of the line box is not 20px but (15px + 7.5px =) 22.5px.
Auto' heights for block formatting context roots (inline-block)
Thanks @TemaniAfif
He was right the reason of 18px
for height was in line-height
of div
element. div
's line-height
specify minimal height of line boxes
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.
In my case div
doesn't specify line-height
property so it has default value equals normal
.
Name:
line-height
Value:
normal
|<number>
|<length>
|<percentage>
|inherit Initial:
normal
https://www.w3.org/TR/CSS22/visudet.html#leading
If line-height
value is normal
then computed value depends from user agent.
But spec recommends to use value 1.0 to 1.2 of element's font-size. Looks like usually this value are equals to font-size * 1.2
but it's also depends from font's metrics like ascent
, descent
and em-box
(so result would depends from font-family).
normal
Tells user agents to set the used value to a "reasonable" value
based on the font of the element. The value has the same meaning as
. We recommend a used value for 'normal' between 1.0 to 1.2.
The computed value is 'normal'.
If you know font's metrics like ascender
and descender
and font-size which you would use on the web you can calculate line-heigh
by (ascender + Math.abs(descender)) * font-size / (units_per_em)
function lh(ascender, descender, unitsPerEm, fontSize) {
return (ascender + Math.abs(descender)) * fontSize / unitsPerEm;
}
In the pictures above ascender=5000
, descender=-200
, units_per_em=1000
and font-size=48px
so line-height=(5000 + 200) * 48 / 1000 = 249.6
(lh(5000, 200, 1000, 48)
)
ascent
, descent
font's properties are shipped with font and defined by font's creator.
You can use FontDrop! service to get information about font
Some implementations details from Chromium(Webkit) relates to line-height
LayoutUnit ComputedStyle::ComputedLineHeightAsFixed() const {
const Length& lh = LineHeight();
// Negative value means the line height is not set. Use the font's built-in
// spacing, if avalible.
if (lh.IsNegative() && GetFont().PrimaryFont())
return GetFont().PrimaryFont()->GetFontMetrics().FixedLineSpacing();
https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/renderer/core/style/computed_style.cc#1835
FixedLineSpacing
float line_gap = SkScalarToFloat(metrics.fLeading);
font_metrics_.SetLineGap(line_gap);
font_metrics_.SetLineSpacing(lroundf(ascent) + lroundf(descent) +
lroundf(line_gap));
https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/renderer/platform/fonts/simple_font_data.cc#123
Why is there space between line boxes, not due to half leading?
The background properties applies only to the content area and not the line box. In most of the cases the content area is defined by the height
. As we can read in the specification:
The dimensions of the content area of a box — the content width and
content height — depend on several factors: whether the element
generating the box has the 'width' or 'height' property set, whether
the box contains text or other boxes, whether the box is a table, etc.
And here:
This property specifies the content height of boxes.
This property does not apply to non-replaced inline elements. See the
section on computing heights and margins for non-replaced inline
elements for the rules used instead.
And if check the above link we can read:
The 'height' property does not apply. The height of the content area
should be based on the font, but this specification does not specify
how. A UA may, e.g., use the em-box or the maximum ascender and descender of the font.
Here is an illustration to better show youref:
The content area is defined by the browser and in some case it can be the em
1 that you see in above figure but not necessarely.
In all the cases and whataver the line-height
will be, the content area will only depend on the font properties. So the line-height
define the height of the line box AND the content area height is defined by the font properties.
So the real question is: Why by default the line-height
doesn't make the line box equal to the content-area?
If check we check the documentation we can see that the default value is set to normal
and:
normal
Depends on the user agent. Desktop browsers (including Firefox)
use a default value of roughly 1.2, depending on the element's
font-family.
Then
<number>
(unitless)The used value is this unitless
<number>
multiplied by the element's own font size.
In some cases, we will have the line box a bit bigger than the content area which explain the gap.1
Now why setting the line-height
to 1
doesn't fix the issue?
Simply because you set the line-height
of the spans and not the line-height
of their container which is not enough. The line-height
of the container is still the default one 1.2
which will be considered since it's bigger than 1
. In other words, the biggest line-height
will win.
Here is some illustration to better understand:
line-height of the body is 2
and only a bigger line-height for span will have an effect:
body { line-height:2}
span { background-color: red; line-height: 1; animation:change linear infinite 2s alternate;}
@keyframes change { to {line-height:3}}
<span>Some span. As seen, background covers font plus half leading on top/bottom. There is still a gap, which is due to something else.</span><br/><span>Some span. As seen, background covers font plus half leading on top/bottom. There is still a gap, which is due to something else.</span>
Why inline and inline-block have different height with the same text content
This is related to how line-height
works and how the height of each element is calculated.
Let's start with a trivial example to highlight the effect of line-height
span {
border:1px solid red;
padding:5px;
line-height:50px;
}
<span>some text</span> <span style="display:inline-block">some text</span>
Inline elements and line-height
This might be confusing because in the inline formatting model there are different heights.
Height of an inline box
An element with display: inline
generates an inline box:
An inline box is one that is both inline-level and whose contents
participate in its containing inline formatting context. A
non-replaced element with adisplay
value ofinline
generates an
inline box.
And line-height
determines the height of that box:
The height of the inline box encloses all glyphs and their
half-leading on each side and is thus exactly 'line-height'
Therefore, your box is, in fact, 15px
tall.
Height of a line box
There are also line boxes:
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.The height of a line box is determined by the rules given in the
section on line height calculations.
In case a line box only contains non-replaced inline boxes with the same line-height
and vertical-align
, those rules say that the height of the line box will be given by line-height
.
So in your case, this is also 15px
.
Height of the content area of an inline box
However, the developer tools of your browser said 18px
. That's because those 18px
are the height of the content area. It's also this content area (together with paddings) which is painted by the green background.
Note those 18px
might vary because CSS 2.1 doesn't specify an algorithm:
The height of the content area should be based on the font, but this
specification does not specify how. A UA may, e.g., use the em-box or
the maximum ascender and descender of the font. (The latter would
ensure that glyphs with parts above or below the em-box still fall
within the content area, but leads to differently sized boxes for
different fonts; the former would ensure authors can control
background styling relative to the 'line-height', but leads to glyphs
painting outside their content area.)
If an UA implements the first suggestion, the content height will be given by font-size
, which determines the em-box. This would what you expected, with the green box being 15px
tall.
However, most UAs don't seem to do that. That means that, probably, the height will be the height of the tallest glyph in the font-family
and font-size
used.
But using a font-size
value of 15px
doesn't mean that the tallest glyph will be 15px
tall too. That depends on the font. This is somewhat analogous to normal
, the initial value of line-height
, which is defined as
Tells user agents to set the used value to a "reasonable" value based
on the font of the element[...]. We recommend a used value for
'normal' between1.0
to1.2
.
That means that, if you use font-size: 15px
, a "reasonable" line-height
would be between 15px
and 18px
. In the "Verdana" font, Firefox thinks the best is 18px
; in the "sans-serif", it uses 17px
.
Line height issue with inline-block elements
The line-height
is applying but you need to understand how it's applying. If we refer to the specification:
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
By setting line-height:5
on the parent element you set a minimum height for the linebox.
On a non-replaced inline element, 'line-height' specifies the height that is used in the calculation of the line box height.
By setting line-height:1.5
you defined the height of your element inside the linebox.
To make it easier, you have an element with a height equal to 1.5
inside a linebox with a height equal to 5
1 but you cannot visually see this. If you inscrease the line-height of child and you reach 5
you will then reach the minimum height and you will start increasing the linebox previously defined by the parent element.
To see this you need to apply vertical-align
. If the line height of child element is smaller than the line height of the parent (the height of the child smaller than the height of the linebox) you can align:
.container {
max-width: 200px;
border: 2px black solid;
line-height: 5;
}
.container>a {
line-height: 1.5;
}
<div class="container">
<a>First</a>
<a style="vertical-align:top;">Second</a>
<a>Third</a>
<a style="vertical-align:bottom;">Fourth</a>
</div>
Box Model for Inline Elements
For the second question you may refer to this part of the specification:
The 'height' property does not apply. The height of the content area
should be based on the font, but this specification does not specify
how. A UA may, e.g., use the em-box or the maximum ascender and
descender of the font. (The latter would ensure that glyphs with parts
above or below the em-box still fall within the content area, but
leads to differently sized boxes for different fonts; the former would
ensure authors can control background styling relative to the
'line-height', but leads to glyphs painting outside their content
area.)The vertical padding, border and margin of an inline, non-replaced box
start at the top and bottom of the content area, and has nothing to do
with the 'line-height'. But only the 'line-height' is used when
calculating the height of the line box.
.test { margin: 0 10px; padding: 20px; border: 5px solid blue;}
div { border:1px solid red; margin:50px 0;}
<div><span class="test">test2test2test2test2test2test2test2 test</span></div>
<div><span class="test">test2test2test2test2test2test2test2 test st2test2test2test2 test st2test2test2test2 test st2test2test2test2 test</span></div>
<div><span class="test" style="line-height:50px;">test2test2test2test2test2test2test2 test2test2</span></div>
<div><span class="test" style="line-height:50px;">test2test2test2test2test2test2test2 test2test2 test2test2test2test2test2test2test2 test2test2</span></div>
Related Topics
Stop Google Chrome Auto Fill The Input
PHP Mail() - How to Put an HTML Link in an Email
Github Pages and Relative Paths
How Does Stackoverflow Make Its Tag Input Field
What Is The Browser-Default Background Color When Selecting Text
Conditional Rendering of Non-Jsf Components (Plain Vanilla HTML and Template Text)
Draw Double Curved Item with Beveled Edges
Change Color of One Character in a Text Box HTML/CSS
Get Parameters in The Url with Codeigniter
How to Remove The Horizontal Scrollbar in a Div
How to Make a Div Tag into a Link
HTML5 Input Box with Type="Number" Does Not Accept Comma in Chrome Browser