与其焦虑被 AI 取代或猜测前端是否已死, 不如看看 vertical-align 扎实你的基础!!!
与其焦虑被 AI 取代或猜测前端是否已死, 不如看看 vertical-align 扎实你的基础!!!
vertical-align设置display值为inline,inline-block和table-cell的元素竖直对齐方式.
从 line-height: normal 究竟是多高说起
我们先来看一段代码, 分析一下为什么第二行的行高, 也就是 line-height 比第一行和第三行还要高?
<p class="border-dash-black max-w-12em text-40 Helvetica">Hello, where are you from?<span class="border-dash-orange Helvetica">xHelp</span><span class="border-dash-orange PingFang">xHelp</span><span class="border-dash-orange Times-New-Roman">xHelp</span>I am from China.
</p>

要知道 line-height 就一定要先了解行盒子(line box), 因为 line-height 的定义就是行盒子的高度.
以上面的 <p> 标签为例, 在英文从左到右的书写顺序下, 每一个内联标签和不在内联标签中的文字都是从左到右排列的. 由于宽度限制, 一行不能容下更多文字的情况下就会另起一行排列. 上图中一共有 3 行, 每一行其实就是一个看不见行盒子. 行盒子就是要容下这一行中所有的元素.
我们知道, line-height 这个属性的值默认是 normal, 也就是说 <p> 的 line-height 值为 normal, 按理说每个行盒子的高度应该是一样的才对, 但是为什么第二行的行盒子就是比第一行和第三行的高呢? 原因出在 normal 这个值究竟是多少?
实际上, CSS 规范中并没有指定 normal 的值究竟是多少, 不同的字体在设计时的 normal 值差别很大. 有人做过统计, Google Fonts 上 1000+ 的字体的 line-height 的 normal 计算值从 0.9+ 到 3.3+
很多专业术语
在深挖 normal 之前, 我们需要认识一些在字体设计领域的专业术语, 实际上其中大部分我们在 CSS 的世界中也常常听到.

baseline: 小写字母x的下边界x-height: 小写字母x的高度,CSS中有一个专门表示这个高度的单位 excap height: 大写字母的高度.cap是Capital的前三个字母,Capital本身就有大写字母的意思ascender: 一些字母从baseline到高过x-height并且通常高过cap height的部分, 比如小写字母b的竖直笔画descender: 在baseline下面的部分, 比如g或者p的下半部分.UPM(Unit Per Em): 首先em是CSS中表示一个字体大小的长度单位.UPM的意思是在一个em的长度内逻辑单元的个数. 为什么是逻辑单元呢?- 在活字印刷技术当中, 传统的字体是刻在一个一个的方块上, 这个方块的高度是统一的, 通常与大写字母
M的宽度相同. 这样做是为了让这个字母的比例是正方形的(因此命名为em square) - 在字体设计领域, 不同类型的字体文件对
UPM的定义也不相同. 比如OpenType字体的UPM通常为1000. 而TrueType字体的UPM通常为2的整数次幂, 比如1024或2048. - 所以如果
H字母在OpenType字体设计时如果高度为700, 那么H在以10px的font-size展示到浏览器页面时, 其高度就是7px.
- 在活字印刷技术当中, 传统的字体是刻在一个一个的方块上, 这个方块的高度是统一的, 通常与大写字母
ascend:baseline到ascender的高度descend:baseline到descender的高度
实践出真知
有了上面的基础知识后, 我们就可以动手亲自看看 normal 的值究竟是多少了. 首先下载 fontforge 这款开源的字体设计软件, 然后下载 JetBrainsMono-Bold.ttf 这款开源字体文件.

可以看到 UPM 是 1000. 并且 Ascend 和 Descend 分别是 1020 和 -300. 当然截图中有两个上高和下深, 但我使用的是 macOS, 所以选择了 HHead 上高和 HHead 下深.
如果我们在 CSS 中使用这款字体, 看看其高度是多少?

好奇 21.5 的高度是怎么计算的吗? 其实有了上面数据, 我们就可以计算在 font-size 默认 16px 大小的前提下, 字体的高度了, 公式很简单. 最后值为 21.12

最后算出来的高度就是 21.5. 在我几周前构思这篇文章的时候计算值还是 21. 有可能是因为我更新了浏览器, 也有可能是浏览器在渲染字体的计算方式远比我这里列出的公式复杂.


不论什么原因, 我们都知道了字体的 line-height 的 normal 值是怎么大概计算出来的了. 我们也可以回答为什么第二行比第一行和第三行还要高了, 就是因为第二行中的 PingFang 字体在设计时的 normal 行高就比 Helvetica 的行高要高. 由于行盒子要容纳一行中所有元素, 所以相应的就变高了.
行距
下面就出现了新的问题, 既然第二行的行高最高并且是由 PingFang 字体撑起来, 那么其他字体呢? Helvetica 和 Times New Roman 如何处理高出来部分呢? 于是引入了行距的概念
如果我们用鼠标选中第二行出现蓝色背景, 你就会发现 Helvetica 和 Times New Roman 的橘色边框的区域处于蓝色背景垂直居中的位置. 达到这样效果就是把高出的部分一分为二, 上面放一份下面放一份. 这也就是行距.

行距翻译自英文 leading, 其中 lead 的意思是铅. 在印刷时为了增加两行文字之间的距离就会在行与行之间加上铅条. 但是注意区分行距是两行文字 baseline 之间的距离, 行高是文字高度加上行距.
进入正题
vertical-align 字如其名, 就是垂直方向的对齐. 但是这个属性只对 display 为 inline, inline-block 和 table-cell 的元素有效, 这里我们不讨论 table-cell 😅
vertical-align 的默认值就是 baseline, 也就是把子元素的 baseline 与父元素的 baseline 对齐. 我们先看一个面试题, 为什么图片的下面有一条空隙?
从一道面试题开始
<p class="border-dash-black"><img src="../../s.jpg" width="200px" alt="">
</p>

要回答这个问题需要有两个知识点
<img>元素本身没有baseline, 又因为vertical-align的默认值是baseline, 所以图片的下边缘刚好在父元素的baseline.<p>元素中压根没有一个字, 如何确定其baseline呢? 非也非也, 有东西, 只是看不见.- CSS 规范中提到, 如果一个块元素由内联元素构成, 那么
line-height指定了这个块元素的最低高度. 最低高度由两部分构成,baseline上方的高度和baseline下方的高度. 好像每一个行盒子都以一个宽度为0的inline盒子开始, 这个inline盒子的font-size和line-height继承父元素, 规范中将这个宽度为0的inline盒子成为strut, 其中文意思是支柱. - 有了
strut即便块元素没有任何元素, 也可以确定块元素的baseline.
- CSS 规范中提到, 如果一个块元素由内联元素构成, 那么
有了上面两个概念, 解决这个问题就可以从两方面入手
- 出现空隙的本质是因为
line-height不是0, 我们直接把line-height改成0或者把font-size改成0. (修改font-size也有效可以理解是因为line-height是相对于font-size计算的) - 既然
vertical-align的默认值是baseline, 那有没有其他值, 使得图片下边缘刚好就在父元素的行盒子的下边缘呢?
你别说, 还真有, 就是 bottom.
vertical-align 的关键字属性
- 第一组: 与
line box有关top: 元素的上边界与line box的上边界对齐bottom: 元素的下边界与line box的下边界对齐
- 第二组: 与
content area有关text-top: 元素的上边界与content area的上边界对齐text-bottom: 元素的下边界与content area的下边界对齐super: 元素的baseline与content area的sup元素的baseline对齐sub: 元素的baseline与content area的sub元素的baseline对齐middle: 元素的高度中心在父元素的baseline加上x-height一半的地方
我知道你有点晕, 先别晕, 虽然 <sup> 和 <sub> 不常见, 但是在数学和化学中常常用到的标签.
<p><span>x<sup>2</sup>y</span><span>H<sub>2</sub>O</span>
</p>

上面又出现了 content area 这个奇怪的新概念, 没关系, CSS 2.1 并没有定义 inline 元素的 content area 是什么, 在这里我们就简单理解成 content-box(📖注意下图中特别标注添加了 padding 的部分).

多一句, vertical-align 还支持数值类型和百分比类型的值, 其中百分比类型是相对于 line-height 计算的.
震惊! baseline 的移动
同样是 inline-block, 不同的内容竟然存在着 baseline 移动的情形, 希望平时没有注意的你这次一定要注意了.
<p class="border-dash-black">x<span class="border-dash-orange inline-block p-10">xHelp</span><span class="border-dash-orange inline-block p-10 w-40 overflow-hidden">xHelpxHelp</span><span class="border-dash-orange inline-block p-10 w-5 h-5"></span>
</p>

同样都是 display: inline-block 的元素, 但是看起来 baseline 却大有不同
正常文字内容:baseline就是文字的baseline设置 overflow: hidden:baseline是元素的下边界无内容:baseline是元素的下边界
所以在遇到不同类型的对齐需求时的一定要注意.
参考
- https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align
- https://christopheraue.net/design/vertical-align#centering-an-icon
- https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align
- https://www.w3.org/TR/CSS2/visudet.html#strut
谢谢你看到这里😊 还和我标题中说的一样, 我不知道未来是怎么样, 但我写这篇文章的时候焦虑有很多缓解, 因为我学到了很多知识, 最关键的是, 我行动了!!!
相关文章:
与其焦虑被 AI 取代或猜测前端是否已死, 不如看看 vertical-align 扎实你的基础!!!
与其焦虑被 AI 取代或猜测前端是否已死, 不如看看 vertical-align 扎实你的基础!!! vertical-align 设置 display 值为 inline, inline-block 和 table-cell 的元素竖直对齐方式. 从 line-height: normal 究竟是多高说起 我们先来看一段代码, 分析一下为什么第二行的行高, 也就…...
路由、交换机、集线器、DNS服务器、广域网/局域网、端口、MTU
前言:网络名词术语解析(自行阅读扫盲),推荐大家去读户根勤的《网络是怎样连接的》 路由(route): 数据包从源地址到目的地址所经过的路径,由一系列路由节点组成。某个路由节点为数据包选择投递方向的选路过程。 路由器工作原理 路…...
在全志V851S开发板上进行屏幕触摸适配
1.修改屏幕驱动 从ft6236 (删掉,不要保留),改为下面的 路径:/home/wells/tina-v853-open/tina-v853-open/device/config/chips/v851s/configs/lizard/board.dts(注意路径,要设置为自己的实际路…...
字符串拷贝时的内存重叠问题
字符串拷贝时的内存重叠问题 1.什么是内存重叠 拷贝的目的地址在源地址的范围内,有重叠。 如在写程序的过程中,我们用到的strcpy这个拷贝函数,在这个函数中我们定义一个目的地址,一个源地址,在拷贝的过程中如果内存重…...
告别PPT手残党!这6款AI神器,让你秒变PPT王者!
如果你是一个PPT手残党,每每制作PPT总是让你焦头烂额,那么你一定需要这篇幽默拉风的推广文案! 我向你保证,这篇文案将帮助你发现6款AI自动生成PPT的神器,让你告别PPT手残党的身份,成为一名PPT王者。 无论…...
JVM配置与优化
参考: JVM内存分区及作用(JDK8) https://blog.csdn.net/BigBug_500/article/details/104734957 java 进程占用系统内存过高分析 https://blog.csdn.net/fxh13579/article/details/104754340 Java之jvm和线程的内存 https://blog.csdn.ne…...
电力系统储能调峰、调频模型研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
C++基础之类、对象一(类的定义,作用域、this指针)
目录 面向对象的编程 类的引入 简介 类的定义 简介 访问限定符 命名规则 封装 简介 类的作用域 类的大小及存储模型 this指针 简介 面向对象的编程 C与C语言不同,C是面向对象的编程,那么什么是面向对象的编程呢? C语言编程,规定…...
javaScript---设计模式-封装与对象
目录 1、封装对象时的设计模式 2、基本结构与应用示例 2.1 工厂模式 2.2 建造者模式 2.3 单例模式 封装的目的:①定义变量不会污染外部;②能作为一个模块调用;③遵循开闭原则。 好的封装(不可见、留接口):①…...
【消息中间件】kafka高性能设计之内存池
文章目录 前言实现创建内存池分配内存释放内存 总结 前言 Kafka的内存池是一个用于管理内存分配的缓存区域。它通过在内存上保留一块固定大小的内存池,用于分配消息缓存、批处理缓存等对象,以减少频繁调用内存分配函数的开销。 Kafka内存池的实现利用了…...
创建型模式——单例(singleton)
1. 模式说明 单例模式保证类只有一个实例;创建一个对象,当你创建第二个对象的时候,此时你获取到的是已经创建过的对象,而不是一个新的对象; 1.1 使用场景 共享资源的访问权限;任务的管理类;数…...
算法:迷宫问题
描述 定义一个二维数组 N*M ,如 5 5 数组下所示: int maze[5][5] { 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, }; 它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或…...
聊聊并发编程的12种业务场景
前言 并发编程是一项非常重要的技术,无论在面试,还是工作中出现的频率非常高。 并发编程说白了就是多线程编程,但多线程一定比单线程效率更高? 答:不一定,要看具体业务场景。 毕竟如果使用了多线程&…...
MySQL执行顺序
MySQL执行顺序 MySQL语句的执行顺序也是在面试过程中经常问到的问题,并且熟悉执行顺序也有助于SQL语句的编写。 SELECT FROM JOIN ON WHERE GROUP BY HAVING ORDER BY LIMIT执行顺序如下: FROM ON JOIN WHERE GROUP BY # (开始使用别名) SUM # SUM等…...
引领真无线耳机未来趋势,NANK南卡OE骨传导真无线耳机惊艳亮相
传统的蓝牙耳机存在很多问题,例如续航时间短、长期佩戴耳朵会不舒服,甚至影响听力等等。为了解决这些问题,在骨传导领域深耕十多年的南卡品牌推出了这款真无线骨传导耳机——NANK南卡 OE。 NANK南卡OE即将正式上线,这一消息一经宣…...
5款写作神器,帮助你写出5w+爆款文案,好用到哭
我不允许还有文案小白、新手博主不知道这5款写作利器! 每次一写文案就头秃的新媒体工作者,赶紧看过来吧!这5款好用到爆的写作神器,喝一杯咖啡的时间就能完成写作。 我和同事都是用它们,出了很多的爆款,现…...
相交链表问题
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 图示两个链表在节点 c1 开始相交: 题目数据 保证 整个链式结构中不存在环。 注意,函数返回结果后&…...
[ubuntu] ax200网卡虚接,导致系统根目录占满而无法进入系统的奇葩问题
20230508,我像往常一样,打开电脑发现根目录满了,报警了,所以按照网上的教程,清理了一下根目录的文件,没想到背后是网卡问题… 文章目录 1.进入终端模式2.查看占用情况3.清理系统log文件3.1 清理/var/log/syslog3.2 清…...
本地字体库的引入方法
本地字体库是指在计算机系统中存储的一组字体文件,通常包含多种字体格式,如TTF、OTF、WOFF等。引入本地字体库可以让用户在使用计算机时可以选择不同的字体,从而提高用户的使用体验。 本地字体库的引入方式有多种,其中比较常用的是…...
7种优秀的导航菜单设计总结
导航是应用程序界面中最常见的模块之一,在链接应用程序中起着每个页面的作用。 不同的设计需求和业务目标决定了导航的设计因品而异,移动设备的尺寸远小于计算机。因此,在设计移动终端导航时,应考虑更全面,以确保简单…...
一键体验:星图平台OpenClaw+百川2-13B-4bits量化模型沙盒环境
一键体验:星图平台OpenClaw百川2-13B-4bits量化模型沙盒环境 1. 为什么选择沙盒环境 作为长期关注AI自动化工具的技术爱好者,我一直在寻找低门槛体验OpenClaw的方案。本地部署虽然可控性强,但配置Python环境、解决CUDA依赖、调试模型连接等…...
QMCDecode终极指南:3分钟解锁QQ音乐加密文件,让音乐真正属于你!
QMCDecode终极指南:3分钟解锁QQ音乐加密文件,让音乐真正属于你! 【免费下载链接】QMCDecode QQ音乐QMC格式转换为普通格式(qmcflac转flac,qmc0,qmc3转mp3, mflac,mflac0等转flac),仅支持macOS,可自动识别到…...
教培人必看!那些好用到哭的网课平台大盘点
一、引言:网课平台,教培行业的新战场 在互联网浪潮的席卷下,教培行业正经历着前所未有的变革。曾经,学生们只能在固定的时间和地点,坐在教室里听老师授课。而如今,随着网课平台的兴起,学习的时…...
ComfyUI-TeaCache:突破AI创作效率瓶颈的全方位优化方案
ComfyUI-TeaCache:突破AI创作效率瓶颈的全方位优化方案 【免费下载链接】ComfyUI-TeaCache 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-TeaCache 在AI图像生成领域,推理速度与生成质量的平衡始终是创作者面临的核心挑战。ComfyUI-Tea…...
Coze智能客服部署指南:从零搭建到生产环境最佳实践
最近在折腾智能客服系统的部署,发现市面上虽然方案不少,但真正能兼顾快速落地、稳定运行和成本可控的并不多。Coze 作为一个新兴的选项,以其灵活的架构和不错的性能吸引了我。经过一番从零到生产环境的摸索,我总结了一套部署指南&…...
Zig语言实战:5分钟搞定HTTP客户端与服务端开发(附完整代码)
Zig语言Web开发实战:从零构建HTTP客户端与服务端 最近在探索新兴系统编程语言时,Zig以其简洁的语法和强大的性能引起了我的注意。特别是它的标准库中内置了完整的HTTP支持,这让Web服务开发变得异常简单。本文将带你快速上手Zig语言的Web开发&…...
FormCreate事件监听全攻略:从‘change’到‘control’,让你的表单真正‘活’起来
FormCreate事件监听全攻略:从‘change’到‘control’,让你的表单真正‘活’起来 表单开发从来不只是静态字段的堆砌。当你的用户需要根据前一个选择动态调整后续选项,当表单提交前需要实时校验多个字段的关联性,当字段间的显示逻…...
Docker 学习之路-从入门到放弃-Jenkins:4
Jenkins 打开 ✅ 如图已经完全成功安装并初始化Jenkins了!从图1可以确认:能正常访问Jenkins Web管理界面、登录成功核心功能入口(Create a job/Manage Jenkins等)正常显示构建执行器(Build Executor Status)…...
Pixel Mind Decoder 嵌入式应用初探:STM32设备日志情绪分析
Pixel Mind Decoder 嵌入式应用初探:STM32设备日志情绪分析 1. 场景痛点与解决方案 在工业物联网领域,设备维护一直是个让人头疼的问题。想象一下,工厂里几十台STM32设备日夜运转,工程师们每天要盯着密密麻麻的日志数据…...
Pyrocko + PSGRN/PSCMP小问题
1.先看看你的脚本,然后诊断 config 文件的问题。问题很明确——YAML 解析 config 文件时在 earthmodel_1d 块标量那里报错。大概率是 |2 缩进指示符和实际内容缩进不匹配。 让我先下载脚本看看,然后直接诊断:fomosto 不在当前环境࿰…...
