再看CSS长度单位使用,做到胸有成竹

2,539 阅读8分钟

前言

在日常的开发过程中,对长度单位的使用较为混乱。本瓜称之为“黑盒长度单位使用”。

涉及到网站需同时兼容 PC 和移动端情况更甚:px、百分比、em、rem、vw etc.

要历经样式修改和功能需求修改的反反复复,如果没有对CSS 长度单位做到成竹在胸,那么随着时间的增长,设置将越来越乱,要了老命嘞~

绝对单位和相对单位

CSS有多种表示长度的不同单位。

许多CSS属性有“length”值,例:width, margin, padding, font-size 等。

长度是一个数字,后跟一个长度单位,例如10px,2em等。

长度单位有两种:绝对单位和相对单位。

绝对单位

Absolute Lengths

W3C 对 Absolute Lengths 的解释:

The absolute length units are fixed and a length expressed in any of these will appear as exactly that size.

绝对长度单位是固定的,用任一一个单位的长度表示的大小将是固定的一个大小值。

Absolute length units are not recommended for use on screen, because screen sizes vary so much. However, they can be used if the output medium is known, such as for print layout.

不建议在屏幕上使用绝对长度单位,因为屏幕尺寸变化很大。但是,如果已知输出媒介,则可以使用它们,例如用于打印的布局。

绝对长度单位有以下这些:

Unit Description
cm centimeters 厘米
mm millimeters 毫米
in inches (1in = 96px = 2.54cm) 英尺
px * pixels (1px = 1/96th of 1in) 物理像素(设备像素)
pt points (1pt = 1/72 of 1in) 逻辑像素
pc picas (1pc = 12 pt) 派卡:印刷行业使用的长度单位
  • 像素(px)在不同的设备有不同表现。对于低 dpi 的设备,1px 是显示器的一个设备像素(点)。对于打印机或高分辨率 屏幕 1 像素表示多个设备像素。

相对单位

W3C 对 Relative length 的解释:

Relative length units specify a length relative to another length property. Relative length units scale better between different rendering medium.

相对长度单位指定相对于另一个长度属性的长度。相对长度单位在不同渲染介质之间缩放更好。

相对长度单位有以下这些:

Unit Description
em Relative to the font-size of the element (2em means 2 times the size of the current font) 相对于元素的字体大小
ex Relative to the x-height of the current font (rarely used) 相对于当前字体的 x 高度,很少用到
ch Relative to the width of the "0" (zero) 相对于“0”的宽度
rem Relative to font-size of the root element 相对于根元素的字体大小
vw Relative to 1% of the width of the viewport* 相对于视口宽度的1%
vh Relative to 1% of the height of the viewport* 相对于视口高度的1%
vmin Relative to 1% of viewport's* smaller dimension 当前vw和vh中较小的值的1%
vmax Relative to 1% of viewport's* larger dimension 当前vw和vh中较大的值的1%
% Relative to the parent element 相对于父元素

你真的了解 px 吗

自然界标准长度单位

每天基本上都和 px 打交道。那请问 px 有多长?

实际上,px 不是自然界的绝对长度单位。px 的长度大小在不同的设备分辨下是不同的,从这个意义上看 px 也是相对的。

但是如 pt 单位,大小为1/72英寸,是一个自然界标准的长度单位。

同样厘米、毫米、英寸都是自然界标准的长度单位。

来看以下两种情况,px 和自然界标准长度单位(这里是英寸)的关系以及清晰度的问题:

  1. 在相同的屏幕宽高下:如:15.6英寸(396.24毫米)的笔记本电脑:
类型 每单位 像素点个数
1920*xxx的分辨率 1毫米 1920/396.24=4.8个px
1366*xxx的分辨率 1毫米 1366/396.24=3.4个px

结论:前者更清晰

  1. 在相同的像素点下:如:1366*xxx的分辨率:
类型 每单位 长度
ipad pro(宽度305.7mm) 1px 305.7/1366 = 0.22(毫米)
笔记本(396.24mm) 1px 396.24/1366 = 0.29(毫米)

结论:一样清晰(ipad pro 用更小的宽度装了同样多的像素点)

肉眼看得清晰与否,跟屏幕实际尺寸的大小没有任何关系,而是跟单位长度的像素点有决定性的关系。 所以购买电脑时,15寸一定比13寸清晰是错误的。

在同等的自然界标准长度下的包含像素点越多,则越清晰。

设备像素和css像素

需要知道的是:我们通常编码的 px 指的是 css 像素而非设备像素:

  • 设备像素(device pixels):是指与硬件设备直接相关的像素,是真实的屏幕设备中的像素点。比如说,一个电脑显示器的参数中,最佳分辨率是1920x1080,那么指的就是这个显示器在屏幕上用于显示的实际像素点,也就是设备像素。

  • css像素(css pixels):css像素是指网页布局和样式定义所使用的像素,也就是说,css代码中的px,对应的就是css像素。

转换关系:在100%缩放比例下,1个css像素等于1个设备像素。

dpr

为什么移动端设计稿通常是 750px ?

这里所说的750px并不是绝对的,750px是iphone6的物理像素,也叫屏幕分辨率。也就是说这个手机被出厂造出来的时候,这个屏幕上有多少个像素点,他的物理像素就是多少;

但是我们在代码里写 width:375px,就能充满整个宽度。是因为 iphone6 的css像素(逻辑像素)是 375px。

dpr=物理像素/逻辑像素,iphone6 的dpr为2。

rem 不会是配角

rem 是毋庸置疑的主角,从它一出现,就注定不平凡,是实际开发和面试中出现的常客。

众所周知,rem 是相对根元素的单位,而 em 是相对父级元素的,前者减少了层级关系的换算,使计算更准确,方便我们使用。

具体如何设置呢?这里提供三种方法,按需取用。原理一致,一通百通。不懂原理,只是为了用而用,Duck 不必。

一、625法

通常情况下:因为各浏览器默认字体字号为 16px,即 16px 相当于 1rem ,设置如下:

html, body {
    font-size: 16px; /*default font-size equal 1 rem*/
}
h1 {
    font-size: 1rem; /*16px * 1 = 16px*/
}
h2 {
    font-size: .8rem; /*16px * 0.8 = 12.8px*/
}

但是显然,这样设置会造成换算的麻烦,因为要除以16。如何使得 1rem = 10px 呢? 我们可以定义 10px / 16px = 0.625 = 62.5% ,即浏览器的默认字体为 16px * 62.5% = 10px。

设置如下:

html, body {
    font-size: 62.5%; /* 10px / 16px = 62.5% 即 font-size 是 10px 相当于 1rem */
}
h1 {
    font-size: 1rem; /*10px * 1 = 10px*/
}
h2 {
    font-size: 1.2rem; /*10px * 1.2 = 12px*/
}
h2 {
    font-size: 1.4rem; /*10px * 1.4 = 14px*/
}

之后再媒体查询设置每个屏幕大小的根的 font-size 百分比,页面会根据设置的根 font-size 进行适配。

html{
	font-size: (clientWidth /  375) * 62.5%
}

优:有一定适用性,换算也较为简单。

劣:有兼容性问题,对不同手机适配不是非常精准;需要设置多个媒体查询来适应不同手机,单某款手机尺寸不在设置范围之内,会导致无法适配。

上述方法是通常解决方案,适用大多数情况,但仍有兼容性情况需要考虑。

如:chrome 强制字体最小值为 12px,低于 12px 按 12px 处理,那上面的 1rem=10px 就变成1rem=12px,就会出现偏差。

如何解决?十倍扩大百分比的设置即可。

设置应如下:

html, body {
    font-size: 625%; // 使得1rem =100px,减少偏差情况的出现
}

二、基准值法(考点)

假设设计师给的稿是 750 ,基于 ip6(dpr 为 2)。 则可以设置基准值为 100; 即 1rem=100px。那么整体屏幕就是 7.5 rem

css换算和这个基准值有关;页面动态font-size值 = 屏幕宽度 / 设计稿 rem 宽度

注:这里要考虑 dpr 这个变量,要先除掉。

// iphone6: 宽度为 375 px,公式:750/2/7.5=50

html{font-size:50px}

// iphone5:宽度为 320 px,公式:750/2/7.5=42.6667
html{font-size:42.6667px}

优:通过动态根font-size来做适配,基本无兼容性问题,适配较为精准,换算简便。

劣:无viewport缩放,且针对iPhone的Retina屏没有做适配,导致对一些手机的适配不是很到位。

三、flexible 法(推荐)

这是手淘解决方案amfe/lib-flexible

拿到设计稿除以10,得到font-size值。

假设拿到的设计稿也是750,Flexible会把设计稿分为10份,可以理解为整个屏幕就是 10 rem,即1rem=75px,所以根的font-size=75px。

引入 flexible.js

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<script src="./node_modules/amfe-flexible/index.js"></script>

页面不用再设定 。Flexible会自动设定每个屏幕宽度的根font-size、动态viewport、针对Retina屏做的dpr。

优:通过动态根font-size、viewpor、dpr来做适配,无兼容性问题,适配精准(动态计算 viewport 和针对 iphone 手机的 dpr 缩放调整,使得页面适配更加精确)。

劣:需要根据设计稿进行基准值换算,在不使用sublime text编辑器插件开发时,单位计算复杂。

小结

举例来说,移动端通常给的设计稿是750px,以 iphone6 为基准,iphone 6是 375px 乘以 2,这个 2 是dpr,也就是我们通常说的 2 倍屏(物理像素/css像素)。我们设定设计稿宽度为X rem,再倒推根元素设置的 font-size 应该是多大即可,然后根据不同的设备设置等比的根的 font-size。flexible.js 相当于帮你做了更详细的换算设定。

参考