【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 为一个内边距 padding1emdiv 元素:

图 2.1 1em 内边距等同于当前字号
图 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 来设置 paddingheightwidthborder-radius 会非常方便,因为当元素继承了不同的字号,或者用户变更了字体设置,这些样式也会跟随当前元素均匀地缩放。

图 2.2 展示了两个不同大小的盒子,它们的字号、内边距及圆角半径都各不相同:

图 2.2 设置了相对大小的内边距和圆角半径
图 2.2 设置了相对大小的内边距和圆角半径会随字号的改变而同步缩放

为上述盒子定义样式时,可以用 em 指定其内边距及圆角半径,比如设为 1em;此时修改各元素的字号,这些属性就会随着字体一起缩放。

按以下代码更新 HTML 示例文件,并给元素分别添加样式类 box-smallbox-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 定义两种不同的字号
图 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 定义了其他属性,比如 paddingborder-radius(基于当前元素的字号)。当使用 em 给同一个元素同时设置字号和其他属性时,情况就变得复杂多了。此时,浏览器必须先计算字号,然后再利用算出的结果进一步算出其余属性的具体取值。这两类属性的声明值可能相同,但计算值却未必相等。

前面的示例中,带有 slogan 样式类的元素最终字号为 19.2px(=继承字号 16px × 1.2em)。如图 2.4 所示,元素还是 slogan 不变,只是内边距 padding 调大到 1.2em。背景设为灰色以便观察内边距的实际效果。可以看到内边距比字号还要偏大一些,尽管二者的声明值都相同。

图 2.4 em 定义的字号有别于同样用 em 定义的内边距
图 2.4 em 定义的字号有别于同样用 em 定义的内边距

这是因为段落标签从 body 元素继承了 16px 的字号,实际字号变为了 19.2px。此时 19.2px 即为该段落元素 1em 的最终大小,padding 的具体大小也是基于这个值进行计算的。相应的 CSS 代码如下所示,更新到示例页查看最终效果:

代码清单 2.4 使用 em 定义 font-sizepadding

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-sizepadding 的声明值相同,但计算值却不相等。

2 字体缩小的问题

em 用于设置具有多级嵌套结构的元素字体时,也会产生意想不到的结果。为了算出每个元素的具体大小,就得知道它们继承的字号是多少;如果父元素碰巧也是用 em 来定义的,就要看该父元素的继承值是多少,以此类推,一直沿着 DOM 树向上考察。

当使用 em 给列表元素定义字号、列表又嵌套了多级子列表时,问题很快就显现出来了。几乎每一位 Web 开发人员在职业生涯的某个阶段加载这样的页面都会碰到类似图 2.5 所示的情况。文字在逐级缩小!正是这样的问题让广大开发人员对 em 敬而远之。

图 2.5 字号设为 0.8em 导致嵌套列表中的文字逐级缩小
图 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.24px12.8px × 0.8),第三级则为 8.192px,依此类推。同理,如果各级字号大于 1em,实际字体大小会逐渐增大。而我们想要的效果是只设置最外层的字号,然后让里面的字体大小保持一致,如图 2.6 所示。

图 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/754775.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

复分析——第9章——椭圆函数导论(E.M. Stein R. Shakarchi)

第 9 章 椭圆函数导论 (An Introduction to Elliptic Functions) The form that Jacobi had given to the theory of elliptic functions was far from perfection; its flaws are obvious. At the base we find three fundamental functions sn, cn and dn. These functio…

一文解决图论中有向图、无向图、非负加权图的单源最短路径问题【超详细】【通用模板程序】【深入分析】【无需基础】【c++】

本文致力于提供一种解决图论中所有&#xff08;或绝大部分&#xff09;有向图、无向图、非负加权图的单源最短路径问题的通用程序模板&#xff0c;本文提供的模板并不是简单的可行模板&#xff0c;而是经过深入分析解释的一个较高质量和性能的通用程序模版。在每个关键变量存储…

JavaSE期末复习速成笔记

面向对象 1. 面向对象的概念 面向对象编程&#xff08;OOP&#xff09;是一种编程范式&#xff0c;它将现实世界的事物抽象为对象&#xff0c;通过类和对象来创建各种功能模块&#xff0c;以此来设计和开发软件。 2. 类与对象 类&#xff1a;是对象的模板&#xff0c;定义了…

Ros2学习中的话题通信-自定义接口消息:在VScode中不能补全的问题

在学习ros2的过程中&#xff0c;当学习到话题通信-自定义接口消息时&#xff0c;当消息的具体类型并未指定时&#xff0c;常见的操作是在base_interfaces_demo下创建msg文件夹及文件。同理&#xff0c;在动作通信等其他类型的通信中也需要这么做&#xff0c;只是创建的文件夹的…

KV260视觉AI套件--开箱报告

目录 1. 简介 2. 与 Zynq 的渊源 3. 官方的入门步骤 4. 总结 1. 简介 传统的ARMFPGA或DSPFPGA控制方案在软件、逻辑、硬件以及系统工程的协同调试中&#xff0c;往往需要团队成员之间严格按照预定计划和接口规范进行分工合作&#xff0c;这不仅增加了测试过程的复杂性&…

【ElementPlus源码】Container 布局容器

文章目录 index.tsContainerheaderutilswithInstallwithNoopInstall hooksuseNamespace 单元测试 看源码时候做的笔记。如有错误请指出&#xff01; 关于路径的省略&#xff0c;详见button&#xff1a;【ElementPlus源码】Button按钮-CSDN博客 index.ts 导入一堆组件&#xff…

Centos7配置支持ftp文件传输功能

报错信息 适用于不支持ftp协议的centos7的系统。 报错信息&#xff1a;An error occurred while executing the action Connect. Details: No connection could be made because the target machine actively refused it. 解决办法 安装及启动等命令 # 安装vsftpd sudo yum…

Spark SQL 的总体工作流程

Spark SQL 是 Apache Spark 的一个模块,它提供了处理结构化和半结构化数据的能力。通过 Spark SQL,用户可以使用 SQL 语言或 DataFrame API 来执行数据查询和分析。这个模块允许开发者将 SQL 查询与 Spark 的数据处理能力结合起来,实现高效、优化的数据处理。下面是 Spark S…

高级运维工程师讲述银河麒麟V10SP1服务器加固收回权限/tmp命令引起生产mysql数据库事故实战

高级运维工程师讲述银河麒麟V10SP1服务器加固收回权限/tmp命令引起生产MySql数据库事故实战 一、前言 作为运维工程师经常会对生产服务器进行安全漏洞加固&#xff0c;一般服务厂商、或者甲方信息安全中心提供一些安全的shell脚本&#xff0c;一般这种shell脚本都是收回权限&…

C++实现简化版Qt信号槽机制(2):增加内存安全保障

在上一篇文章中《C实现一个简单的Qt信号槽机制》&#xff0c;我们基于前面的反射代码实现了信号槽的功能。 但是上一篇的代码中没有对象生命周期管理的机制&#xff0c;如果在对象的生命周期结束后还存在未断开的信号和槽连接&#xff0c;那么信号触发时可能会尝试访问已经被析…

Redis 7.x 系列【11】数据类型之位图(Bitmap)

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Redis 版本 7.2.5 源码地址&#xff1a;https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. 概述2. 基本命令2.1 SETBIT2.2 GETBIT2.3 BITCOUNT2.4 BITPOS2.5 BITFIELD2.6 BITF…

【产品经理】订单处理10-分配快递策略

本次主要讲解下在订单处理过程中分配快递的策略以及分配快递中需要用到的设置。 一、建立快递档案 在ERP系统中&#xff0c;需要建立快递档案&#xff0c;设置所属快递、快递的服务类型、支持的打印模版以及快递在各个平台的电子面单支持情况。 二、仓库绑定快递 仓库需要设…

【动态规划】279.完全平方数

279. 完全平方数 难度&#xff1a;中等 力扣地址&#xff1a;https://leetcode.cn/problems/perfect-squares/ 没有刷过的小伙伴们请一定要先去刷一次&#xff0c;然后如果感兴趣的话再阅读以下内容&#xff0c;便于交流 ~ 多谢支持 ~ 问题描述 给你一个整数 n &#xff0c;返…

C# 入门—基本语法

一、数据类型 C# 语言中内置了一些基本的数据类型&#xff0c;数据类型用来指定程序中变量可以存储的数据的类型&#xff0c;C# 中的数据类型可以大致分为三类&#xff1a; 值类型&#xff08;Value types&#xff09;&#xff1b;引用类型&#xff08;References types&…

[推荐]有安全一点的网贷大数据信用查询网站吗?

在互联网金融日益发展的今天&#xff0c;网贷大数据查询网站成为了许多人申贷前的必备工具。随着使用这些网站的人群越来越多&#xff0c;安全问题也逐渐浮出水面。最近&#xff0c;就有许多用户反馈自己的个人信息在网贷大数据查询网站上被泄露。为了解决这一问题&#xff0c;…

Spring Cloud Gateway3.x自定义Spring Cloud Loadbalancer负载均衡策略以及实现动态负载均衡策略的方案

目录 前言 1.原理分析 1.1 ReactiveLoadBalancerClientFilter源码分析 1.2 LoadBalancerClientFactory源码分析 2.代码实现 2.1 扩展原生RoundRobinLoadBalancer轮询策略 2.1.1 自定义实现RoundRobinLoadBalancer 2.1.2 配置自定义的RoundRobinLoadBalan…

idea2024使用springboot3.x系列新建java项目,使用jdk17,启动项目报错

身为一名开发人员&#xff0c;敲代码无数&#xff0c;竟被一个小小启动给我卡了大半天&#xff0c;太丢脸了 报错一&#xff1a;Field infoSysRepository in com.erectile.Impl.PersonalInfoServiceImpl required a bean of type ‘com.erectile.jpa.repository.InfoSysReposit…

前端vue使用onlyoffice控件实现word在线编辑、预览(仅列出前端部分需要做的工作,不包含后端部分)

简介 ONLYOFFICE 文档 是一个开源办公套件&#xff0c;包括文本文档、电子表格、演示文稿和可填写表单的编辑器。 它提供以下功能&#xff1a; 创建、编辑和查看文本文档、电子表格、演示文稿和可填写表单&#xff1b; 与其他队友实时协作处理文件。 基于这个控件&#xff0c;…

微信小程序根据蓝牙RSSI信号强度测试设备距离

背景 在做小程序连接蓝牙设备的时候&#xff0c;有需求表明在搜索到0.5米之内的设备时自动连接 问题&#xff1a; 蓝牙模组只提供了RSSI信号强度&#xff0c;那又该如何计算蓝牙设备距离小程序的距离呢&#xff1f; 解决方案 通过以下公式做大量测试&#xff1a;求 A、n 的平均…

【深度学习】卷积神经网络CNN

李宏毅深度学习笔记 图像分类 图像可以描述为三维张量&#xff08;张量可以想成维度大于 2 的矩阵&#xff09;。一张图像是一个三维的张量&#xff0c;其中一维代表图像的宽&#xff0c;另外一维代表图像的高&#xff0c;还有一维代表图像的通道&#xff08;channel&#xff…