12.2 理解和实现媒体查询
我们在8.6节中学习过,可以使用两种方式针对特定的媒体类型定位CSS。(还有第三种方式,即使用@import
规则,我们不讨论这种方法,因为它会影响性能。)回顾一下,第一种方式是使用link
元素的media
属性,例如(位于
head
内)。第二种方式是在样式表中使用@media
规则,
例如:
- /* 打印样式表 */
- @media print {
- header[role="banner"] nav,
- .ad {
- display: none;
- }
- }
媒体查询增强了媒体类型方法,允许根据特定的设备特性定位样式(参见图12.2.1)。要调整网站的呈现样式,让其适应不同的屏幕尺寸,采用媒体查询特别方便。下面列出了可以包含在媒体查询里的媒体特性。
width
(宽度)height
(高度)device-width
(设备宽度)device-height
(设备高度)orientation
(方向)aspect-ratio
(高宽比)device-aspect-ratio
(设备高宽比)color
(颜色)color-index
(颜色数)monochrome
(单色)resolution
(分辨率)scan
(扫描)grid
(栅格)
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8" />
- <title>Media queries in link elements </title>
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <link rel="stylesheet" media="all" href="base.css" />
- <!--
- 逻辑是only
- 类型是screen
- 特性:min-width的值为480px
- -->
- <link rel="stylesheet" media="only screen and (min-width: 480px)" href="styles-480.css" />
- </head>
- <body>
- ...
图12.2.1 base.css中的样式用于所有的输出设备。styles-480.css中的样式则仅用于支持媒体查询且视觉区域宽度不低于480像素的浏览器
还有一些非标准的媒体特性,如
-webkit-device-pixel-ratio
(WebKit1设备像素比)
1 WebKit是Chrome、Safari等浏览器使用的网页引擎和JavaScript引擎开源程序。——译者注
-moz-device-pixel-ratio
(Mozilla2设备像素比)
2 Mozilla是Firefox等浏览器的基础程序。——译者注
除了orientation
、scan
和grid
以外,上述属性均可添加min-
和max-
前缀。min-
前缀定位的是“大于或等于”对应值的目标,而max-
前缀定位的则是“小于或等于”对应值的目标。在本章里,我们将着重介绍min-width
和max-width
,因为它们是制作响应式页面时反复用到的两个媒体特性。CSS3媒体查询规范(www.w3.org/TR/css3-mediaqueries/#media1)中有对各项媒体特性的介绍。
现代桌面浏览器和移动电话浏览器对媒体查询的支持程度很高。不过,Internet Explorer 8及以下版本并不支持媒体查询(针对这些浏览器的min-width
和max-width
解决方案见第一条提示)。
- 媒体查询语法和示例
Peter Gasston的The Book of CSS3(No Starch Press,2011)一书写得很棒。该书对媒体查询的语法做了很好的归纳。以下是媒体查询的基本语法。
- 指向外部样式表的链接:
- <link rel="stylesheet" media="logic type and (feature: value)" href="your-stylesheet.css" />
- 位于样式表中的媒体查询:
- @media logic type and (feature: value) {
- /* 目标CSS样式规则写在这里 */
- }
- /* 常规样式写在这里。每个设备都能获取它们,除非被媒体查询中的样式规则覆盖 */
- body {
- font-size: 100%;
- }
- p {
- color: green;}
- /*
- 逻辑是only
- 类型是screen
- 特性:min-width 的值为480px
- */@media only screen and (min-width:480px) {
- /* 针对这种情形的样式写在这里 */
- p {
- color: red;
- font-weight: bold;
- }
- }
图12.2.2 这个粗略的示例包含了默认的段落样式,接着是当媒体查询结果为真时对段落文本的修改。我将这份样式表保存为basic-media-query.css,并在如图12.2.3所示的页面中加载该文件。结果如图12.2.4、图12.2.5和图12.2.6所示
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8" />
- <title>Basic media query example</title>
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <link rel="stylesheet"
- href="assets/css/basic-media-query.css" />
- </head>
- <body>
- <p>Hi, I'm a paragraph. By default, I'm green and normal. But get me in a viewport that's at least 480px wide, and I get red and bold!</p>
- </body>
- </html>
图12.2.3 这个页面包含指向外部样式表(参见图12.2.2)的链接,该样式表包含一个基本的媒体查询示例
图12.2.4 在iPhone纵向模式下,Mobile Safari的视觉区域为320像素宽,因此文本仍为样式表中基准样式定义的绿色(它从浏览器的默认样式继承了font-weight
的常规值)。不过,当页面显示在iPad中时……
图12.2.5 ……由于在iPad纵向模式下浏览器的视觉区域为768像素宽,而宽度大于或等于480像素时会触发媒体查询,因此文本变成以红色、粗体显示。在iPhone横向模式下该效果也会生效,因为该模式下视觉区域的宽度刚好为480像素
图12.2.6 现代桌面浏览器也理解媒体查询。这是Firefox,通过拖拽窗口的右下角使视觉区域的宽度小于480像素,因此文本显示为红色,font-weight
为常规值。如果让窗口变大,使其宽度至少为480像素,文字将立即以粗体、红色显示——无须刷新页面
我将在随后解释有关的语法,不过几个简单的例子(参见图12.2.1和图12.2.2)有助于在上下文中理解这些语句。示例中的查询是相同的,但它们呈现样式的方式却是不同的。图12.2.1中的示例可以翻译为“仅当媒体类型为screen
且视觉区域最小宽度为480像素时,加载并使用styles-480.css
中的样式规则”。图12.2.2中的示例可以翻译为“仅当媒体类型为screen
且视觉区域最小宽度为480像素时,使用下面的样式规则”。(关于视觉区域的含义,参见本节末尾的“理解视觉区域及使用视觉区域meta
元素”。)我创建了一个测试页(如图12.2.3所示),并指向包含图12.2.2中代码的样式表。可以查看该页面在iPhone(图12.2.4)、iPad(图12.2.5)及窄的桌面浏览器 (图12.2.6)中显示的样子。
回到语法,让我们看看这些代码的组成部分。
logic
(逻辑)部分是可选的,其值可以是only
或not
。only
关键字可以确保旧的浏览器不读取余下的媒体查询,同时一并忽略链接的样式表。not
关键字可以对媒体查询的结果求反,让其反面为真。例如,使用media="not screen"
会在媒体类型为screen
以外的任何类型时加载样式表。type
(类型)部分是媒体类型,如screen
、print
等。feature: value
对是可选的,但一旦包含它们,它们必须用括号包围且前面要有and
这个字。feature
是预定义的媒体特性,如min-width
、max-width
、orientation
等。对color
、color-index
和monochrome
特性来说,value
是可选的。
可以使用and
将多个特性和值的组合串接起来,还可以创建一系列媒体查询(使用逗号分隔每个媒体查询)。在用逗号分隔的媒体查询列表中,如果有一个媒体查询为真,则整个媒体查询列表为真。图12.2.7和图12.2.8显示了多种媒体查询。
- ...
- <link rel="stylesheet" media="onlyscreen and (min-width: 480px) and (max-width: 767px)" href="styles.css" />
- <link rel="stylesheet" media="only screen and (orientation: landscape)" href="styles.css" />
- <link rel="stylesheet" media="only print and (color)" href="color-pages.css" />
- <link rel="stylesheet" media="only print and (monochrome)" href="monochrome-pages.css" />
- <link rel="stylesheet" media="only screen and (color), projection and (color)" href="styles.css" />
- </head>
- <body>
- ...
图12.2.7 当媒体查询为真时加载外部样式表的示例
- /* 基准样式
- ------------------------------- */
- /* 针对所有设备的基准样式 */
- /* 开始媒体查询
- ------------------------------- */
- @media only screen and (min-width:
- 480px) and (max-width: 767px) {
- /* 样式规则 */
- }
- @media only screen and (orientation: landscape) {
- /* 样式规则 */
- }
- @media only print and (color) {
- /* 样式规则 */
- }
- @media only print and (monochrome) {
- /* 样式规则 */
- }
- @media only screen and (color),
- projection and (color) {
- /* 样式规则 */
- }
图12.2.8 这些媒体查询与图12.2.7中的是相同的,只是直接出现在样式表中
- 指向外部样式表时定义媒体查询
在希望使用有关样式表的每个HTML页面的
head
部分,输入。
输入
media="
以开始媒体查询。根据“定义媒体查询的步骤”,创建媒体查询。
输入
"
以结束媒体查询。输入一个空格,再输入
href="url.css"
,这里的url.css
是当媒体查询为真时应该应用到页面的样式表的路径和名称。输入一个空格,最后输入
/>
。(如果你愿意,也可以不输入空格,直接输入>
。这两种方式都是HTML5所允许的,其效果也是相同的。)
- 在样式表内定义媒体查询并关联样式规则
在样式表内,输入
@media
和一个空格。根据“定义媒体查询的步骤”,创建媒体查询。
输入一个空格和
{
。在新的一行(可选)创建当媒体查询为真时应该应用到页面的样式规则。
在新的一行(可选)输入
}
以结束媒体查询块。
- 定义媒体查询的步骤
可选,输入
only
和一个空格。(尽管这一步是可选的,但我推荐包含only
,除非指定了not
。)如果不指定only
,输入not
和一个空格(可选),表示条件为媒体查询的反面为真。输入
type
,这里的type
是媒体类型(通常为screen
或print
,参见8.6节)。可选,输入一个空格、
and
和另一个空格。再输入(feature: value)
,其中feature
是某种预定义的媒体特性(包括width
、height
、device-width
、device-height
、orientation
、aspect-ratio
、device-aspect-ratio
、color
、color-index
、monochrome
、resolution
、scan
以及grid
),value
是合适的feature
值(通常情况下以像素或em表示,但也并非总是如此,有关示例参见图12.2.2、图12.2.7和图12.2.8)。如果想创建一系列媒体查询,输入一个逗号,再重复第2步和第3步。否则,媒体查询就定义完成了。
提示 要了解如何解决IE8及以下版本不支持媒体查询的问题,参见12.3节中的“在IE8及以下版本中呈现媒体查询样式。
提示 任何位于媒体查询以外的基准样式规则都会应用于所有的设备。可以使用媒体查询覆盖这些样式规则。需要说明的是,媒体查询样式规则声明仅在与常规样式冲突时进行覆盖,如图12.2.5中的
color: green;
。如果媒体查询之前的p
的样式规则包含font-style: italic;
,那么媒体查询为真时段落文本仍以斜体显示,因为媒体查询内的p
的样式规则并未设置font-style
。
提示 iPhone调高了横向模式下页面的缩放级别。因此,有些内容会显示到可视区域以外,需要访问者手动缩小页面,让宽度在屏幕边界以内。有一种方法可以防止这种现象的产生,但不幸的是,使用这种方法也会让访问者无法改变页面缩放级别。不过,如果你一定要控制这种行为,可以添加以下代码中突出显示的部分:
。但我不推荐使用这种方法,应该忽略这两个属性,让访问者控制网站页面的缩放。
提示 可以使用苹果推出的免费的iOS Simulator(iOS模拟器)测试示例页面在iPhone和iPad中的显示情况。参见下一节的“移动编码和测试工具”。
理解视觉区域及使用视觉区域
meta
元素视觉区域(viewport)指的是浏览器(包括桌面浏览器和移动浏览器)显示页面的区域。它不包含浏览器地址栏、按钮这样的东西,只是浏览区域。媒体查询的
width
特性对应的是视觉区域的宽度。不过,device-width
特性不是,它指的是屏幕的宽度。在移动设备(如iPhone)上,默认情况下这两个值通常不一样。Mobile Safari(iPhone的浏览器)的视觉区域默认为980像素宽,但iPhone的屏幕只有320像素宽(高为480像素)。因此,iPhone会像设为980像素宽的桌面浏览器那样显示页面,并将页面缩小以适应320像素的屏幕宽度(在纵向模式下),如图12.2.9所示。结果,当你在Mobile Safari中浏览大部分为桌面浏览器建立的网站时,会显示将这些网站缩小了的样子。在横向模式下也是这样处理的,只不过宽度为480像素。如图12.2.9所示,如果不进行放大,页面通常是难以阅读的(注意不同设备的默认视觉区域宽度并不相同)。
图12.2.9 我的测试页面包含一个320像素×480像素大小、绿色的
div
。Mobile Safari的视觉区域默认为980像素宽,因此iPhone会将该div
缩小,以在320像素宽的屏幕内显示它。这就是这个绿色盒子大约占据屏幕宽度的三分之一(即320/980)的缘故
图12.2.10 这个测试页面的代码与图12.2.9中页面的代码相比,除了包含设置了
width=de-vice-width
的视觉区域meta
元素以外,其他内容是完全相同的。如你所见,现在的视觉区域宽度与屏幕宽度是相同的幸好,对于流式布局(即在CSS中使用百分数宽度建立的布局)有一种简单的解决方案。在页面的
head
部分添加视觉区域meta
元素即可。
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8" />
- <title>Fancy page title</title>
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- …
- </head>
- <body>
- …
这段代码的重点是
width=device-width
。有了这条语句,视觉区域的宽度会被设成与设备宽度(对iPhone来说为320像素)相同的值,因此在纵向模式下该宽度的页面内容会填充整个屏幕(如图12.2.10所示)。如果不包含这一语句,使用媒体查询的min-width
和max-width
特性将不会得到预期的结果。代码中的
initial-scale=1.0
部分对width
和device-width
值没有影响,但通常会包含这一语句。它将页面的默认缩放级别设成了100%。你也可以指定小于1.0
或大于1.0
的值。还有其他三种属性(不过这里并未演示)。将
minimum-scale
设成大于0
且不超过10.0
的值,可以有效地控制页面的最小缩放级别。关于maximum-scale
和user-scalable
属性的信息,参见提示。