The trick is within the display and you won't find any logical relation between the height you are getting because in both cases the calculation is different.
In the first case, you have inline element and this rule apply:
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.ref
So the height of your span depends only on the font properties (font-family, font-size, etc) + the border top/bottom. You cannot find how the height is calculated exactly unless you dig into the font properties which is a difficult exercise especially if we deal with the default font that differ a from browser to another (and from OS to another).
Related:
Can specific text character change the line height?
What determines the space between the highest and lowest letter and the top and bottom border of the element the letter's in?
In the second case, you span is now a block element because you made it position:absolute
so you need to follow the rule detailed here: https://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-height that will lead us to use the following rule: https://www.w3.org/TR/CSS21/visudet.html#root-height
If it only has inline-level children, the height is the distance between the top of the topmost line box and the bottom of the bottommost line box
So the height of our element is now the height of the line box which is defined by line-height
(like detailed here: https://www.w3.org/TR/CSS21/visudet.html#line-height). Not only line-height but also vertical alignment of the elements inside but in your case you don't have this complexity since you have only one character
The default line-height
is defined by the browser but if you fix it you will get the height you want:
const
small = document.querySelector('#small'),
large = document.querySelector('#large')
window.onclick = () => {
console.log(small.getBoundingClientRect().height,
large.getBoundingClientRect().height)
}
div {
border: solid purple 2px;
}
#small {
border: solid red 2px;
line-height:1; /* will give a height = 1*16 + 4 */
}
#large {
border: solid black 2px;
font-size: 10rem;
line-height:1; /* will give a height = 1*10*16 + 4 */
}
span {
position: absolute;
}
<div>
<span id='small'>.</span>
<span id='large'>.</span>
</div>
Related: How does height will be calculated, based on font-size?
If you make the span
element inline-block
you will get the same behavior as in the second case because you follow the rules here: https://www.w3.org/TR/CSS21/visudet.html#block-root-margin that will get us to the same rule for absolute element (https://www.w3.org/TR/CSS21/visudet.html#root-height) which means the line-height
will control your height:
const
small = document.querySelector('#small'),
large = document.querySelector('#large')
window.onclick = () => {
console.log(small.getBoundingClientRect().height,
large.getBoundingClientRect().height)
}
div {
border: solid purple 2px;
}
#small {
border: solid red 2px;
display:inline-block;
line-height:1;
}
#large {
border: solid black 2px;
font-size: 10rem;
display:inline-block;
line-height:1;
}
<div>
<span id='small'>.</span>
<span id='large'>.</span>
</div>