美文网首页
深入了解CSS:字体度量、line-height和vertica

深入了解CSS:字体度量、line-height和vertica

作者: tangyefei | 来源:发表于2021-04-04 18:02 被阅读0次

    原文地址:Deep dive CSS: font metrics, line-height and vertical-align

    注:翻译中对内容进行了不少简化,力求不陷入繁缛的细节。

    文章目录

    • 你真的了解它们吗
    • 首先聊聊font-size
    • line-box 和 inline-element
    • line-height相关的问题
    • vertical-align一个属性将它们串起来
    • CSS真奇妙
    • 知识点总结

    你真的了解它们吗

    很多人以为自己知道 line-heightvertical-align 是怎么工作的,以及怎么使用它们。但实际上,它们非常复杂,并且是在CSS特性 inline formating context 中扮演主要的角色。

    测试你的理解情况,可以尝试回答下面几个问题:

    问题1:line-height 可以是具体的单位值,也可以是无单位数值,但它的默认值是 normal,什么是 normal?通常我们把它当作1或1.2,又或者是1到1.2之间的数值?CSS的规范中都没有清楚地说明这一点。

    问题2:我们知道line-height使用无单位数值的是相对 font-size而言,但问题是font-size:100px 对于不同的字体而言有着截然不同的表现,所以line-height的效果是相同的还是不同的呢?我们知道line-height使用无单位数值的是相对 font-size而言,但问题是font-size:100px 对于不同的字体而言有着截然不同的表现,所以line-height的效果是相同的还是不同的呢?

    问题3:vertical-align 对 line-height 有什么影响呢?

    首先聊聊font-size

    下面的简单HTML代码中,三个 <p> 标签包含了对应的 <span> ,区别在于它们有不同的 font-family

    <p>
        <span class="a">Ba</span>
        <span class="b">Ba</span>
        <span class="c">Ba</span>
    </p>
    
    p  { font-size: 100px }
    .a { font-family: Helvetica }
    .b { font-family: Gruppo    }
    .c { font-family: Catamaran }
    
    image.png

    相同的 font-size 作用在不同的 font-family 上导致了不同高度,原因是:

    • 每个字体都有它的em-square(默认字体容器高度,字体就在这个容器内被绘制),通常它的基准单位被设置为1000单位,但也有字体是1024、2048单位,甚至任何单位
    • 正是基于这个em-square的单位,字体的ascend,descend,capital height,x-height等被确定

    FontForge 打开 Catamaran 字体,可以看到它的一些数值(结合下面两张图来看):

    • em size(基准单位):1000
    • ascent(上升部分):1100
    • descent(下沉部分): 540
    • capital height(大写高度): 680
    • x height(小写高度): 485
    image.png image.png

    总结:

    Catamaran字体在1000单位的em-square 中使用了1640单位的高度,设置 ****font-size:100px**** 最终得到了 ****164px** **的高度,我们称这个高度为 ****content-area**** ,你可以将它等同于 ****background**** 起作用的高度。

    line-box 和 inline-element

    在下面的例子中, <p> 元素受限于它的宽度,视觉上分了三行展示,每一行称作 inline-box。每一行都由匿名 或 带HTML标签的inner element组成,inline-box 的高度由它所包含的 inner element 决定。

    line-box的高度肯定能容纳它的所有子元素,因此如果你知道了一个HTML元素的所有line-box的高度,那么你就知道了这个元素的高度(想加即可)。

    下图中可以看到第二个line-box的高度大于另外两个,因为 Catamaran 字体的 content-area 高于其他的字体。

    <p>
        Good design will be better.
        <span class="a">Ba</span>
        <span class="b">Ba</span>
        <span class="c">Ba</span>
        We get to make a consequence.
    </p>
    
    image.png

    不过实际应用中,如果有多个line-box你是无法看到单个line-box的高度的。

    line-height相关的问题

    image.png

    一个 inline element 有两个高度

    • content area,字体内容的高度(计算公式为:ascend+descend)
    • virtual area,用于计算line-box的高度,等于 line-height(作者发明了这个称呼)

    virtual area 和 content area 高度的差值,分别对半被添加到了顶部和地步的 leading 中。依据 line-height的具体知道,这个差值可能为0、正数、负数。负数意味着virtual arae的高度低于content area。

    还有一些类型的inline elements,他们的高度会由 height 、marign、border属性决定。如果 height 设置为 auto,那么(似乎默认就设置了,因此此处不强调它) content-area 的高度严格和line-height相等。

    • replaced inline elements: <img> <input> <svg>
    • inline-blockinline-* 元素
    • 在某些特殊的formating content 中(比如 flexbox中的元素)的inline元素

    注:你可以尝试将 <p> 包含的 <span>设置 display:inline-block,可以看到 content-area(背景颜色区域)变得和virtual area一样了。

    所以回到开篇问题:line-height 的 normal 的值是多少?

    我们以另外一个字体 Arial 为例,它的 em-square取的基准单位是 2048,ascender的高度是1854单位,descender的高度是434单位,行间距是67单位,计算得到font-size:100px时,content-area的高度是:

    (1854+434)/2048100=112px(小数点后四舍五入),line-height:normal的高度是:(1854+434+67)/2048100=115px。因此 line-height:normal 的高度通常是由字体的设计者决定的。

    所以显而易见的是:设置 line-height:1 是一种糟糕的实践,因为我们它相对的是font-size(即em-square),而不是 content-area,结果就是 virtual area 比 content area小。

    我(注:原文作者)统计了电脑上安装的1117中字体,发现95%的字体 line-height的值都大于1,计算得到的line-heigt的值在 0.618到3.378之间。

    一些line-box计算的知识点

    • inline元素,padding和border会导致背景区域变大,但是content-area高度不变,可知content-area的高度并不总和你看到的一致;margin-top和margin-bottom没有效果。
    • 对于replaced inline elements设置 inline-block后,padding margin border都会增加高度:包括content-area和line-box的高度。

    vertial-align一个属性将它们串起来

    虽然到目前位置我们还没提起过 vertical-align,但实际上它可能是 inline formating context 的最重要的概念。

    vertical-align 的默认值是 baseline,如果你还记得前面条的 ascender 和 descender的话,它们的value决定了baseline的位置,以及上下leading的比率(很少是50/50)。

    <p>
        <span>Ba</span>
        <span>Ba</span>
    </p>
    
    p {
        font-family: Catamaran;
        font-size: 100px;
        line-height: 200px;
    }
    

    一个 <p> 标签包含两个相邻的 <span> 元素,它们都继承相同的 font-family , font-sizeline-height 。两个 <span>元素的baseline对齐并且line-box的高度和line-height一样。

    image.png

    如果我们把第二个元素的 font-size 设置得更小一些会怎么样?

    span:last-child {
        font-size: 50px;
    }
    

    可以看到,默认的baseline对齐导致了更高的line-box:line-box的高度计算方式是由子元素的最高点到最低点

    image.png

    让我们看看另外一个例子,一个 <p> 标签设置了 line-height: 200px,包含一个 <span> 继承了父级的 line-height

    <p>
        <span>Ba</span>
    </p>
    
    p {
        line-height: 200px;
    }
    span {
        font-family: Catamaran;
        font-size: 100px;
    }
    

    line-box的高度会是多少呢?我们期望它是200px,事实上 <p> 有它自己的 font-famliy,结果就是 <p> 的baseline和 <span> 的baseline不同,更高的baseline导致了更高的context-area的高度。在规范中这个规则叫strut:0宽度的字符也会参与line-box的计算当中。

    image.png

    直接使用 vertical-align: middle 能解决这个问题吗?如规范中所说, middle 对齐的是:垂直中点加上x-height高度的一半。考虑到上下ratio并不相同,设置为 middle 也不可靠,在大多数情况下,middle 并不表示的绝对中间位置。

    顺带提一下,还有4个值可能会有用:

    • vertical-align: top / bottom 对齐line-box的头部和底部
    • vertical-align: text-top / text-bottom 对齐content-area的头部或底部
    image.png

    当仍旧要小心的是,多数情况下对齐的参照标准是 virtual area,看看同样使用了 vertical-align: top 的例子:line-height导致了奇怪但并不令人惊讶的结果

    image.png

    最后, vertical-align 可以忽略baeline的位置接受数字类型的值,它可能会派上用场。

    CSS真奇妙

    最后原文作者演示了如何设置一个字体的各个部位的高度,可以做到让不同字体在同一个 line-box齐整的对仗,但在实际中有若干理由并不推荐你这么做。

    知识点总结

    • inline formatting context 是一个实在难以理解的概念
    • 所有的inline elements有两个高度:context area 和 virtual area,并且它们都无法被视觉查看到
    • line-height: normal 是基于每种字体的设计而定的
    • vertical-align 是不可靠的
    • 一个 line-box 高度计算是基于所有子元素的 line-heightvertical-align
    • 在CSS中查询或设置字体的度量并不容易

    相关文章

      网友评论

          本文标题:深入了解CSS:字体度量、line-height和vertica

          本文链接:https://www.haomeiwen.com/subject/joulkltx.html