为什么将带有 overflow:hidden 的 `inline-block` 元素的基线设置为其底部边距?

Why baseline of `inline-block` element with `overflow:hidden` is set to its bottom margin?

在阅读了解释 inline-block 元素 (Why is this inline-block element pushed downward? and why the span's line-height is useless) 行为的两个很好的答案后,我还有两个无法解释的问题。

1.inline-block 元素的基线从其行框的基线更改为底部边距边缘的原因是什么?

http://www.w3.org/TR/CSS2/visudet.html#leading

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.

2.如何计算这个班次?

重要提示:我不会试图找到如何修复它的解决方案。我试图了解在应用 overflow: hidden 时更改 inline-block 元素定位行为的原因是什么。所以,请不要post回答傻瓜。

更新

不幸的是,虽然我接受了答案,但我没有得到我想要的。我认为问题本身就是问题。关于第一个问题:我想了解为什么inline-block即使有overflow:hidden也不能保留其线框的基线(当然,尽管有W3C规范).我想听听设计决定 - 不仅仅是它 必须 设置为某些东西,因为它要求 W3C。 第二个:我想得到一个公式,我们可以在其中粘贴元素的 font-sizeline-height 并获得正确的结果。

无论如何都要感谢大家:)

更新 2

幸运的是,主观上找到了答案!请参阅第一个重新接受的答案。谢谢@pallxk!)

这看起来不像答案,但我在 this 示例中发现了一个非常有趣的事情。

如果我们仔细观察 #firstDiv,我们可以看到底部有一些空白。但我认为这个边距取自水平滚动条的高度。

我拍了个高度,高度接近14px;

然后取inline-block的上边距高度,有overflow: hidden的是15px,没有overflow: hidden的接近30px。

是巧合吗?我不这样认为。同样的技巧将使用更大的 #container.

高度

P.S。此回复并非旨在回答,我只是无法将其全部放在评论中。我不知道这一切是如何联系起来的,我只是注意到了这一点。谢谢理解。

这可能不是答案。但它可能有助于通过删除 inline-block 元素之间的额外 space 来解决此问题。

<style>
.main_div {
    display:table;
    border-collapse:collapse;
    width:100%;
    border:1px solid red;
}
.main_div span {
    display:table-cell;
    border:1px solid black;
    height:20px;
    border:1px solid green;
}

</style>
<div class="main_div">
    <span class="one">one</span>
    <span class="two">two</span>
    <span class="three">three</span>
</div>

@timur:首先是个好问题。

我不知道它是否能回答你的问题,但我想谈谈 "inline-block" 元素的一些行为方面。

首先,"inline-block" 个元素根据其兄弟元素及其内容进行操作。

如果有两个div,一个挨着一个,都有display:inline块; property:value 然后它将取决于每个 div 中的内容,并将开始显示基线的内容,这是 "inline-block element".

的自然行为

现在,让我向您解释 "overflow" 属性 行为。

默认情况下,溢出 属性 是 "Visible" 并且其依赖的 属性 是 "overflow-wrap: normal;"。此外,它仅适用于 "block" 级别和 "inline-block" 元素,因为内联元素是那些包裹在文本中的元素,并且内容中没有白色 space 来阻止溢出。

因此您提供的示例中的跨度必须是 "block" 或 "inline-block" 才能应用溢出和垂直对齐。

如果你看这个 fiddle ---> http://jsfiddle.net/Lkyd1kr0/1/ 我在第二个跨度元素中使用了 "inline-block"。

HTML

<div class="one"><span>as</span></div><div class="two"><span>asd</span></div>

CSS

.one,.two { 
width: 200px;
display: inline-block ;

}

.one { border: 2px solid #f00; }
.two { border: 2px solid #000; }

.one span { display: block; }

.two span { 
    display: inline-block;
    overflow:hidden;
}

现在,只需使用 Web 开发人员工具并将鼠标悬停在 div.two 和 div.two > 跨度上并检查高度差异。

这是因为,span 是 div.two 的内容,inline-block 和其他div.two 高度上的 space 的其余部分是白色的 space。您通常会在 "block" 级和 "inline-block" 级元素上看到这种行为。

此外,请注意 "transform-origin" "span" 和 "div.two" 它在 y 轴上会有 4px 的差异。

1.将 inline-block 元素的基线从其行框的基线更改为底部边距边缘的原因是什么?

它是默认值 line-height 或其父元素继承到 inline-block 元素的正常行高或由用户代理定义的默认值,顺便说一下 W3C 推荐 line-height:normal .

参考这里

http://www.w3.org/TR/CSS2/visudet.html#propdef-line-height

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'.

所以我们知道默认值是line-height:normal并且它继承。 现在我们知道 inline-block 将元素添加到 line-height 并让我们看看设置 overflow:hidden 时会发生什么

W3C - Overflow

  • hidden

The content is clipped and no scrollbars are provided.

overflow:hidden 和 display:inline-block 为像 pgy 这样的悬挂字符创建 space。因为它是块和内联的,所以溢出保留了 space 可能出现的悬挂字符和行高。

2。如何计算这个班次?

其浏览器特定,因此我们需要参考浏览器规范

看这里知道'normal'

的价值

mozilla

Initial value normal
Inherited yes

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.

要理解图像,请参见下面的HTML CSS

第二个 div 和第二个 Div Span 具有 line-height:normal(通常为 1.2),因为 normal 被继承为未定义。

Third div and Third Div Span has line-height:40px which is defined, 第三个div line-height 的值默认继承到它的inline子元素也是。

CSS/Properties/display

  • inline-block 使元素生成内联级块容器。内联块的内部被格式化为块框,并且 元素本身被格式化为原子内联级框。

正如术语内联所说,它意味着元素是一个内联元素,而块意味着它的块。所以在一起意味着它是在同一行中定义的块元素 这是显示三种情况的示例证明 默认情况下 DIV 是块级元素,而 SPAN 是内联元素。此处有更多信息 HTML Block and Inline Elements

<style>
.first-div{
    border:#F00 1px solid;
}
.first-div span{
    /**by default span is an inline element.**/
    border:#093 1px solid;
}
.second-div{
    /** line-height not defined default line height will be used **/
    border:#F00 1px solid;
}
.second-div span{
    /** default line height inherited from the secod-div **/
    display:inline-block;
    border:#093 1px solid;
    overflow:hidden;
}
.third-div{
    border:#F00 1px solid;
    /**see line height. we change the default line height**/
    line-height:40px;
}
.third-div span{
    /**see line height. line height 40px set in the parent will be used**/
    display:inline-block;
    border:#093 1px solid;
    overflow:hidden;
}
</style>
<div class="first-div">
First Div
<span>First Span</span>
</div>
<br/>
<div class="second-div">
Second Div
<span>Second Span</span>
</div>
<br/>
<div class="third-div">
Third Div
<span>Third Span</span>
</div>

1.将 inline-block 元素的基线从其行框的基线更改为底部边距边缘的原因是什么?

overflow 属性 设置为 hidden 时,'inline-block' 的基线更改为其底部边距边缘(完整规范 here) .

至于这个决定的原因,我认为由于溢出的部分是隐藏的,用户代理(浏览器)可能会选择渲染那个溢出的部分而不显示它,或者选择根本不渲染它。并且当溢出的部分没有被渲染时,用户代理没有办法告诉它最后一行框的基线,因为它没有被渲染,它去哪里是未知的。

如果 overflow 设置为 hidden 的 'inline-block' 的基线仍然保留为其最后一行框的基线,则用户代理将被迫呈现隐藏的内容用户,可能会影响性能,或者至少,对用户代理施加额外限制。更重要的是,在这种情况下,同一行框中的其他内联文本与这样的基线对齐,其中溢出隐藏内联框周围的文本被隐藏,这是有点奇怪而不直观.

我做了一个简单的演示,模拟了隐藏溢出的内联块仍然将其基线设置为其最后一个行框的基线。

var isOverflowHidden = false;
document.querySelector('button').onclick = function() {
  document.getElementById('inline-box').style.overflow = isOverflowHidden ? '' : 'hidden';
  isOverflowHidden = !isOverflowHidden;
}
html { background: white; }
#inline-box { display: inline-block; height: 18px; }
.overflown { color: white; }
<p><button id="toggle">Toggle 'overflow: hidden;' on 'inline-block'</button></p>

<span>
  texts sit
  <span id="inline-box">
    texts in inline-block <br>
    <span class="overflown">
      line 2 <br>
      line 3
    </span>
  </span>
  on baseline
</span>

此外,您还可以将此行为与display: none进行比较。设置后,clientWidthclientHeight 都等于 0。

2。如何计算这个班次?

这部分要简单得多,因为它记录在您在问题中给出的 link 中。

我将从'line-height'的定义开始。

The height of the inline box encloses all glyphs and their half-leading on each side and is thus exactly 'line-height'.

line-height由上到下的上半行+高度(上升)+深度(下降)+下半行组成

可以针对给定大小的给定字体计算每个组件的高度。

基本上,每种字体都有字体规格,指定基线以上的特征高度和基线以下的深度。

以'Times New Roman'为例,使用FontForge,我们看到它有Em Size为2048,HHead Ascent为1825,以及HHead Descent 为 -443。也就是说,1825 / 2048 = 89.1% 的字体大小有助于上升,443 / 2048 = 21.6% 有助于下降。

也有以 'Typo' 开头的指标,如果选中 'Really use Typo metrics',将使用该类别,规范建议:

Note. It is recommended that implementations that use OpenType or TrueType fonts use the metrics "sTypoAscender" and "sTypoDescender" from the font's OS/2 table for A and D (after scaling to the current element's font size). In the absence of these metrics, the "Ascent" and "Descent" metrics from the HHEA table should be used.

line-height减去ascent和descent就是所谓的leading。

Half the leading is added above A(ascent) and the other half below D(descent).

假设 font-family: Times New Roman; font-size: 100px; line-height: 200px;,我们得到

ascent = 100px * (1825 / 2048) = 89px
descent = 100px * (443 / 2048) = 22px
top half-leading = bottom half-leading = (200px - 89px - 22px) / 2 = 44.5px

所以我们看到这是可以计算的。而且这个也可以在页面上衡量。

这是供您 fiddle 使用的另一个演示。

如果您要求移动下半行距,则在代码段中显示为绿线和蓝线之间的space。 如果您要求移动下降和底部半前导,则在代码段中显示为红线和蓝线之间的space。

var $ = document.querySelector.bind(document);

var fontFamily = window.getComputedStyle($('#examinee'))['font-family']
  , fontSize = +window.getComputedStyle($('#examinee'))['font-size'].replace('px', '')
  , containerLineHeight = +window.getComputedStyle($('#examinee'))['line-height'].replace('px', '')
  , textLineHeight = $('.target').offsetHeight
  , ascent = $('#examinee .baseline').offsetTop + $('#examinee .baseline').offsetHeight - $('#examinee .text-top').offsetTop
  , descent = $('#examinee .text-bottom').offsetTop - $('#examinee .baseline').offsetTop
  , topHalfLeading = $('#examinee .text-top').offsetTop
  , bottomHalfLeading = $('#examinee').offsetHeight - 2/* borders of the container */ - $('#examinee .text-bottom').offsetTop - $('#examinee .text-bottom').offsetHeight;

$('#font-family').innerText = fontFamily;
$('#font-size').innerText = fontSize + 'px';
$('#container-line-height').innerText = containerLineHeight + 'px';
$('#text-line-height').innerText = textLineHeight + 'px';
$('#ascent').innerText = ascent + 'px';
$('#descent').innerText = descent + 'px';
$('#top-half-leading').innerText = topHalfLeading + 'px';
$('#bottom-half-leading').innerText = bottomHalfLeading + 'px';
div {
  font-size: 20px;
  line-height: 2;
  width: 650px;
  
  border: 1px dashed gray;
  border-top: 1px solid blue;
  border-bottom: 1px solid blue;
  margin: 1rem 0;
  overflow: hidden;
  white-space: nowrap;
}

span:not([class]) {
  display: inline-block;
  border: 1px dashed gray;
}

.baseline,
.text-bottom,
.text-top {
  display: inline-block;
  width: 200%;
  margin: 0 -100%;
}

.baseline {
  border-bottom: 1px solid red;
  vertical-align: baseline;  /* the default */
}

.text-bottom {
  border-bottom: 1px solid green;
  vertical-align: text-bottom;
}

.text-top {
  border-bottom: 1px solid green;
  vertical-align: text-top;
}

#examinee {
  position: relative;
  font-size: 100px;
  line-height: 200px;
}
<p>
  Demonstrates that "overflow: hidden;" sets baseline of an inline-block element to its bottom margin.
</p>
<div>
  <span class="baseline"></span>
  <span class="text-top"></span>
  <span class="text-bottom"></span>
  &lt;div&gt;
  <span>
    &lt;span style=""&gt;&lt;/span&gt;
  </span>
  &lt;/div&gt;
</div>
<div>
  <span class="baseline"></span>
  <span class="text-top"></span>
  <span class="text-bottom"></span>
  &lt;div&gt;
  <span style="overflow: hidden;">
    &lt;span style="overflow: hidden;"&gt;&lt;/span&gt;
  </span>
  &lt;/div&gt;
</div>

<p>
  Demonstrates the position of baseline, text-top and text-bottom. <br>
  Demonstrates how "line-height" affects box sizing.
</p>

<ul>
  <li>Blue lines: top and bottom borders of line boxes
  <li>Red lines: baseline of texts
  <li>Green lines: text-top or text-bottom of texts
</ul>

<ul>
  <li>Between blue lines: the line-height
  <li>Between red line and green line: ascent or descent
</ul>

<div id="examinee">
  <span class="target">GgJjPpQqYy</span>
  <span class="baseline"></span>
  <span class="text-top"></span>
  <span class="text-bottom"></span>
</div>


Measured metrics:
<ul>
  <li>font-family: <span id="font-family"></span></li>
  <li>font-size: <span id="font-size"></span></li>
  <li>container line-height: <span id="container-line-height"></span></li>
  <li>text line-height: <span id="text-line-height"></span></li>
  <li>ascent: <span id="ascent"></span></li>
  <li>descent: <span id="descent"></span></li>
  <li>top half-leading: <span id="top-half-leading"></span></li>
  <li>bottom half-leading: <span id="bottom-half-leading"></span></li>
</ul>