大禹记。

首页 / 笔记 / 正文

px / rem / em / % 到底怎么选

同一个数值换个单位,结果就不同,差别全在「相对谁」。先查表,再看几处我常记错的细节。

单位相对谁什么时候用一个坑
px设备像素,绝对值边框、圆角、阴影偏移这类不该跟着缩的用成正文尺寸会顶掉浏览器放大字号
rem根元素的字号正文和标题的字号、常见间距根字号被写死,全站比例跟着变形
em当前元素自己的字号组件内部的间距,跟着组件字号缩嵌套时逐层相乘,第三层就失控
%看属性,不固定容器宽度、栅格分栏上下 padding 也按宽度算
vw / vh / dvh视口尺寸整屏高度、跟着窗口缩放的装饰移动端地址栏一收一放,vh 会跳
ch字体里数字 0 的宽度限制一行长度换字体就变,中文场景不精确
fr网格容器里剩余的空白grid-template-columns 的分栏只能当轨道用,写成 width 直接无效

% 的参考对象跟着属性变

  • width 的 %:相对包含块的内容宽度。
  • height 的 %:相对包含块高度;它是 auto 时这条声明直接失效。
  • padding 和 margin 的 %:四个方向全部相对包含块的宽度,这是最常见的意外,我撑固定比例的占位块靠的就是它。
  • font-size 的 %:相对父元素字号,会继承着往下乘。
  • line-height 的 %:相对自身字号。
  • translate 的 %:相对盒子自身尺寸。

em 连乘与 line-height 不带单位

.box   { font-size: 1.2em; }   /* 相对父元素:1.2 倍 */
.box p { font-size: 1.2em; }   /* 相对 .box:实际 1.44 倍
                                 * 再往里嵌一层就是 1.728 倍 */

字号链路我一律用 rem,em 只留在组件内部的间距上,改一处字号其余自动跟上。line-height 固定写不带单位的数,比如 1.6;写成 160% 会被子元素继承成已经算好的像素值,标题的行高就不跟字号放大了。

rem 依赖根字号,缩放交给媒体查询

根元素的 font-size 若也写 rem,参照的是浏览器默认字号而不是它自己,所以我在 html 上只写百分数,往下一律用 rem。小屏要整体缩,只改这一处:

html {
  font-size: 100%;          /* 跟随用户在浏览器里设的字号 */
}

@media (max-width: 640px) {
  html {
    font-size: 93.75%;      /* 约 15px,全站 rem 一起缩小 */
  }
}

body {
  font-size: 1rem;
  line-height: 1.8;         /* 无单位,跟着各自字号走 */
  max-width: 65ch;          /* 一行大约 65 个半角字符 */
  padding: 0 1.25rem;
}

.card {
  width: 50%;               /* 相对包含块的内容宽度 */
  padding: 8%;              /* 上下这 8% 也按包含块宽度算 */
  font-size: 0.95rem;       /* 这里不用 em,避免嵌套连乘 */
}

vh 在手机上会跳

手机浏览器的地址栏会伸缩,视口高度跟着变,各家对 vh 取最小还是最大视口口径不一,写 100vh 时底部常被吃掉一截。真要铺满我用 dvh,它跟着当前视口实时变;不想抖就用 svh。另外滚动条算在 vw 里,桌面端 width: 100vw 容易顶出横向滚动条,我不拿它当容器宽度。

我自己的三条习惯

  • 字号只用 rem,组件内间距用 em,边框和圆角用 px。
  • 一行长度交给 ch,宽度交给 % 和 fr,不拿 vw 当容器宽度。
  • 整屏高度默认不写 vh,要写就用 dvh 加一个 min-height 兜底。