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

时间:2015-08-18 17:29:51

标签: html css overflow w3c

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

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

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

  

'内联块的基线'是正常流程中其最后一个行框的基线,除非它没有流入的行框或者它的溢出' property具有除' visible'之外的计算值,在这种情况下,基线是底边距边缘。

2. 如何计算这种转变?

enter image description here

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

更新

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

无论如何,感谢任何人:)

更新2

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

5 个答案:

答案 0 :(得分:10)

<强> 1。将内联块元素的基线从其线框基线更改为下边距边缘的原因是什么?

&#39;内联块的基线&#39;当overflow属性设置为hidden(完整规范here)时,会更改为其下边距边缘。

至于做出这个决定的原因,我认为由于溢出的部分是隐藏的,用户代理(浏览器)可能会选择渲染溢出的部分而不显示它,或选择不渲染它。并且当没有呈现溢出部分时,用户代理无法告知其最后一个行框的基线,因为它没有呈现,它的去向不明。

如果&#39; inline-block&#39;的基线其overflow设置为hidden仍然作为其最后一个行框的基线,用户代理被迫呈现隐藏给用户的内容,可能会阻碍性能,或至少,对用户代理施加额外限制。更重要的是,在这种情况下,同一行框中的其他内联文本与这样的基线对齐,其中隐藏溢出隐藏内联框周围的文本,这是类型的stange而不是直观< /强>

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

emultaing_imaginary_baseline_of_overflow_hidden_inline_block

&#13;
&#13;
var isOverflowHidden = false;
document.querySelector('button').onclick = function() {
  document.getElementById('inline-box').style.overflow = isOverflowHidden ? '' : 'hidden';
  isOverflowHidden = !isOverflowHidden;
}
&#13;
html { background: white; }
#inline-box { display: inline-block; height: 18px; }
.overflown { color: white; }
&#13;
<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>
&#13;
&#13;
&#13;

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

<强> 2。如何计算这种转变?

这部分要容易得多,因为它在问题中提供的link中有记录。

我将从&#39; line-height&#39;的定义开始。

  

内联框的高度将所有字形包围在每一侧的半个前导,因此恰好是&#39; line-height&#39;。

也就是说,行高由上到下,上半部分+高度(上升)+深度(下降)+下半部分组成。

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

基本上,每种字体都有字体指标,指定高于基线的特征高度和低于它的深度。

采取新时代的罗马&#39;例如,使用 FontForge ,我们看到它的Em Size为2048,HHead Ascent为1825,HHead Descent为-443。也就是说,1825 / 2048 = 89.1%的font-size有助于上升,443 / 2048 = 21.6%有助于下降。

FontForge

还有以&#39; Typo&#39;开头的指标,如果&#39;真正使用错字指标&#39;将使用该类别。检查,规范建议:

  

请注意。建议使用OpenType或TrueType字体的实现使用指标&#34; sTypoAscender&#34;和&#34; sTypoDescender&#34;来自字体的A和D的OS / 2表(在缩放到当前元素的字体大小之后)。如果没有这些指标,那么&#34; Ascent&#34;和&#34;下降&#34;应使用HHEA表中的指标。

线高减去上升和下降是所谓的领先。

  

领先的一半加在A(上升)之上,另一半加在D之下(下降)。

假设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

所以我们看到这可以计算出来。这也可以在页面上测量。

这是另一个让你摆弄的演示。

如果您要求下半场前移,它会在代码段中显示为绿线和蓝线之间的空格。 如果您要求下降和下半场前移,它会在代码段中显示为红线和蓝线之间的空格。

&#13;
&#13;
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';
&#13;
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;
}
&#13;
<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>
&#13;
&#13;
&#13; line-height measuring

答案 1 :(得分:2)

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

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

答案 2 :(得分:2)

@timur:首先是个好问题。

我不知道它是否会回答你的问题,但我想谈谈&#34; inline-block&#34;的一些行为方面。元件。

首先,&#34;内联块&#34;元素根据其兄弟元素及其内容行事。

如果有两个div,一个在另一个旁边,两个都有显示:inline-block; property:value然后它将取决于每个div内的内容,并将开始显示基线中的内容,这是&#34; inline-block元素&#34;的自然行为。

现在,让我来解释一下&#34;溢出&#34;财产行为。

默认情况下,溢出属性为&#34;可见&#34;它的依赖属性是&#34; overflow-wrap:normal;&#34;。它也仅适用于&#34; block&#34;级别和&#34;内联块&#34;元素因为内联元素是包含在文本中的元素,并且内容中没有空格可以停止溢出。

因此,您提供的示例中的范围必须是&#34;阻止&#34; OR&#34;内联块&#34;应用溢出和垂直对齐。

如果你看这个小提琴---&gt; http://jsfiddle.net/Lkyd1kr0/1/我使用了&#34; inline-block&#34;对于第二个span元素。

<强> 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&gt;之上。跨度并检查高度差异。

这是因为span是 div.two 的内容,内联块,其余部分位于div的高度。对于剩余的内容,即白色空间,保护了两个。这种行为通常会在&#34; block&#34;级别和&#34;内联块&#34;等级元素。

另外,请注意&#34; transform-origin&#34;两个&#34; span&#34;和&#34; div.two&#34;它在y轴上会有4px的差异。

答案 3 :(得分:1)

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

如果我们把一个lool带到#firstDiv,我们可以看到底部有一些边缘。但我认为这个边距取自水平滚动条的高度。

Scrollbar

我采取高度,高度接近14px;

然后选择inline-block的{​​{1}}的上边距高度为{1},它是15px,没有overflow: hidden它接近30px。

15px margin 30px margin

这是巧合吗?我不这样认为。相同的技巧将是overflow: hidden的高度更高。

P.S。这个回复并不意味着回答,我只是不能把它全部放在评论中。我不知道它是如何连接起来的,我只是注意到了这一点。谢谢你的理解。

答案 4 :(得分:1)

<强> 1。将内联块元素的基线从其线框基线更改为下边距边缘的原因是什么?

默认line-height或其父级的正常行高 - 是继承到内联块元素还是由用户代理定义的默认值,这是W3C推荐的line-height:normal

此处参考

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

  

<强>正常

     

告诉用户代理将使用的值设置为“合理”值   在元素的字体上。该值具有相同的含义   

     
    

我们建议将“正常”的使用值介于1.0到1.2之间。该     计算值为“正常”。

  

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

W3C - Overflow

  
      
  • 隐藏
  •   
     

内容被剪裁,没有提供滚动条。

溢出:隐藏和显示:内联块为挂起的字符创建空间,如pgy。因为它是块和内联,溢出会为可能出现的悬挂字符和行高保留两个空间。

enter image description here

<强> 2。如何计算这种转变?

它的浏览器具体,因此我们需要参考浏览器规范

请点击此处了解“正常”的价值

mozilla

Initial value normal
Inherited yes
  

<强>正常       取决于用户代理。桌面浏览器(包括Firefox)使用大约1.2的默认值,具体取决于元素   字体家庭。

要了解图像,请参阅下面的HTML CSS

enter image description here

第二个div和Second Div Span有行高:正常(通常为1.2),因为normal是未定义的继承。

第三个div和第三个Div Div具有行高:40px被定义,第三个div行高的值默认继承到它的内联子元素。

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>