跳到主要内容

CSS 响应式方案

“响应式”——在 CSS 中指的是样式能够根据浏览器窗口的大小有不同的“响应”。比如在手机、pc、平板设备等任意尺寸下都可以很好的展示出网页内容。

利用 rem 和 media query

  1. media-query:根据不同的屏幕宽度,设置根元素的 font-size 属性;
  2. rem:基于根元素的相对单位计算出子元素的大小;

比如:

@media only screen and (max-with: 374px) {
/* iPhone5 或者更小的尺寸,以 iPhone5 的宽度(320px)比例设置 font-size */
html { font-size: 86px; }
}

@media only screen and (min-with: 375px) and (max-width: 413px) {
/* iPhone6/7/8 和 iPhoneX */
html { font-size: 100px; }
}

@media only screen and (min-with: 414px) {
/* iPhone6pro 或者更大的尺寸,以 iPhone6pro 的宽度(414px)比例设置 font-size */
html { font-size: 110px; }
}

我们以 100px/375px 为基准,如果是 iPhone5 或者更小的尺寸(320px),根据比例:375px/320px ≈ 100px/86px

同样,414px 以上对应的字体大小也能根据比例算出来:(414px/375px) * 100px ≈ 110px

然后设置基准字体大小:

body {
font-size: 0.16px;
}

当屏幕宽度在 [375px, 413px] 区间时,默认的字体大小将是 16px(110px * 0.16rem),当大于等于 414px 时,默认字体大小将是 17.6px

rem 和 em 的不同

  1. 1em 等于当前元素的字号,如果当前元素没有设置字号,则继承父级元素的字号;
  2. 1rem 等于根元素的字号,只相对于根元素(html元素);

如果元素的字体大小都用 1em 表示,你会发现内层的元素字体会变得越来越小,这是因为 em 是相对当前元素的字体大小,但当前元素的字体大小又来自于上级元素,因此里层的元素字体会越来越小。

通常可以按这个策略设置尺寸:

rem 设置字号;用 px 设置边框;用 em 设置其他大部分属性,尤其是内边距(padding)、外边距(margin)和圆角(border-radius),或者用百分比设置容器宽度。这样字号是可预测的,同时还能在其他因素改变字号时,借助 em 缩放内外边距。

设置一个合理的默认字号

如果你希望默认字号为 14px,那么不要将默认字体设置为 10px 然后再覆盖一遍,而应该直接将根元素字号设置为想要的值。将想要的值除以继承值(在这种情况下为浏览器默认值)是 14/16 = 0.875

:root {
font-size: 0.875em;
}

设备屏幕:

/* 作用到所有屏幕,但是在大屏上会被覆盖 */
:root {
font-size: 0.75em;
}

/* 仅在宽度 800px 及其以上的屏幕,覆盖之前的值 */
@media (min-width: 800px) {
:root {
font-size: 0.875em;
}
}

/* 仅作用到宽度 1200px 及其以上的屏幕,覆盖前面的两个值 */
@media (min-width: 1200px) {
:root {
font-size: 1em;
}
}

使用 vw 定义字号

如果给一个元素加上 font-size: 2vw 会发生什么?

在一个 1200px 的桌面显示器上,计算值为 24px(1200 * 2%),在一个 768px 的平板上计算值为 15px(768 * 2%),这样做的好处是元素能够在这两种大小之间平滑的过渡,这意味着不会在某个断点突然改变。当视口大小改变时,元素会逐渐过渡。

不幸的是,24px在大屏上来说太大了,在 iPhone6 上会缩小到只有 7.5px。

如果能够保留这种缩放的能力,但是让极端情况缓和一些就更棒了,CSS 中的 calc() 函数可以提供帮助。

:root {
font-size: calc(0.5em + 1vw);
}

@media (min-width: 50em) {
/* 超过最大断点时,字号不再增加 */
:root {
font-size: 1.125em;
}
}

上面代码中,0.5em 保证了最小字号,1vw 则确保了字体会随着窗口缩放。在 iPhone6 里的 11.75px(0.5 * 16 + 375 * 0.01)一直过渡到 1200px 的浏览器窗口里的 20px,可以按照自己的喜好调整这个值。

移动优先

响应式设计的第一原则是移动优先,顾名思义就是构建桌面版之前要先构建移动端布局,这样才能确保两个版本都生效。

移动优先的方式会让你设计网站的时候就一直思考着这些限制:屏幕空间受限、网络变慢、更用户交互方式(没有鼠标)也不一样。一旦移动版的体验做好了,就可以用“渐进增强”的方式为大屏用户增加体验。

给视口添加 viewport meta 标签

这个 HTML 标签用于告诉移动设备,你已经特意将网页适配了小屏设备,如果不加这个标签,移动浏览器会假定网页不是响应式的,并且会尝试模拟桌面浏览器。

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>

meta 标签的 content 属性里包含两个选项。首先,它告诉浏览器当解析 CSS 时将设备的宽度作为假定宽度,而不是一个全屏的桌面浏览器的宽度。其次当页面加载时,它使用 initial-scale 将缩放比设置为 100%。

这些选项还可以设置为其他值,但以上配置应该最能满足实际需求。

此外 content 属性还可以设置第三个选项 user-scalable=no,阻止用户在移动设备上用两个手指缩放。

媒体查询

媒体查询除了 and 关键字联合起来之外,如果设备只需要满足多个条件之一,可以用逗号分割,例如:

/* 当查询匹配小于等于 20em 的视口,以及大于等于 35em 的视口 */
@media (max-width: 20em), (min-with: 35em) {}

媒体类型(media type)描述设备的一般类别。除非使用 not 或 only 逻辑运算符,否则媒体类型是可选的,并且会(隐式地)应用 all 类型(适用于所有设备,比如 screen、print)。

详细可以查看 MDN 文档:使用媒体查询

响应模式案例:Responsive Patterns

流式布局

流式布局,有时也被称作液体布局。指的是使用的容器随视口的变化而变化。它跟固定布局相反,固定容器(比如设定了 width: 800px 的元素)在小屏幕上会超出视口范围,导致需要出现水平滚动条,而流式布局会自动缩小以适视口。

流式布局中,主页面容器通常不会有明确的宽度,也不会给百分比宽度,但可能会设置左右内边距,或者设置左右内边距为 auto,让其与视口边缘之间产生留白。也就是说容器可能比视口略窄,但永远不会比视口宽。

在主容器中,任何列都会百分比来定义宽度(比如主列宽70%,侧边栏30%)。这样无论屏幕是多少都能放得下主容器。

响应式图片

响应式图片的最佳实践是为一个图片创建不同分辨率的副本。如果用媒体查询能知道屏幕大小,就不必发送过大的图片,不然浏览器为了适配图片也会将其缩小。

通过媒体查询可以在不同屏幕下设置对应的 backgroundImage。但如果图片是用的 <img /> 标签加载的又该怎么办呢?一个重要的解决办法是 srcset 属性("source set" 的缩写)。

<img
alt=""
src="beans-small.png"
srcset="beans-small.png 560w,
beans-medium.png 800w,
beans.png 1280w"
/>

这种方式允许针对不同的屏幕尺寸优化图片,更棒的是,浏览器会针对高分辨率的屏幕做出调整。如果设备的屏幕像素密度是 2 倍(通常意味着着在每英寸的空间内,有两个物理像素),浏览器就会相应的加载更改分辨率的图片。

大部分浏览器都支持 srcset 属性,不支持的也会根据 src 属性加载相应的 URL。

MDN 相关文档:HTMLImageElement.srcset

图片作为流式布局的一部分,请始终确保它不会超过容器的宽度,为了避免这种情况发生,一劳永逸的办法是在样式表中加入 img { max-width: 100%; }。

设备的屏幕像素密度是指每英寸(inch)上显示的物理像素数量。高像素密度通常用于提供更清晰和更细致的图像,特别是在小型设备,如智能手机和平板电脑上。例如,如果一个设备的分辨率是200x200像素,而屏幕物理尺寸是2英寸,那么它的像素密度就是每英寸100像素(200像素 / 2英寸 = 100像素/英寸),如果是2倍像素密度,那么每英寸就有200物理像素(每英寸100像素 * 2倍像素密度 = 200像素/英寸)。

处理表格

在移动设备的流式布局里,表格的问题特别多,如果表格的列太多,很容易超出屏幕宽度。

处理方式可以将表格强制显示为一个普通的块级元素。

@media (max-width: 30em) {
/* 强制转成块级 */
table, thead, tbody, tr, th, td {
display: block;
}

/* 标头移动到屏幕外,将其隐藏 */
thead tr {
position: absolute;
top: -999999px;
left: -999999px;
}

/* 表格数据的每个之间加上间隔 */
tr {
margin-bottom: 1em;
}
}

显示效果如下。

table 响应式

最后

网页响应式设计的结构实现方式千变万化,最终这些方式都会归纳为三大原则:移动优先、媒体查询、流式布局。

  • 优先实现移动端设计;
  • 使用媒体查询,按照视口从小到大的顺序渐进增强网页;
  • 使用流式布局适应任意浏览器尺寸;
  • 使用响应式图片适应移动端设备的带宽限制;
  • 不要忘记给视口添加 meta 标签;