11.8 CSS 响应式技术(responsiveness)

页面自适应多种用户终端

Web是用来通过互联网分享信息的,从早期的电脑,发展到现在形形色色的移动智能终端,都需要能浏览这些信息。这给网页设计和技术实现在适配各种屏幕尺寸(分辨率)上提出了很大的挑战。

移动设备通常要比电脑的屏幕小很多,一套以电脑分辨率和视觉效果为蓝本的设计,显然不能满足要求。那么我们该怎么处理移动端的展示呢?通常我们有3种选择:

  1. 让用户自己调整页面大小和位置来阅读网页的不同部分乃至屏幕外的部分。
  2. 创建一个单独的移动网站,比如像 m.baidu.com,然后检测用户代理并把移动端阅读重定向到这个独立网站。
  3. 使用响应式网页设计(responsive web design),也就是本章要介绍的内容。

设备(Device),浏览器(browser),视口(viewport)

我们首先定义几个关键术语:

device
用来上网的信息终端:智能手机,平板,电脑或笔记本。
browser
运行在终端上显示网页的软件:Firefox, Google Chrome, Safari, Internet Explorer以及Microsoft Edge。
viewport
浏览器中用来显示网页的实际区域。

Difference between a device, a browser, and a viewport

响应式网页设计(Responsive web design)

响应式网页设计的设想是让网站能够自适应各种设备,为用户提供一致而流畅的用户体验。在具体实现上,它首先需要定位出不同的设备,然后针对不同的设备应用各自的样式。有一部分样式在不同设备之间可以共享,而有一部分样式则是某种设备所独有的。

响应式技术依赖于设备或视口的属性,比如:

  • viewport的宽高
  • viewport的方向
  • 设备的分辨率

针对这些不同的属性组合,响应式技术给网页应用不同的、或额外的CSS规则。

踏得网搜索主站和本教程页面都使用了响应式设计,不同的设备将呈现不同的布局和样式以获取更好的用户阅读体验。

媒体查询(media queries)

我们在前述的CSS优先级章节已经提及媒体类型(media type)和媒体查询(media query)的概念。

media type的引入有多种可选方式。

使用link标签

  <link href="css/print.css" rel="stylesheet" type="text/css" media="print" />

在样式文件或head的style块中通过@import调用别一个样式文件

 @import url("css/print.css") print;

在样式文件或head的style块中通过@media定义CSS样式

 @media screen{
    选择器{
     属性:属性值;
    }
  }

上述语句中的media属性,就是用来指定特定的media type,如屏幕(screen)和打印(print)的样式表,当然还有其他的,比如说“TV”,“handheld”等,其中“all”表示的是支持所有媒体介质。

media type由CSS2引入,而CSS3中的media query是对media type功能的增强,我们可以把media query看作是(media type+查询条件),如果媒体符合相应的条件,那么就会调用对应的样式表或应用对应的样式。

media query的语法看起来和动画@keyframes语法有些类似,它们都在一个CSS规则块(定义作用范围)中内置其它CSS规则(用来定义该约定范围内的具体样式)。

/* 默认字体,用于所有viewport */
body{ font-size: 14px;}

@media (min-width: 1200px) {
  /* 这部分代码只在viewports大于1200px时被读取 */
  body{ font-size: 16px;}
}

这里,默认字体是 14px。但是为了适应大尺寸屏幕,当viewport大于1200像素时,文本字体被设置为 16px

记住我们讨论的是 viewport,而不是设备。

我们可以通过调整桌面浏览器的窗口大小来查看media query条件被激活或失效的情况。

支持多种条件

你可以在media query中包含多个查询条件。

body{ font-size: 18px;}

@media (min-width: 1000px) and (orientation: landscape) {
  body{ font-size: 20px;}
}

字体将只在满足以下两个条件时被设置为20px:1.viewport不小于1000px宽;2.设备处于横屏(landscape) 模式(与之相对的是竖屏portrait模式)。

我们还可以使用 notonly。它们被称为逻辑操作符(logical operators)

支持多个CSS规则

我们可以在media query中添加多个CSS规则

body{ font-size: 14px;}
.button{ display: block;}
.title{ text-align: center;}

@media (min-width: 1200px) {
  body{ font-size: 16px;}
  .container{ margin: 0 auto; width: 960px;}
  .button{ display: inline-block;}
  .title{ text-align: left;}
}

条件参数(Parameters)

如上面的示例代码所示,media query的参数其实就是用来设置样式被激活的限定条件

宽度(width)

width 是响应式Web设计中最常用的参数。在本节开始部分的viewport概念介绍中,我们提到过默认viewport往往会导致浏览器出现水平滚动条,阅读体验不好。这归因于我们对于文章的整体阅读习惯是由上而下方向的,通过页面向下滚动我们可以阅读更多的内容。我们通常不在水平方向上滚动(尤其是阅读文章时。图片轮播或幻灯片除外)。

这在阅读体验上就要求内容能够自动匹配可用viewport宽度。 media query允许检测这个宽度,然后在viewport大于(min-width)或者小于(max-width) 某个数值时应用不同的样式。

  • min-width(960px): 样式仅当viewport大于960px时被应用
  • max-width(768px): 样式仅当viewport小于768px时被应用

宽度单位可以使用像素(pixel)emrem。理论上你也可以使用绝对单位如cm或inch,但浏览器支持很有限,所以不可靠。

每当viewport发生变化时,浏览器检查CSS中所有的媒体查询语句,检查条件参数,然后匹配当前viewport值,应用相应的样式。

高度(height)

height参数和width类似,用来设定viewport的高度查询条件。

我们一样可以使用min-heightmax-height

由于网页通常是竖向滚动的,很少需要去适配更短的viewport,因此这个参数很少被使用。

方向(orientation)

orientation参数用来查询viewport是否处于以下两种模式之中:

  • 横屏(landscape): viewport的宽度大于高度
  • 竖屏(portrait): viewport的高度大于宽度
@media (orientation: portrait) {
  /* 用于竖屏viewports */
}

@media (orientation: landscape) {
  /* 用于横屏viewports */
}

竖屏模式通常用于平板或智能手机。

在移动设备上,即使你的设备处于竖屏模式,但是当键盘被触发显示时,viewport有可能被视作横屏而发生模式切换,因为屏幕高度变小了。

分辨率(resolution)

分辨率是屏幕关键的显示性能指标,是指显示器所能显示的像素的多少。由于屏幕上的点、线和面都是由像素组成的,显示器可显示的像素越多,画面就越丰富细致,同样的屏幕区域内能显示的信息也越多。

分辨率依赖于两个因素,即设备像素密度(pixel density)和屏幕尺寸,其中像素密度可以表示为每英寸点数(dots per inch)dpi 或每厘米点数(dots per centimeter)dpcm

屏幕分辨率取值通常以宽乘以高的形式表示,如1440x900,表示屏幕宽度上能显示1440个像素,高度上能显示900个像素。

像素密度和显示的精细度有关(dpi越高,显示越精细)。

@media (min-resolution: 300dpi) {
  /* */
}

桌面屏幕的像素密度一般差不多是100dpi。智能手机则拥有惊人的像素密度,详见dpi范围表。比如:

  • Nokia Lumia 640: 332dpi
  • Apple iPhone 6+: 401dpi
  • Google Nexus 5: 445dpi
  • HTC One: 469dpi
  • Samsung Galaxy S6: 577dpi

设备物理像素,设备独立像素,CSS像素

我们上面谈论设备像素时指的是实际存在的设备物理像素,除了物理像素外,还常常接触设备独立像素(device independant pixel(dip))的概念以及CSS样式表中的像素单位。我们有必要搞清楚这些关键概念。

设备物理像素我们很好理解,就是实际渲染时候的物理像素点。

CSS像素是一个参考像素,差不多就是0.26mm(1/96 inch)的样子。在这个0.26mm里,对于一些高dpi的移动设备,可能会存在多个物理像素。
CSS像素如此定义是出于历史原因,在Web技术的早期,绝大多数显示器都是96dpi的。后来出现了更高DPI的显示器。假如我们编写了一个30px的按钮,显示器尺寸为15inch,然后把分辨率从800x600调整到1600x1200(DPI是前者的2倍),这时如果CSS像素和物理像素保持一致,30px的按钮将被缩小1倍。
这导致网页(WEB)或本地应用(APP)的外观样式严重依赖物理设备,因此为了达到跨平台的设备独立性,很多操作系统或浏览器推出了和设备无关的抽象层像素,这个虚拟像素在Android平台就是设备独立像素(DIP),对于iPhone是PT,对于Web而言就是CSS像素。

在早期移动设备上,像素密度较低,比如iPhone3上,CSS像素=设备物理像素,而在iPhone4,苹果引入视网膜(Retina)显示技术,像素密度提高了一倍,这时1个CSS像素=2个设备物理像素。其它系统的移动设备也采用了类似的技术。
比如Android系统根据ldpi、mdpi、hdpi、xhdpi等由低到高不同DPI级别,一个CSS像素相当于多个屏幕物理像素,因设备而异。

这样就引入了一个和像素密度相关的概念叫:设备像素比(Device Pixel Ratio),表示设备上物理像素和设备独立像素(device-independent pixels (dips))的比例,对于Web APP而言就是:devicePixelRatio = 物理像素 / CSS像素。请扩展阅读设备像素比详解

浏览器会把CSS像素按照这个比例转换成设备物理像素后才执行真正的渲染。iPhone系列手机最新设备像素比可查看iPhone设备像素比指南

设备像素比将会影响image元素的使用(“视网膜显示下的CSS技术”),设计师会偏好高精度的图片,Retina屏幕也支持更高的像素。

Image density in CSS

所以一个所谓Retina优化了的网站,应该是为所有设备提供一张缺省图片,而为Retina屏幕提供高精度图片,但限定为相同的视觉尺寸。

/* 40x40 logo */
.logo{ background-image: url(techbrood-logo.png); background-size: 40px 40px;}

@media (min-resolution: 300dpi) {
  /* 80x80 logo resized to 40x40 */
  .logo{ background-image: url(techbrood-logo@2x.png);}
}

记住background size必须被设置。否则,@2x Retina 图片将占据2倍的空间,而不是在相同的空间显示2倍的精度。

@2x 后缀只是苹果用来引用Retina图片的,但已经成为一个事实上的CSS标准符号。

viewport meta标签

上面我们了解设备像素、CSS像素和Retina显示技术,为了让网页能够自适配设备宽度(即在水平方向刚好填满设备屏幕),苹果iPhone Sarafi引入了viewport meta标签,并迅速得到其他厂商的支持。

<meta name="viewport" width="device-width" initial-scale="1.0" maximum-scale="1.0">

上面的代码中,device-width是以设备像素计算的屏幕宽度(对于iPhone5以下是320px,iPhone6是375px),width以CSS像素计量总的页面宽度(在iPhone中,默认为980px)。

如果不设置viewport,那么显然页面内容得缩小到1/3才能在屏幕上完整显示。而在viewport语句中把width设置为和device-width相等,则浏览器将自动把网页适配屏幕宽度(等同于在浏览器中禁止了Zoom)。这个特性很实用,省掉了我们为各个设备手动设置viewport的麻烦。

然后结合media query,我们就可以很方便的设计实现一个响应式Web页面。

一些基本技术

media query是响应式设计的核心基础,用来检测设备屏幕,在确定好设备后,我们可以采用如下基本方法来构建响应式页面:

  • viewport meta标签, 网页自动适配设备屏幕宽度,在浏览器中禁止zoom
  • 排版,根据设备大小自动剪裁相关区域,调整字体大小和垂直空间布局
  • 大屏幕设备采用grid布局,小屏幕设备缺省使用单列
  • 针对特定代理做一定的设计折中
  • 对于图片宽度,使用百分比(%)单位

这里有一组很棒的响应式网页模板,可以作为读者自己构建响应式网站的一个很好的基础:

移动优先还是桌面优先

移动优先还是桌面优先取决于你的网站实际使用场景。移动优先有助于简化网站设计,从简单布局和元素入手。

使用CSS文档流的概念来设计移动网站是很自然的,因为移动网站通常不需要多列布局,自上而下按顺序安排内容即可。

在技术上而言,一个移动优先的CSS会使用 min-width 媒体查询以便于为小屏幕设定默认样式,而为大屏幕应用特定的样式。

参考阅读: