Bug 157293 - Element with "font-size: 0; overflow: hidden;" is not fitted to the parent.
Summary: Element with "font-size: 0; overflow: hidden;" is not fitted to the parent.
Alias: None
Product: WebKit
Classification: Unclassified
Component: Layout and Rendering (show other bugs)
Version: Safari 9
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
: 36084 (view as bug list)
Depends on:
Reported: 2016-05-02 19:10 PDT by Eunmi Lee
Modified: 2016-06-08 11:44 PDT (History)
3 users (show)

See Also:

simple test page (498 bytes, text/html)
2016-05-02 19:10 PDT, Eunmi Lee
no flags Details
result image (2.01 KB, image/png)
2016-05-02 19:11 PDT, Eunmi Lee
no flags Details
Slightly more reduced test case (337 bytes, text/html)
2016-05-03 10:07 PDT, Myles C. Maxfield
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Eunmi Lee 2016-05-02 19:10:40 PDT
Created attachment 277960 [details]
simple test page

Element with "font-size: 0" is layout with top margin in the many browsers (ie, chrome, safari, firefox..),
and front-end developer can remove top margin by adding that element to the "overflow: hidden" element,
but it is not efficacious only in the safari browser.

chrome and safari results and test html are attached.
Comment 1 Eunmi Lee 2016-05-02 19:11:21 PDT
Created attachment 277961 [details]
result image
Comment 2 Myles C. Maxfield 2016-05-03 10:07:51 PDT
Created attachment 278007 [details]
Slightly more reduced test case
Comment 3 Myles C. Maxfield 2016-05-03 10:36:11 PDT
The slightly more reduced test case is invalid - it renders the same in other browsers as in Safari.
Comment 4 Myles C. Maxfield 2016-05-03 11:31:17 PDT
Let me explain what is going on here.

There are two pieces of information which are important here:

1. The CSS 2.1 spec [1] says: "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.”

Other browsers implement this behavior described above.

2. When placing inline elements inside a block element, we first calculate where the baseline of the entire line of inline elements should be (which is equal to the maximum ascent of all the elements in the line). Then, we calculate where the baseline of each inline element is, and we place all the baselines vertically on top of each other.


So, let's break it down: we have three divs. The outer one (#header) has a height of 45px, and a width of 100%. It doesn't have a font-family or font-size specified, so it defaults to 16px Times. This font (16px Times) has an ascent of 14px and a descent of 4px.

Inside, we have #wrapper, which is display: inline-block, and has overflow: hidden. Therefore, according to the spec, and because #wrapper has overflow: hidden, the baseline of #wrapper is its bottom margin edge. Because #wrapper is the only thing inside #header, the baseline for the first line of #header is therefore calculated to be at the bottom margin edge of #wrapper (which is 45px downward from the top). Therefore, when we align the baselines, the entire #wrapper is sitting on top of the baseline.

(An interesting side effect of this is that the first line of #header still has a 4px descent (below the baseline) because of that 16px Times font used. However, you don't see it in the example because the height of #header is explicitly set to 45px. Therefore, if there were any text inside #header, you would see the bottoms of the letters drop down below #wrapper)

Okay, so now let's consider #icon. This is an inline-block element without overflow: hidden, which means, according to the spec, its baseline is the baseline of its last line box. Its last line box comes from that "A" character inside it. That "A" character, however, has a font-size of 0px, which means that it lies all the way in the top left corner of #icon (but it's so small you don't see it). Therefore, the baseline of #icon lies at its very top.

The last piece remaining is how #icon gets placed within #wrapper. This placement follows the same logic as before - we line up the baseline of the first line of #wrapper with the baseline of #icon. We know that the baseline of #icon is at its very top. Because the font-size of #wrapper is 0px, and its only content is #icon, so the first line of #wrapper has a baseline at its very top. Placing these two baselines on top of each other makes #icon appear at the very top of #wrapper.

So, when all of this is done, the baseline of the first line of #header is at 45px (downward from the top); the baseline of the first line of #wrapper is at 0px from the top, and the baseline of the first line of #icon is at 0px from the top.

That is how the spec describes this, and that is what the other browsers do.


WebKit purposely does not implement the spec (as it appears above). We believe that putting overflow: hidden on #wrapper should not put its baseline at its bottom edge. Instead, we believe that a better behavior is to put #wrapper's baseline at the baseline of its last line box (which would come from the baseline of #icon, which is at 0px from its top).

In this situation, almost all of the above discussion is still valid. However, because we place #wrapper's baseline 0px from its top, this means that the baseline of the first line of #header is now at 14px (which is the ascent of the 16px Times font used inside it). Then, we align this baseline with the baseline of #wrapper (which is at its top edge), which leads to the 14px gap you saw in your screenshot.

This is rendering as we expect.


You are right, however, that there is a difference in rendering between other browsers and WebKit. Interoperability is definitely one of WebKit's goals. However, we feel strongly enough about this new baseline placement behavior that we (I) have petitioned successfully to have the spec changed. You can read more about it at [2], and you can see that the proposal was accepted at [3]. Therefore, other browsers will adopt this behavior in the future (hopefully soon!).


There are a few ways to adapt to this content to the new inline-block placement scheme. The most straightforward one is to style #header with font-size: 0px. Another one is to style #header with position: relative and style #wrapper with position: absolute. Another one is to use flexbox. Another one is to remove the font-size: 0px from all the divs, and wrap the "A" in a span and style the span with font-size: 0px. Or, you could use the same approach and style the span with display: none.

[1] http://www.w3.org/TR/CSS21/visudet.html#leading
[2] https://lists.w3.org/Archives/Public/www-style/2015Mar/0342.html
[3] https://lists.w3.org/Archives/Public/www-style/2015Apr/0144.html
Comment 5 Myles C. Maxfield 2016-06-08 11:44:12 PDT
*** Bug 36084 has been marked as a duplicate of this bug. ***