沐光

记录在前端之路的点点滴滴

浅谈行内元素

前言

最近在工作中遇到很多奇怪的样式错位问题,解决问题之余,有重新温习了一下样式方面的知识。一般块级元素的问题都比较好解决,而行内元素的问题还总是得试试,可能是理解的不够透彻,因此此篇算是我对行内元素做的一个简短的笔记吧。

基础知识

什么是行内元素

行内元素,顾名思义,就是指在在一行内不换行的元素。通俗来讲,行内元素相当于“句子”,其内可以包含数据与其它行内元素。

一个行内元素只占据它对应标签的边框所包含的空间。
MDN —— 行内元素

常见的行内元素

  • b, big, i, small, tt
  • abbr, acronym, cite, code, dfn, em, kbd, strong, samp, var
  • a, bdo, br, img, map, object, q, script, span, sub, sup
  • button, input, label, select, textarea

行盒子与浮动

文字环绕特效

word 文档内有“文字环绕”一表格属性,能够实现图片周围环绕文字,例如:

文字环绕效果

当然,上图是 html 实现的,实现方法也很简单,代码如下(例 1-1):

1
2
3
4
5
6
7
8
<figure class="test-figure">
<img class="test-img" src="./cat.jpg" alt="" />
<span
>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Alias, dolore qui
obcaecati fuga ratione nobis dolor veniam soluta sequi rem voluptatem quo
similique quis doloribus fugit autem! Quas, ipsum reiciendis?</span
>
</figure>
1
2
3
4
5
6
7
.test-figure {
width: 300px;
}
.test-img {
width: 100px;
float: left;
}

文字环绕原理

代码很简单,实现难度也不大,但是为什么这么写能够实现呢?它实现的原理又是什么呢?

其实,在我们所知的盒子模型中,除了基础的块级盒子和行内盒子,我们还有一个比较隐秘的匿名盒子。参考一个例子(例 1-2):

1
2
3
4
<p>
我在块级盒子的匿名行内盒中
<span>我在行内盒子的匿名行内盒中</span>
</p>

回忆一下 CSS 选择器,其中有两个用的不是很多的伪元素选择器::first-letter::first-line,在此例中,它们选中的其实就是盒子模型中的匿名盒子的内容。那这个和我们所说的“文字环绕”又有什么关系呢?

我们知道,浮动会让元素脱离文档流,因此它不会再向非浮动元素影响其它元素的布局,因此在例 1-1 中,我们的 img 标签已经脱离了文档流,span 标签 此时在层级上会置于其下,如图:

匿名行内盒

但是!float 元素内的内容,也就是 img 的内容,它并不会跟随 img 标签一起浮动,而是仍然会存在于正常的文档流中,同时也会记住 img 标签的大小,因此在后面的匿名行盒子(span 中的)在计算其应该所在的位置时,会给 float 元素留出它所需要的空间,也就出现了“文字环绕”的样式。

常用伪元素: ::before、::after

知识拓展

因为浮动并不算是完全脱离文档流,因此在开发中还会出现不少 bug,比如:“高度塌陷”,在处理这类问题时,我们经常用到的方法是 clear: both; ,例如(例 1-3):

1
2
3
4
5
<!-- 这里就用类名表示相应效果 -->
<div>
<p class="float"></p>
<div class="clear-both"></div>
</div>

但是浏览器在对这做处理时,会为浮动元素留下足够大的空间,也就是给我们的元素加隐性的 padding,从而实现换行的效果(注意: span 标签不生效,display: block 才生效)。

行内元素的排版

行盒子的构造

处理行内元素时,比较令人头疼的就是它们的对齐方式了。虽然对应的知识都比较了解,在项目中遇到多个行内元素没有对齐时,稍微多几次尝试基本上也能够搞定对齐,万一实在弄不定,一个 flex 布局基本能解决所有的痛苦。但是,仅仅这样也就止步于此了,不明白的点最终也弄不明白,因此,我稍微花了些时间去了解了一下行盒子到底是什么东西。

此处引用《精通 CSS,高级 Web 解决方案》里面的一张图:

行内格式化模型

这里将行内格式化模型描述很清晰。由于行内盒子不能显示的设置高度,因此决定行内元素的高度那就剩下:内容高度。而影响内容高度的有两属性,分别是: line-heightfont-size(当然 font-family 也会有一定影响)。

行盒子的行高计算方法是:行盒子的整体高度减去font-size,剩余的值再平均分成两份,也就是图内的“半铅空”。例如:

1
2
3
4
.inline-box {
line-height: 28px;
font-size: 12px;
}

那么“半铅空”为 8px。加入 line-height 值为数字,如: line-height: 1.5,则表明当前 line-height 为当前 font-size 的 1.5 倍,计算方法不变。

因此在编写样式时,如果发现和设计稿不一致的情况时,若是行内元素,那么就可以考虑下是否是行高造成的问题了。

行内元素的对齐方式

除了 line-height 之外,影响行内元素对齐的属性那就是 vertical-align 了。它的默认对齐属性值为 baseline。除了 baseline 之外,其实还有很多对齐方式,如: middle, text-top, bottom 等等(更多的可参阅 MDN),举个例子:

1
2
3
4
5
6
7
<style>
span {
vertical-align: 'middle';
}
</style>

<span>This is a paragraph, and this is a <em>special</em> word.</span>

行内元素对齐比较常见的问题在于图片的对齐,一般的行内元素对齐要么令其行高一致,要么 vertical-align 统一配置同一值即可,但是图片比较特殊,对齐大概分为这么几种:

  1. top、text-top
  2. middle
  3. baseline
  4. bottom、text-bottom、sub

除了 middle 之外,其余的对齐方式会以图片的顶部或者底部来与其余行内元素对齐,因此设置图片对齐方式一般用 vertical-align: middle;又因为默认的行内元素对齐方式为 vertical-align: baseline,因此会出现图片与行内元素无法对齐的情况,了解清楚了这一点那么问题就很好解决了,即:统一行内元素的 vertical-align 的对齐方式为 middle 即可。

注:line-height 设置后会影响 top、bottom 位置,全部保留原来的不变则效果一样,详见 MDN

参考文档