on
All I want is 对齐
在项目中要某些元素对齐简直直是不能再常见的需求。
而文本的对齐
就是对齐大军中的一支先锋部队了。说实话,我到现在都有点害怕文本对齐🤦♂️。
那么,这篇blog也就呼之欲出了,今天我们就来一起学习一下文本相关的对齐。
本文注重的是不同font-size的字体对齐
说在前
有的CSS属性看起来是最基本最简单的,但是其中真的蕴藏玄机。有的时候真的觉得CSS
好难啊😭。
感觉自己一直没有很系统的去学习一遍CSS
,总是停留在某些单个的属性上会让知识变得相当的分散。无法形成体系也就意味着对整体没有概念无法通其前因后果,方难得始终啊
。
所以,类似于BFC
& IFC
这样的核心知识当然是要被提上日程。本期就先不展开讨论了~(不,我不会鸽的,不知鸽为何物)
先说说font-size
至于IFC
& ,我们当然要留到下期展开讲了
不知道大家在开发过程中有没有观察过界面里的字体。在框选它们的时候,款选的文本上下都会出现一部分的空白
接下来看看不同的字体。
相同的font-size
在框选它们的时候却拥有着不一样的高度
这就非常迷惑了,大家都是font-size: 100px
,凭啥有的高有的低呢?
想要搞起出这个问题,你必须要搞清楚字体设计和"制造"
的过程。
字体是如何“制造”出来的?
当需要设计一款字体的时候,我们肯定是针对每个字(汉字是一个字,英文则是每个字母)来逐一设计的。
每款字体
会定义一个属于自己的em-square
。可以理解为一个容器
,用来盛放单个字母或者汉字,有点像我们古代的活字印刷
。每个字符的高度是统一的,这样每个字模可以整齐地放进行和块中。
em-square
em-square
这个名字的由来,后半部分就不用说了,因为是正方形
的容器。
em
则是源于大写字母M
的宽度
。em size
是根据字模计算出的点值,所以点值为10 points
的字体em
也等于10 points
。
em
大小通常是1000 units
。在TrueType字体中,UPM约定是2的幂,通常是1024或2048。
在真正的使用这些字体时,是会根据使用的情况进行缩放
。
假如一个M
高度是700units
,那么在一个font-size: 10em
的字体中M的高度将是7em
。
为什么要说这个呢?
因为我们还没有解开为什么这些字体实际的高度
会比我们看到的字母本身的高度
上下都多出来一截这个问题。
接下来要引入一个设计字体的工具FontForge
FontForage告诉你为什么,字体实际高度比看起来要高
由于我在学习的博客中大家都提到了
FontForge
这个字体设计程序,所以接下来的截图均源于FontForge
接下来看这张图
其实我们会发现,实际高度
和字母本身的高度
相差的地方就是图中?
所指出的地方。(ig.emo直呼内行并发了个?
其实在设计字体的时候
,字体的一些属性就已经定死
了。这是字体内部的属性,是无法通过css
来改变的。
这是一张字体相关的设置图,就是设置一些字体相关的数值,每个字段所代表的含义可以看下面这张图更直观。
这里首先需要指出一点
通过测试发现,macOS 上的浏览器使用了 HHead Ascent 和 HHead Descent 值,Windows 上的浏览器使用了 Win Ascent 和 Win Descent(而且两个平台上的值不一样)。
然后我们发现,?
部分其实就是
- ?上 = Win/HHead Ascent - Type Ascent
- ?下 = Win/HHead Descent - Type Descent
而这些值都是在设计字体的时候就定好的
。
我们再来计算一次,如图所示
我们假设我们给定font-size: 100px;
这里要注意font-size是相对于em-square的,而不是字母本身
所以当我们设定了font-size: 100px;
时,实际的高度竟然有164px
(特定的某种font-family)
所以这里也解释了为什么不同的字体高度都不一样。因为设计时
就已经配置了不同的Win/HHead Ascent
& Win/HHead Descent
& other setting...
插曲baseline
emmmm,没有错,baseline其实就是指字母本身的最下侧
,在上图标出来了。
那么line-height呢?
说到line-height
就要引出两个概念,分别是content-area
&line-box
。
content-area
就是我们刚才算了半天的100px -> 164px
的那个164px的实际高度
,对就是它。它(164px)决定了content-area
的高。line-box
则是由它所有子元素的高度计算得出的,换句话说就是每个line-box一定能放得下自己所有的子元素(尤其是高度)
。
这个时候就要请出line-height
这个属性了。
可以看到如果我们设定的line-height > 计算出来的content-area
那么,line-box为了能够放得下这个内容,自然应该跟随line-height
的高度而非content-area
。
这么一来,这就打破了一个长久的谣言:line-height 表示两个 baseline 之间的距离。在 CSS 里,不是这样的。
其实我说句我个人的理解:line-height === baseline之间的距离也不是全错,它只是需要有一个前置条件,那就是line-height的高度就是content-area的高度。当然line-height === line-box的高度
更加通用。
还有另一类比较特殊的元素
- 可替换的内联元素,如 img / input / svg 等
- inline-block 元素,以及所有 display 值以 inline- 开头的元素,如 inline-table / inline-flex
- 处于某种特殊格式化上下文的内联元素,例如 flexBox 元素中的子元素都处于 flex formatting context(弹性格式化上下文)中,这些子元素的 display 值都是「blockfied」
这三种虽然都是内联元素,他们的height是取决于自己的盒模型高度的
。
那么它们的height: auto;
这个auto
的值取自谁呢??
那就是line-height
且这个时候content-area的高 === line-height
。
有趣的事儿
line-height: normal;
时,到底是多高呢?
其实这个时候就要拿出刚才的content-area
,对就是那个100px -> 164px
的content-area
。
但这个时候还要引出一个在设计字体时配置的字段line gap
。
normal时的高度是根据content-area的高度 & line gap的值
算出来,也就是说,normal的高度其实也是在设计之初就规定好我们无法改变的。取决于字体类型的。
当 line-height 的值是一个数字时,其实就是相对 font-size 的倍数
,而不是相对于 content-area。所以 line-height:1 很有可能使得 virtual-area 比 content-area 矮,从而引发很多其他的问题。
- 对于内联元素,padding 和 border 会增大 background 区域,但是不会增大 content-area(不是 line-box 的高度)。一般来说你无法再屏幕上看到 content-area。margin-top 和 margin-bottom 对两者都没有影响。
- 对于可替换内联元素(replaced inline elements)、inline-block 元素和 blockified 内联元素,padding、margin 和 border 会增大 height
一直不懂的vertical-align
首先要记住,vertical-align
的默认值是baseline
,只作用于inline,inline-block, table-cell box
。
当不同font-size
的文本以baseline
的形式对齐时,就会出现这种情况。
line-box
为了能盛下所有的自元素,它变高了
。
这种情况还可能发生在一些本身就内置了font-family的标签中。
vertical-align: middle;是什么意思?
vertical-align: middle: Aligns the middle of the element with the baseline plus half the x-height of the parent.
这里的x-height
是什么呢?
记得上面的图中有提到Capital height
是大写字母的高度
,这里的x-height
也是设计师一开始就设定好的这种字体小写字母的高度
。
baseline 所处的高度跟字体有关,x-height 的高度也跟字体有关,所以 middle 对齐也不靠谱。
所以我想要的对齐该怎么做
英文数字很简单~
import './App.css';
function App() {
return (
<div className="container">
<div>
<span className="span1">AAAAA</span>
<span className="span2">aaaaa</span>
<span className="span3">00000</span>
<span className="span4">GgGgGg</span>
</div>
</div>
);
}
export default App;
.span1 {
font-size: 30px;
}
.span2 {
font-size: 10px;
}
.span3 {
font-size: 50px;
}
.span4 {
font-size: 20px;
}
当改成中文的时候,就不行了
这是因为中文的基线不是汉字的下端。
可以分别设置不同的line-height
function App() {
return (
<div className="container">
<div class="a inline">
<div class="b">哈哈</div>
<span class="b">你好啊</span>
<b class="b">??</b>
<div class="b e1">haha</div>
<span class="b e2">小丑竟是我自己</span>
</div>
</div>
);
}
.a {
width: 100%;
border-bottom: 1px solid lightblue;
margin: 40px auto;
}
.inline .b {
display: inline;
vertical-align: bottom;
}
.a div {
font-size: 20px;
line-height: 20px;
}
.a span {
font-size: 40px;
line-height: 38px;
}
.a b {
line-height: 15px;
}
.b.e1 {
line-height: 16px;
}
.b.e2 {
line-height: 37px;
}
但这样也太傻了。。。。。
所以最终的最终,我才意识到,我学了半天对齐,竟然vertical-align救不了我??????
原来绝对定位才是最方便快捷有效的让中英文不同字体
对齐的最有效办法。