【CSS in Depth 2 精译】2.2 em 和 rem + 2.2.1 使用 em 定义字号
当前内容所在位置
- 第一章 层叠、优先级与继承
- 第二章 相对单位
- 2.1 相对单位的威力
- 2.1.1 响应式设计的兴起
- 2.2 em 与 rem ✔️
- 2.2.1 使用 em 定义字号 ✔️
- 2.2.2 使用 rem 设置字号
- 2.3 告别像素思维
- 2.4 视口的相对单位
- 2.5 无单位的数值与行高
- 2.6 自定义属性
- 2.7 本章小结
2.2 em 与 rem
em 是最常见的相对长度单位,也是排版中用于设置字体大小(即字号)的度量单位。在 CSS 中,1em
表示当前元素的字号,具体大小取决于作用的元素。图 2.1 为一个内边距 padding
为 1em
的 div
元素:
图 2.1 1em 内边距等同于当前字号(虚线用于展示内边距大小)
其样式代码如代码清单 2.1 所示。规则集指定字号为 16px
,即该元素在本地定义的 1em
的实际大小。随后又用 em
设置了其内边距。将代码清单 2.1 中的样式拷到一个新样式表,并在元素 <div class="padded"
中放一些文字,看看最终效果。
代码清单 2.1 对 padding
使用相对单位 em
.padded {font-size: 16px;padding: 1em; /* Sets padding on all sides equal to font-size */
}
可以看到 padding
的值为 1em
,再乘以字号,则渲染出了大小为 16px
的内边距。重点来了:浏览器根据相对单位声明的值计算出的绝对单位值,称为 计算值(computed value)
若将本例中的 padding
改为 1.5em
,则计算值变为 24px
;如果另一个选择器也指向该元素并设置了不同的字号,则会修改本地 em
的大小,算出的 padding
值也会随之更新。
使用 em
来设置 padding
、height
、width
及 border-radius
会非常方便,因为当元素继承了不同的字号,或者用户变更了字体设置,这些样式也会跟随当前元素均匀地缩放。
图 2.2 展示了两个不同大小的盒子,它们的字号、内边距及圆角半径都各不相同:
图 2.2 设置了相对大小的内边距和圆角半径会随字号的改变而同步缩放
为上述盒子定义样式时,可以用 em
指定其内边距及圆角半径,比如设为 1em
;此时修改各元素的字号,这些属性就会随着字体一起缩放。
按以下代码更新 HTML 示例文件,并给元素分别添加样式类 box-small
、box-large
,作为尺寸修饰符:
<span class="box box-small">Small</span>
<span class="box box-large">Large</span>
接着,按照代码清单 2.2 所示添加样式。该样式以 em
为单位定义了一个 box
类,同时还指定了上述一大一小两个修饰符,利用不同的字号大小缩放各自所在的元素。
代码清单 2.2 将 em 应用到不同元素
.box {padding: 1em;border-radius: 1em;background-color: lightgray;
}.box-small {font-size: 12px; /* 与 L12 不同的字号,该字号定义了当前元素的 em 大小 */
}.box-large {font-size: 18px; /* 与 L8 不同的字号,该字号定义了当前元素的 em 大小 */
}
这就是 em 的强大之处:定义某个元素的大小后,只需一句变更字号的样式声明,就能缩放整个元素。稍后会再举一例,在此之前,先聊聊 em
和字号设置相关的话题。
2.2.1 使用 em
定义字号
当 em
作用于 font-size
属性(property
)时,其表现略有不同。之前讲到,当前元素字号决定了 em
的大小;但如果声明 font-size: 1.2em
会怎样呢?一个字号肯定不能等于自身的 1.2 倍;事实上,font-size
属性上的 em
的大小是基于它继承的字号计算出来的。
举个简单的例子。如图 2.3 所示,有两段字号各异的文字,样式按代码清单 2.3 所示,用 em
进行设置。
图 2.3 使用 em
定义两种不同的字号
按以下代码更新页面。第一行文本在 <body>
标签内,则会按 body 的字号进行渲染;带 slogan 样式类那行,则会继承该字号来渲染:
<body>We love coffee<p class="slogan">We love coffee</p> <!-- slogan 继承了 <body> 的字号 -->
</body>
代码清单 2.3 中的样式指定了 body
的字号,为便于演示,这里用像素作单位。接着使用 em
来增大 slogan 的字体大小。
代码清单 2.3 使用 em
定义 font-size
body {font-size: 16px;
}
.slogan {font-size: 1.2em; /* 经计算,字号为该元素继承字号的 1.2 倍 */
}
此时 slogan 的字号为 1.2em
。要拿到计算出的像素值,需要参考继承来的大小为 16px 的字体。由于 16 × 1.2 = 19.2,所以算出的实际字体大小为 19.2px
。
提示
如果已知字号的像素值,但是想声明为 em 的形式,则用这个简单公式换算:目标像素值 ÷ 父元素(继承)字号的像素值。比如,目标字号为
10px
,该元素继承的字号为12px
,转成em
则为 10 / 12 = 0.8333em;目标字号16px
、父级字号12px
,转成em
则为 16 / 12 = 1.3333em。本章还会进行几次类似的计算。
大多数浏览器的默认字号均为 16px,记住这些知识将大有好处。用专业的话来讲,关键字 medium
的值经计算为 16px
大小。
1 em 同时用于字号和其他属性
至此,我们已经用 em
定义了字号(基于继承的字号),并且通过 em
定义了其他属性,比如 padding
和 border-radius
(基于当前元素的字号)。当使用 em
给同一个元素同时设置字号和其他属性时,情况就变得复杂多了。此时,浏览器必须先计算字号,然后再利用算出的结果进一步算出其余属性的具体取值。这两类属性的声明值可能相同,但计算值却未必相等。
前面的示例中,带有 slogan
样式类的元素最终字号为 19.2px
(=继承字号 16px
× 1.2em
)。如图 2.4 所示,元素还是 slogan
不变,只是内边距 padding
调大到 1.2em
。背景设为灰色以便观察内边距的实际效果。可以看到内边距比字号还要偏大一些,尽管二者的声明值都相同。
图 2.4 em 定义的字号有别于同样用 em 定义的内边距
这是因为段落标签从 body
元素继承了 16px
的字号,实际字号变为了 19.2px
。此时 19.2px
即为该段落元素 1em
的最终大小,padding
的具体大小也是基于这个值进行计算的。相应的 CSS 代码如下所示,更新到示例页查看最终效果:
代码清单 2.4 使用 em
定义 font-size
和 padding
body {font-size: 16px;
}
.slogan {font-size: 1.2em; /* 计算值为 19.2px */padding: 1.2em; /* 计算值为 23.04px */background-color: #ccc;
}
本例中,padding
的声明值为 1.2em
,乘以 19.2px
(当前元素字号),得到计算值 23.04px
。尽管 font-size
和 padding
的声明值相同,但计算值却不相等。
2 字体缩小的问题
当 em
用于设置具有多级嵌套结构的元素字体时,也会产生意想不到的结果。为了算出每个元素的具体大小,就得知道它们继承的字号是多少;如果父元素碰巧也是用 em
来定义的,就要看该父元素的继承值是多少,以此类推,一直沿着 DOM 树向上考察。
当使用 em
给列表元素定义字号、列表又嵌套了多级子列表时,问题很快就显现出来了。几乎每一位 Web 开发人员在职业生涯的某个阶段加载这样的页面都会碰到类似图 2.5 所示的情况。文字在逐级缩小!正是这样的问题让广大开发人员对 em
敬而远之。
图 2.5 字号设为 0.8em 导致嵌套列表中的文字逐级缩小
当列表又嵌套了多级子列表、并且给列表逐级设置基于 em
的相对字号时,就会发生文字缩小的现象(译注:其值须小于 1 才会缩小,大于 1 则为逐级放大)。如代码清单 2.5 所示,将无序列表的字号设为 0.8em
后,由于该选择器会对页面上每一个 <ul>
元素生效,从而让内层元素逐级继承外层元素的 em
字号,字体的坍缩幅度也随之逐级叠加。
代码清单 2.5 使用 em 指定无序列表的字号
body {font-size: 16px;
}
ul {font-size: 0.8em;
}
若将上述样式应用到代码清单 2.6 所示的 HTML 中,就会出问题。每一个 <ul>
都从父列表继承字号,这些 em
值只会让字体逐渐缩小:
代码清单 2.6 嵌套列表 HTML
<ul><li>Top level<ul> <!-- 该列表嵌套在第一个列表中,继承第一个列表的字号 --><li>Second level<ul> <!-- 该列表嵌套在上一个列表中,继承第二个列表的字号 --><li>Third level<ul> <!-- 依此类推 --><li>Fourth level<ul><li>Fifth level</li></ul></li></ul></li></ul></li></ul></li>
</ul>
每级列表的字号都是其父列表的 0.8 倍,即:第一个列表的实际字号为 12.8px
,下一级则为 10.24px
(12.8px
× 0.8),第三级则为 8.192px
,依此类推。同理,如果各级字号大于 1em
,实际字体大小会逐渐增大。而我们想要的效果是只设置最外层的字号,然后让里面的字体大小保持一致,如图 2.6 所示。
图 2.6 文字大小正常的嵌套列表
实现上述效果的一种解决方案如代码清单 2.7 所示。先设置一级列表的字号为 0.8em
(同代码清单 2.5);再用第二个选择器选中除最顶层外、所有无序列表下的所有后代列表,并设置字号等于其父级字号,最后得到如图 2.6 所示的效果。
代码清单 2.7 更正文字缩小问题
ul {font-size: 0.8em;
}
ul ul { font-size: 1em; /* 嵌套列表的字号应与其父级字号一致 */
}
问题倒是解决了,尽管不是很理想——定好一个字号,立马又用另一个字号去覆盖掉。如果不用提高选择器的优先级来覆盖规则,就再好不过了。
至此,各位也该心里有数了:使用 em
稍有不慎就会变得难以驾驭。em
用在内边距、外边距以及元素尺寸上时挺省心的;可一旦用到字号上,省心就容易变成闹心。好在 CSS 还有一个更好的方案—— rem
。
相关文章:

【CSS in Depth 2 精译】2.2 em 和 rem + 2.2.1 使用 em 定义字号
当前内容所在位置 第一章 层叠、优先级与继承第二章 相对单位 2.1 相对单位的威力 2.1.1 响应式设计的兴起 2.2 em 与 rem ✔️ 2.2.1 使用 em 定义字号 ✔️2.2.2 使用 rem 设置字号 2.3 告别像素思维2.4 视口的相对单位2.5 无单位的数值与行高2.6 自定义属性2.7 本章小结 2.…...
C++Primer Plus 第十四章代码重用:14.4.4 数组模板示例和非类型参数
系列文章目录 14.4.4 数组模板示例和非类型参数 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 系列文章目录14.4.4 数组模板示例和非类型参数 14.4.4 数组模板示例和非类型参数 模板常用作容器类,这…...

短视频哪个软件好用?成都柏煜文化传媒有限公司
短视频哪个软件好用?一文带你了解各大平台特色 随着移动互联网的飞速发展,短视频已经成为现代人生活中不可或缺的一部分。市面上涌现出众多短视频平台,它们各具特色,满足了不同用户的需求。那么,短视频哪个软件好用呢…...

金融科技:重塑用户体验,驱动满意度飙升
随着科技的飞速发展,金融科技(FinTech)已经深入到我们生活的每一个角落,从日常支付到投资理财,再到跨境汇款,它都在悄无声息地改变着我们的金融行为。而在这背后一个不可忽视的驱动力就是金融科技对用户体验…...
JavaScript——算术运算符
目录 任务描述 相关知识 - * / %运算符 递增运算符和递减运算符 编程要求 任务描述 本关任务:给定两个字符串变量,把它们转为数字后相除,拼接被除数、除数和余数为一个新的字符串。 例如:a 为 "5",b 为…...

备份SQL Server数据库并还原到另一台服务器
我可以将SQL Server数据库备份到另一台服务器吗? 有时您可能希望将 SQL数据库从一台服务器复制到另一台服务器,或者将计算机复制到计算机。可能的场景包括测试、检查一致性、从崩溃的机器恢复数据库、在不同的机器上处理同一个项目等。 是的,…...

二刷算法训练营Day45 | 动态规划(7/17)
目录 详细布置: 1. 139. 单词拆分 2. 多重背包理论基础 3. 背包总结 3.1 背包递推公式 3.2 遍历顺序 01背包 完全背包 详细布置: 1. 139. 单词拆分 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单…...

大模型项目落地时,该如何估算模型所需GPU算力资源
近期公司有大模型项目落地。在前期沟通时,对于算力估算和采购方案许多小伙伴不太了解,在此对相关的算力估算和选择进行一些总结。 不喜欢过程的可以直接 跳到HF上提供的模型计算器 要估算大模型的所需的显卡算力,首先要了解大模型的参数基础知识。 大模型的规模、参数的理解…...

LLM应用开发-RAG系统评估与优化
前言 Hello,大家好,我是GISer Liu😁,一名热爱AI技术的GIS开发者,在上一篇文章中,我们学习了如何基于LangChain构建RAG应用,并且通过Streamlit将这个RAG应用部署到了阿里云服务器;&am…...

秋招突击——第七弹——Redis快速入门
文章目录 引言Redis是什么 正文对象String字符串面试重点 List面试考点 压缩列表ZipList面试题 Set面试题讲解 Hash面试重点 HASHTABLE底层面试考点 跳表面试重点 ZSET有序链表面试重点 总结 引言 在项目和redis之间,我犹豫了一下,觉得还是了解学习一下…...

软考初级网络管理员__操作系统单选题
1.在Windows资源管理器中,假设已经选定文件,以下关于“复制”操作的叙述中,正确的有()。 按住Ctr键,拖至不同驱动器的图标上 按住AIt键,拖至不同驱动器的图标上 直接拖至不同驱动器的图标上 按住Shift键࿰…...
从入门到精通:网络编程套接字(万字详解,小白友好,建议收藏)
一、预备知识 1.1 理解源IP地址和目的IP地址 在网络编程中,IP地址(Internet Protocol Address)是每个连接到互联网的设备的唯一标识符。IP地址可以分为IPv4和IPv6两种类型。IPv4地址是由32位二进制数表示,通常分为四个八位组&am…...

dledger原理源码分析系列(一)架构,核心组件和rpc组件
简介 dledger是openmessaging的一个组件, raft算法实现,用于分布式日志,本系列分析dledger如何实现raft概念,以及dledger在rocketmq的应用 本系列使用dledger v0.40 本文分析dledger的架构,核心组件;rpc组…...

第七节:如何浅显易懂地理解Spring Boot中的依赖注入(自学Spring boot 3.x的第二天)
大家好,我是网创有方,今天我开始学习spring boot的第一天,一口气写了这么多。 这节通过一个非常浅显易懂的列子来讲解依赖注入。 在Spring Boot 3.x中,依赖注入(Dependency Injection, DI)是一个核心概念…...
Postman自动化测试实战:使用脚本提升测试效率
在软件开发过程中,接口测试是确保后端服务稳定性和可靠性的关键步骤。Postman作为一个流行的API开发工具,提供了强大的脚本功能来实现自动化测试。通过在Postman中使用脚本,测试人员可以编写测试逻辑,实现测试用例的自动化执行&am…...
CSMA/CA并不是“公平”的
CSMA/CA会造成过于公平,对于最需要流量的节点,是最不友好的,而对于最不需要流量的节点,则是最友好的。 CSMA/CA是优先公平来工作的。 CSMA/CA首先各节点使用DIFS界定air idle,在此期间大家都等待 其次,为了同时发送引起碰撞,在DIFS之后随机从CWmin和CWmax之间选择一个时…...

【漏洞复现】I doc view——任意文件读取
声明:本文档或演示材料仅供教育和教学目的使用,任何个人或组织使用本文档中的信息进行非法活动,均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现测试工具 漏洞描述 I doc view 在线文档预览是一个用于查看、编辑、管理文档的工具…...

图数据库 vs 向量数据库
最近大模型出来之后,向量数据库重新翻红,业界和市场上有不少声音认为向量数据库会极大的影响图数据库,图数据库市场会萎缩甚至消失,今天就从技术原理角度来讨论下图数据库和向量数据库到底差别在哪里,适合什么场景&…...
企业品牌出海第一站 维基百科词条创建
维基百科是一部内容开放、自由的网络百科全书,旨在创造一个涵盖所有领域知识,服务所有互联网用户的知识性百科全书。其在国外应用非常广泛且认可度很高,国内品牌出海或国际品牌都很有必要创建企业自己的维基百科页面,以及企业高管的个人维基百科页面。 如…...

Windows下activemq集群配置(broker-network)
1.activemq版本信息 activemq:apache-activemq-5.18.4 2.activemq架构 3.activemq集群配置 activemq集群配置基于Networks of Brokers 这种HA方案的优点:是占用的节点数更少(只需要2个节点),而且2个broker都可以响应消息的接收与发送。不足ÿ…...

大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...

《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...
ubuntu22.04 安装docker 和docker-compose
首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...

高考志愿填报管理系统---开发介绍
高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发,采用现代化的Web技术,为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## 📋 系统概述 ### 🎯 系统定…...