作者 | Brilliant Open Web团队
自从进入移动互联网时代,响应式布局这个词经常出现在 Web 设计和开发领域,响应式网页设计的理念是让 Web 页面在不同尺寸的设备上和窗口上都能得到友好的渲染,以获得良好的浏览体验。响应式布局可自动调整并适应任何设备屏幕的大小,无论是 PC,平板电脑还是手机。
在学习响应式布局之前,需要先了解一些基础知识,只有对它们有一定的了解,才能在实现的时候选取合适的技术方案。
响应式布局设计通常可以采用“流体”设计、网格布局、弹性布局和 Media Query 等方式来实现。那么,我们就从基础的“流体”设计的概念开始,循序渐进的走进响应式布局。
“流体”设计的概念要求页面元素大小采用相对单位,而不是px这样的绝对单位。有哪些相对单位可以使用?在特定场景下,采用哪种相对单位最合适?让我们先来了解一下这些在 Web 开发中常见的单位。
绝对单位 —px
你真的了解px吗?为什么 iPhone X 手机标注的分辨率是 1125×2436,而开发中却以 375px 为整个页面的设计宽度呢?
px
像素一般指 PC 或者手机屏幕上的光点,常见的描述中 iPhone X 的分辨率 1125×2436,一般指的是在屏幕长和宽上像素点的个数,对应设备的物理分辨率。而在 Web 开发中,经常提到 iPhone X 的分辨率是 375×812,又是怎么回事呢?这里需要提到设备像素(Device Pixels)和虚拟像素–也可以叫 CSS 像素(CSS Pixels)或者逻辑像素(后面统一使用 CSS 像素这个称呼),虚拟像素在 Android 开发中又被叫做设备无关像素(Device Independent Pixel,简写 dip)。设备像素很好理解,对应屏幕上光点的数量,即设备的物理分辨率。而 CSS 像素则对应了设备的逻辑分辨率。
科技发展到今天,屏幕的物理分辨率已经达到人眼无法区分单个像素的程度,人眼无法在 iPhone X 宽不到 7cm 的屏幕上数出 1125 个像素点。Web 开发人员眼中的 1px 可能对应多个设备像素,这个 “1px” 指的就是 CSS 像素,对应的是设备的逻辑分辨率(Peter-Paul Koch 在他的博文《A pixel is not a pixel is not a pixel》中有详细的讲解:https://www.quirksmode.org/blog/archives/2010/04/a_pixel_is_not.html)。
比如在 iPhone X 上,设备像素是 1125×2436,而 CSS 像素(逻辑像素)是 375×812,那么一个 CSS 像素对应的是长和宽各 3 个设备物理像素,共 9 个设备物理像素点。
1 css pixel = 3 x 3 device pixels
这个比值 3 就是平时所说的设备像素比(Device Pixel Ratio),简称为 DPR。DPR 不是一个单位,而是一个比值,这个比值可以在浏览器中通过 window.devicePixelRatio获取。
// 设备像素比,在 iPhone X 中等于 3,在 iPhone 6 中等于 2window.devicePixelRatio
所以, Web 开发中使用的px,比如height = 1px,实际指的是设备的 CSS 像素,并不是屏幕上真实的光点数,1px 具体对应屏幕上的多少光点,还取决于设备的 DPR。比如,1px 在 iPhone X 上对应 3×3 个屏幕上的光点,而在 iPhone 6 上就对应了 2×2 个屏幕光点。
通过上面的分析我们知道了px单位的来历,当使用了px为单位,元素的大小就会按照 CSS 像素和 DPR 渲染在屏幕上。但是像电脑和手机这样不同的设备,它们的 CSS 像素是不同的,如果用px设定了同样的大小,就会导致在电脑上显示正常的字体在手机上特别小。怎么解决这个问题相信你已经有答案了,就是相对单位,那么相对单位有哪些,它们之间的区别又是什么呢?
字体相对单位 —EM,REM
提到相对单位,最熟悉最常见的就是em和rem。什么时候应该使用em,什么时候使用rem呢?
EM
em是元素相对于自身的 font-size,它不像px是固定的单位,因此很适合用来做响应式布局。
<style> h1 { font-size: 20px; margin: 1em; /* 1em = 20px */ } p { font-size: 14px; padding: 1em; /* 1em = 14px */ } .outer { font-size: 12px; } .inner { font-size: 2em; padding: 1em; /* 1em = 24px */ } </style><div class="outer"> <div class="inner"></div></div>
看一下运行效果:
-
h1 元素的font-size是 20px,所以它的 margin = 1em = 20px,如图所示:
-
p 元素的font-size 是 14px,所以它的 padding = 1em = 14px,如图所示:
-
inner div 的 font-size是 2em,没有设置具体,em会从继承父元素的字体大小,也就是 outer div 的 12px,所以inner div 的 font-size是 2em = 2*12px = 24px,所以它的 padding = 1em = 它的 font-size = 24px,如图所示:
如果当前元素没有设置 font-size,那 1em 实际大小是多少?
p {
padding: 1em; /* 1em 等于多少像素 */
}
在上面的代码中没有设置<p>的font-size,它会从继承父元素的字体大小,如果父元素也没有设置字体大小,会一直找到根元素<html>,而<html>元素的默认font-size一般是 16px。有的元素有默认的字体大小,比如<h1>的font-size默认等于 2em,最终计算还是会追溯到最外层。
<html>
<head></head>
<body>
<p>1em = 16px</p>
</body>
</html>
REM
rem= root em,顾名思义就是相对于根元素的em,是根据根元素来计算出 CSS 像素点的大小。根元素就是<html>,而它的默认字体大小是 16px。
h1 { font-size: 20px; margin: 1rem; /* 1rem = 16px */}p { font-size: 1rem; /* 1rem = 16px */}
所以,如果我们改变根元素的字体大小,页面上所有使用rem的元素都会被重新计算元素属性并重绘。
EMvsREM
em和rem都是相对单位,两者都可以用来做响应式布局的单位。根据它们的特性,em和rem互有优劣。
- em– 对于模块化的页面元素比较好,比如 Web Components 标签,标签内的元素都根据父元素计算像素大小,只需设置最外层父元素的字体大小就可同时影响子元素,保持自定义元素具有一定的模块封闭性。但em比较难以追溯,需要逐层向上排查显式设置了字体大小的元素。
- rem– 方便是rem最大的好处,只需知道<html>的字体大小即可计算当前的实际像素大小。
有些开发者全部都用rem,有些开发者全部用em,这其实都是不合理的用法,开发者应该视不同情况采用不同的单位。但在现在的环境下,rem使用的更广泛一些。开发者根据设计师提供的 UE 图进行开发时,测量出来的大小单位一般是像素,如果需要转换为rem,可以采用 PostCSS 的插件postcss-px2rem自动转换为rem单位。通过上·述分析,我们已经了解了em和rem的基本原理。但是,它们或者是相对于自身的font-size,或者是相对于 html 根元素的font-size,一旦设置指定的值,元素在 PC 端或者手机端都会按照指定的大小进行渲染,当浏览器视口尺寸发生变化时元素大小并不会随之改变。随着技术的发展,元素根据视口的变化而实时调整大小的解决方案被提出,这就是视口单位。CSS3 把视口单位新增了进来,比如vw、vh、vmin和vmax。和上述em和rem相比,它们具有根据视口调节大小的优势,由于早期浏览器对视口单位的支持不全面,很多开发者没有选择使用视口单位。但是从现在来看,各主流浏览器的支持已经非常友好了,开发者也可以根据需求使用起来了。
那么应该怎样使用它们?视口单位的计算原理又是什么呢?
视口相对单位 —vh,vw,vmin,vmax
视口是相对于浏览器上的可视区域来说的,视口单位计算中涉及的视口都是包含滚动条的。视口单位是相对于浏览器的视口进行计算的。
使用视口单位的优势是:一方面,当发生页面加载、缩放或手机横屏等触发视口尺寸变化的事件时,对于使用视口单位的元素,浏览器可以自动重新计算改变后的尺寸,去做相应的渲染。另一方面,使用视口单位会使浏览器根据不同设备的视口大小去渲染元素,从而减少不必要的媒体查询(媒体查询将在后续文章中介绍)。当前 CSS 中的视口单位有 4 种,分别是vh,vw,vmin和vmax。先来看vh,vw这两个基本的视口单位。
vh,vw
vh和vw都是相对于视口 viewport 进行计算的单位。
- vw– viewport width,视口宽度,1vw = 1% 视口宽度
- vh– viewport height,视口高度,1vh = 1% 视口高度
vw和vh的逻辑比较简单,100vw = 100% 视口宽度。下面的代码演示如何在 iPhone X 上计算vw的实际 CSS 像素大小,vh的计算方法和vw一样。
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
p {
width: 50vw; /* 1vw = 1 / 100 * 375px = 3.75px */
}
</style>
</head>
<body>
<p>50vw = 50% viewport width = 50% * 375px = 187.5px</p>
</body>
</html>
vw, vhvs%
现在我们知道 1vw = 1% 视口宽度,那么它们是不是等价呢?来看下面的代码,同样还是以 iPhone X 为例。
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.p1 {
width: 50vw; /* 1vw = 1 / 100 * 375px = 3.75px */
}
.outer {
width: 80vw;
}
.p2 {
width: 50%;
}
</style>
</head>
<body>
<p class="p1">50vw = 187.5px</p>
<section class="outer">
<p class="p2">50% = 150px</p>
</section>
</body>
</html>
在浏览器中运行上面的代码,发现第二个<p>标签的实际宽度为 150px,不是 187.5px。其实原理非常简单,就和em和rem一样,百分比是相对于父元素的宽度来计算,而vw根据视口的宽度来计算。所以再回顾上面的例子中的第二个<p>标签,.outer元素的宽度为 80vw = 300px,那么其子<p>标签的宽度为 300px * 50% = 150px。
vh,vw有没有问题呢?
vh、vw基于视口的特性决定了它们对视口很敏感,有些时候这反而成了问题。比如,当我们像下面这样把字体设置为3vw,在 CSS 像素为 320px 的手机上字体被渲染成 10px,你会发现它有些小,而在分辨率为 2560px 的 PC 上字体被渲染成 77px 又会显得太大了。
.px-container {
font-size: 3vw
}
解决方法就是:使用 CSS 的calc()为字体设置一个最小值,同时对 viewport 设置比较小的系数:
.px-container { font-size: calc(18px + 0.25vw)}
这样即使在分辨率小的屏幕上字体依然至少可以被渲染成 18px 的大小,同时设置了比较小的vw系数值,这就避免了在分辨率高的 PC 端字体被渲染得很大的问题。
vmin,vmax
vmin和vmax也是相对于视口 viewport 进行计算的单位。了解了vh和vw之后,vmin和vmax就变得很简单了。
- vmin: 取vw和vh中的较小值
- vmax: 取vw和vh中的较大值
有了vh,vw,为什么还需要vmin,vmax?
在进行移动端开发时,当用户把屏幕横过来,那么谁是vh,谁是vw呢?
横过来之后手机的 “高” 成了vw,“宽” 成了vh,这就会造成:如果使用vw、wh设置字体大小(比如 5vw),在竖屏和横屏状态下显示的字体大小会像上图中那样差别非常大。而vmin和vmax是根据vw和vh大小进行实时取值,就可以避免横屏出现的这种状况,从而使得文字大小在横竖屏下保持一致。
其他单位
Web 开发中还有很多其他的单位。
如绝对单位中的in(英尺),mm(毫米),cm(厘米),这些是来自自然生活的单位,而pt(磅),pc(派卡)则是来自印刷界的单位,有排版方面的历史原因。它们往往与输出媒介相关(媒介是屏幕还是纸张)。绝对单位之间的换算关系是: 1in = 2.54cm = 25.4mm = 72pt = 6pc 。如果打印一段字体大小为 12pt 的文字,那么无论你在什么显示屏上显示,无论显示效果如何,打印到纸上的字体都是一样的 1/6 英寸大小(1pt=1/72英寸)。注意这里是当媒介是纸张的时候。如果媒介是显示屏,并不是说你写了一个大小为 12pt 的字在屏幕上,它的物理长度就是 1/6 英寸,具体显示还与屏幕的分辨率相关。举个例子,比如你的电脑屏幕分辨率是 800px * 600px,根据勾股定理,对角线就是 1000px,如果你的屏幕物理尺寸是 20 英寸,那么每英寸就是 50px,又因为 1pt = 1/72英寸,所以在这块屏幕上,12pt = 12 * 1/72 * 50,大约为 8px,在其他不同尺寸和分辨率的屏幕上显示又不相同。这里仅仅是举个例子,开发者明白原因即可,这些单位在日常 Web 开发中并不推荐使用。
相对单位还有ex和ch。ex是相对于元素字符集的x-height,也就是当前字符集里字符 x(小写) 的高度,ch则是相对于当前字符集里字符 0 的宽度。它们与em / rem的区别是,当改变字符集 font-family 的时候,使用em / rem单位的元素大小不会受到影响,而对于使用ex的元素,浏览器会根据字符集重新计算字体大小。
尽管上述单位在使用上没有界限,但是一般来说,我们会根据不同的媒介选择不同的单位:
媒介 | 推荐 | 偶尔使用 | 不推荐 |
屏幕 | vh, vw, vmin, vmax, em, rem, % , px | ex | pt, cm, mm, in, pc |
打印 | cm, mm, in, pt, pc, %, px | px, ex | – |
可见,在 Web 开发中in,mm,cm, pt,pc,ex和ch等这些单位使用的都不多,开发者仅作了解就可以。
总结
通过上面的分析,我们了解了 Web 开发中一些常用的绝对单位和相对单位。相对单位的使用是响应式布局的开始,也是响应式布局中不可缺少的一部分。通过这些相对单位的使用可以做到简单的、元素大小方面的响应式,避免一些由“大小”引起的设备差别。但是这还远远不够,元素布局、与不同设备的兼容更是实现响应式设计必须面对的问题。这就涉及到布局方面的响应式设计(比如弹性布局)和媒体查询(比如图片的响应式设计)等,只有将这些响应式布局的内容都融会贯通后才能实现优秀的响应式布局设计。后续文章会带大家进一步走进响应式布局,了解更多的响应式布局设计和优秀实践。
未经允许不得转载:大自然的搬运工 » 响应式布局基础篇 – 你了解这些长度单位吗?