How to determine height of content-box of a block and inline element
For block elements its quite easy but you need to distinguish between two different cases. When we have an IFC (inline formatting context) or BFC (block formatting context). From the specification you can read
If 'height' is 'auto', the height depends on whether the element has any block-level children and whether it has padding or borders:
The element's height is the distance from its top content edge to the first applicable of the following:
- the bottom edge of the last line box, if the box establishes a inline formatting context with one or more lines
- the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin does not collapse with the element's bottom margin
- the bottom border edge of the last in-flow child whose top margin doesn't collapse with the element's bottom margin
- zero, otherwise
Only children in the normal flow are taken into account (i.e., floating boxes and absolutely positioned boxes are ignored, and relatively positioned boxes are considered without their offset)
If we consider an IFC then the line boxes will define our height exactly like your examples where in the div
and p
you have one line box defined by the line-height.
If we consider a BFC then the (2) and (3) apply. Here, you can see it as a recursive definition because having a BFC means we have other blocks inside and those blocks will follow the same rules (either BFC or IFC and so on). In addition, we consider the margin collapsing rules to get the final height.
If the block is empty then it's zero.
Of course, this consider the case of height:auto
. If you explicitely set a height then it's trivial.
For inline elements you can 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.)
Here is a bit tricky but the rule is simple: you cannot control or set the height of the content area. Only the font properties you will be using will define the final height.
You should also note that the content area is different from the line box.
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.
<span style="background-color: aquamarine; font-size: 16px; line-height: 2em;">Is line-height same as height of span tag?</span>
<br>
<span style="background-color: aquamarine; font-size: 16px; line-height: 4em;">Is line-height same as height of span tag?</span>
<br>
<span style="background-color: aquamarine; font-size: 16px; line-height: 8em;">Is line-height same as height of span tag?</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>
How to calculate the height of an inline element
The CSS 2.1 spec says:
10.6.1 Inline, non-replaced elements
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.
As it happens the height, as opposed to the line-height, of a non-replaced inline element has very little effect on anything else so browsers are pretty free to report whatever number they like here.
However, a little reverse engineering can be instructive.
If we look at the font metrics for Times New Roman, we see EM size of 2048, WinAscent of 1825, and WinDescent of 443. Sum the ascent and descent, divide by the EM size, multiply by the font size (20px) and round to the integer and we get 22px.
Taking Arial as another font, we have EM size of 2048, WinAscent of 1854, and WinDescent of 434. Do the calculation again and we again get 22px.
What about a different font? Tahoma has EM size of 2048, WinAscent of 2049, and WinDescent of 423. Do the calculation again and this time we get 24px. And hey presto, if you try your JsBin with the Tahoma font, Firefox does indeed show a height of 24px.
The font metrics above were obtained from loading the fonts into Type Light 3.2.
Not conclusive, but a reasonable suggestion of how it all works.
Is it possible to make it tall 20px without using inline-block ?
Assuming the above is correct, you should be able to achieve it by using a custom font and modifying the font metrics of that font to suit. I wouldn't like to predict the knock-on effects of doing that though.
Why Empty Display Inline Block Element Create Height But Display Inline and Display Block not?
To understand this you need to know the difference between a BFC (block formatting context) and IFC (inline formating context.
When having only block elements inside your container this one will create a BFC:
In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block. The vertical distance between two sibling boxes is determined by the 'margin' properties. Vertical margins between adjacent block-level boxes in a block formatting context collapse.
In this case, only the height and margin of the block element inside are considered to calculate the height of your container and you only have one empty element so the height is 0.
When having an inline-block
/inline
elements you will trigger the creation of an IFC and the story is different:
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.
As you discovered, we will be dealing with line boxes and line-height
will be considered here to define the height of each line box (in your case you have only one)
Now, the difference between the inline
and inline-block
is about white space. In the case of inline
element you will end having an empty container because all the white space will collapse. More details here: https://www.w3.org/TR/2011/REC-CSS2-20110607/text.html#white-space-prop.
If you change the white space algorithm (and you add a space) you will get the same height as with the inline-block
element.
.container {
background-color: red;
margin:5px;
white-space:pre;
}
<div class="container"><div style="display: inline-block;"></div></div>
<div class="container"><div style="display: inline;"> </div></div>
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
.
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>
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
Text overflow - why is block element smaller than inline element
overflow
apply to only block level element ref and the content of inline element cannot overflow since you cannot have it's height smaller than its content due to the fact that you cannot define height on inline element and the height is automatically defined by the content ref
Adding border will clearly show this:
.large { font-size: 50px; line-height: 1;}
.overflow { overflow: hidden; border:1px solid green;}
body > div { margin:20px; outline:2px solid red;}
<body> <div class="overflow large"> Testing: pPgG </div> <div> <span class="overflow large"> Testing: pPgG </span> </div></body>
Related Topics
How to Make Scrollable Table with Fixed Headers Using CSS
Required Attribute Not Work in Safari Browser
How to Print Background Images in Ff or Ie
How to Set the Max-Width of a Table Cell Using Percentages
Localization of Input Type Number
Html5 New Elements (Header, Nav, Footer, ..) Not Working in Ie
How to Create a Curve Between Two Gradient Using CSS
Empty Vertical Space Between Columns in Bootstrap 4
How to Determine Height of Content-Box of a Block and Inline Element
Bootstrap 3 to Bootstrap 4 Cols No Longer Horizontally Aligned
<Fieldset> Resizes Wrong; Appears to Have Unremovable 'Min-Width: Min-Content'
Center Aligning a Fixed Position Div
HTML Button Calling an MVC Controller and Action Method
How to Make a Whole 'Div' Clickable in HTML and CSS Without JavaScript
What's the Difference Between HTML 'Hidden' and 'Aria-Hidden' Attributes