CSS3之美(一):媒体查询

长期以来,在CSS中有一种方法可以为不同的媒体类型提供不同的样式,这种方法就是使用 link 元素的 media 属性:

1
<link rel="stylesheet" href="style.css" media="screen">

但是,如果屏幕尺寸有可能在 3.5 英寸到 32 英寸之间时,使用这种方式就没什么用了。对于这个问题,CSS3 通过媒体查询模块 Media Queries Module 提供了解决方案。

媒体查询提供了一种查询语法去扩展媒体类型,这种查询语法可以更加具体地为用户的设备提供样式。它解决了许多问题,使用它的好处如下:

  1. 媒体查询会基于设备的属性来检测设备,这样就不需要使用浏览器检测脚本了
  2. 允许直接按照设备的功能去设定样式表
  3. 对于小屏幕的设备,CSS规则会自调整以适应屏幕尺寸

媒体查询的基础知识

引入CSS样式

为一个 HTML 元素应用 CSS 样式有三种方式。同样地,当然首先也是为相应的媒体查询条件引入 CSS 样式也有三种方式:

  1. 使用 link 元素去调用一个外部样式表:
1
<link rel="stylesheet" href="style.css" media="logic media and (expression)">
  1. 使用 @import 指令调用外部的样式表:
1
@import url('file') logic media and (expression);
  1. 在一个嵌入 style 属性的 HTML 元素中或在样式表本身利用扩展的 @media 规则使用媒体查询:
    1
    @media logic media and (expression) { rules };

如果针对媒体查询的CSS代码量大,推荐使用第1种方式,将其单独组织为一个样式表文件并通过特定语法引入到HTML文件中。如果针对媒体查询的CSS代码量较少,则推荐使用第3种方式,在主要样式表中使用特定语法写出即可。

基本语法

下文以上文的第三种方式为例,详析一下媒体查询的基本语法:

1
@media logic media and (expression) { rules }

media 属性主要用来声明样式要应用的媒体类型,就像 HTML 的 link 标签一样:

1
<link href="style.css" rel="stylesheet" media="screen, projection">

和当前语法一样,在使用 media 属性时我们可以使用逗号隔开的列表去选择多种媒体类型,不过我们最长用的媒体类型还是 screen,即用于计算机显示器。

@media的规则的第一个属性是logic,可选,值可以为onlynot

1
2
3
@media only media and (expression) { rules }
/* ----- or ----- */
@media not media and (expression) { rules }

  • 如果要对不支持该语法的浏览器隐藏规则,可以使用 only 值;对支持该语法的浏览器而言,only 可以被有效地忽略。
  • not 值有点儿补集的思想,即否定此次特定的媒体查询。如果浏览器不满足设置的参数,就可以使用 not 来应用这些样式。

expression 属性用于接受参数并根据这些参数选择 CSS 样式响应何种设备。我们可以使用 and 操作符去声明 expression,并用它设置媒体类型以外的参数。这些参数被称为媒体特征。例如:

1
2
@media screen and (min-width: 480px) { rules }
/* CSS 规则将会被应用到浏览器窗口宽度大于等于 480px 的设备 */

详解媒体特征

媒体特征

前面说到 expression 属性是根据媒体特征参数选择响应何种设备的,那么什么是媒体特征呢?

媒体特征就是与显示网页的设备有关的信息,它包括了设备的大小、分辨率等。这些信息被用于匹配一条 expression,若匹配成功则相应的样式规则就会被应用到相应设备上。

在媒体查询中,需要为大多数的媒体特征表达式提供一个值:

1
@media media and (feature: value) { rules }

不过在某些情况下,该值也可以被忽略,只对媒体特征本身进行检测:

1
@media media and (feature) { rules }

width与height

width 媒体特征描述了特定媒体类型的渲染视区的宽度,实际上,对于桌面的操作系统来说,通常就是浏览器的当前宽度(包括滚动条)。其基本语法需要一个长度值:

1
@media media and (width: 600px) { rules }

看,就是这样,很好理解吧。像读文章一样,上面代码的意思是在宽度为 600px 的浏览器上应用此样式。CSS 还为我们提供了 最小宽度 min-width 和 最大宽度 max-width,方便我们进行更精确地控制,小示例:

1
2
@media screen and (max-width: 480px) and (min-width: 600px) { rules }
/* 在浏览器窗口宽度不小于 480px 且不大于 600px 的设备上应用此样式 */

height 也是同样的呀,只不过用得比较少了,毕竟大家在浏览器里都是垂直滚动嘛,很少有人是水平滚动吧。所以不废话了,小结一下吧:

1
2
3
4
5
6
@media media and (width: value) { rules }
@media media and (min-width: value) { rules }
@media media and (max-width: value) { rules }
@media media and (height: value) { rules }
@media media and (min-height: value) { rules }
@media media and (max-height: value) { rules }

device-width与device-height

刚刚的 widthheight 都是针对浏览器窗口的宽高而言的(包括滚动条),而现在要说的 device-widthdevice-height 则是针对设备本身的宽度和高度。device-widthdevice-heightwidthheight 的语法没什么大区别,所以也不废话了,小结一下:

1
2
3
4
5
6
@media media and (device-width: value) { rules }
@media media and (min-device-width: value) { rules }
@media media and (max-device-width: value) { rules }
@media media and (device-height: value) { rules }
@media media and (min-device-height: value) { rules }
@media media and (max-divice-height: value) { rules }

注意: IOS(iPhone、iPad,等等)和 Android 设备会通过四个屏幕侧边中较短的一对去测量 device-width。也就是说,给定尺寸为 480x600 的设备,无论它是纵向显示还是横向显示,其 device-width 都会是 480px。

orientation

如果我们需要对水平方向(如网页浏览器)或者垂直方向(如电子书阅读器)两种网页浏览方式进行优化,则需要使用媒体特征 orientation。它的语法如下:

1
@media media and (orientation: value) { rules }

其中,value 只允许两个关键字值:

  • landscapelandscape 值会在浏览器宽度大于高度的时候被应用
  • portrait: 应用场景与 landscape 相反,会在浏览器宽度小于高度的时候被应用

由于媒体特征 orientation 只有两个值,所以如果我们只使用了其中一个值,那么另外一个自然就是相反的。

aspect-ratio/device-aspect-ratio

媒体特征 aspect-ratio 用于检测浏览器的宽高比,而 device-aspect-ratio 特征则用于检测设备的宽高比。它们的语法如下:

1
2
@media media and (aspect-ratio: horizontal/vertical) { rules }
@media media and (device-aspect-ratio: horizontal/vertical) { rules }

其中,horizontal 表示宽度,而 vertical 表示高度,二者的值都是正整数,最终媒体特征的值代表查看浏览器(或设备)的屏幕宽度与高度对应的比值。例如:16:9、16:10。

DPR(设备像素比)

一般而言,CSS像素单位(px)是指计算机屏幕上一个单独像素的大小——如果屏幕的分辨率是 1024px X 768px,我们把一个元素的宽度设置为 1024px 时,可以预期它在水平方向上将填满整个屏幕。不过,对于智能手机和移动设备来说情况并不总是这样。在它们的小屏幕上访问网站,通常需要放大显示,这样会导致屏幕像素大于 CSS 像素。例如,以 100% 的比例缩放页面,意味着 1 个 CSS 像素会以 4 个设备像素(2x2)的大小在屏幕上显示。对于可缩放的内容,比如文本和矢量图形,放大不会导致什么问题;但对于位图格式的图片,放大可能会导致严重失真。

DPR(device pixel ratio),设备像素比,即设备像素与 CSS 像素的比值。

媒体特征 device-pixel-ratio 可以根据设备的像素比去判断设备,它在 Mobile Webkit 中的实现带有 -webkit- 前缀。

1
@media media and (-webkit-device-pixel-ratio: value) { rules }

其中,value 是一个小数,表示设备的像素密度。当然了,和其他媒体特征一样,我们还是会有最小像素密度 min-device-pixel-ratio 和最大像素密度 max-device-pixel-ratio 的:

1
2
@media media and (-webkit-min-device-pixel-ratio: value) { rules }
@media media and (-webkit-max-device-pixel-ratio: value) { rules }

多种媒体特征一起用

还记得 @media media 后面的那个 and 么,我们可以使用 and 操作符添加表达式,从而把多个媒体特征查询链接在同一个媒体类型上:

1
@media logic media and (expression) and (expression) { rules }

这种语法在应用选定规则之前,先测试两个表达式是否匹配。

我们也可以在多种媒体类型上设置不同的表达式:

1
@media logic media and (expression), media and (expression) { rules }

媒体查询的实际使用

以上代码中反复出现的 media 表示媒体类型,这是 CSS2 的语法规范。不过我们最常用的还是 screen 即用于计算机显示器。

下面是个小例子:

1
2
3
4
5
6
7
8
9
@media screen and (min-width: 400px) {
h1 {
background: block url('bc.jpg') no-repeat 50% 50%;
color: white;
height: 190px;
margin-bottom: 0;
padding: 20px;
}
}

上面的 CSS 规则只会被应用到浏览器窗口大于等于 400px 的设备。

一般来说,我们可能倾向于先创建一个为较大的浏览器或设备而优化的样式,再使用媒体查询为较小的设备提供不同的样式。但是在现实中,我们却可能不会这样做,由于某些浏览器加载页面资源(比如样式表中包含的图片)的方法所致。

一般媒体查询的早期使用者,先使用大的背景图片,之后在移动设备设置 disaply: none,将图片隐藏起来。不过,尽管这些背景图片不会显示,但仍然可能被下载并存放在缓存中。这种方式增加了页面的加载时间,也可能会消耗带宽流量——这对于没有无线连接的设备用户来说确实很糟糕。

所以,创建页面的更好方法是先为移动用户制作一个基本的样式表,然后再为桌面用户制作一个带较大资源的样式表,最后使用像 device-width 这样的媒体特征进行查询来加载。

1
2
<link href="mobile.css" rel="stylesheet" media="screen">
<link href="desktop.css" rel="stylesheet" media="screen" and (min-device-width: 480px)">

如上,采用这种方式把样式表分开后,对于屏幕宽度小于 480px 的设备,将不会加载 desktop.css 文件,那些大资源自然也不会在后台下载了。

这种方式最大的例外就是 IE。IE9 以下的版本都不支持媒体查询,为了解决这个问题,我们需要 CSS Hack:

1
2
3
4
5
<link href="mobile.css" rel="stylesheet" media="screen">
<link href="descktop.css" rel="stylesheet" media="screen and (min-device-width: 480px)">
<!--[if It IE 9]>
<link href="desktop.css" rel="stylesheet" media="screen">
<![endif]-->