12.2 理解和实现媒体查询

我们在8.6节中学习过,可以使用两种方式针对特定的媒体类型定位CSS。(还有第三种方式,即使用@import规则,我们不讨论这种方法,因为它会影响性能。)回顾一下,第一种方式是使用link元素的media属性,例如(位于head内)。第二种方式是在样式表中使用@media规则,

例如:

  1. /* 打印样式表 */
  2.  
  3. @media print {
  4.  
  5. header[role="banner"] nav,
  6.  
  7. .ad {
  8.  
  9. display: none;
  10.  
  11. }
  12.  
  13. }

媒体查询增强了媒体类型方法,允许根据特定的设备特性定位样式(参见图12.2.1)。要调整网站的呈现样式,让其适应不同的屏幕尺寸,采用媒体查询特别方便。下面列出了可以包含在媒体查询里的媒体特性。

  • width(宽度)

  • height(高度)

  • device-width(设备宽度)

  • device-height(设备高度)

  • orientation(方向)

  • aspect-ratio(高宽比)

  • device-aspect-ratio(设备高宽比)

  • color(颜色)

  • color-index(颜色数)

  • monochrome(单色)

  • resolution(分辨率)

  • scan(扫描)

  • grid(栅格)

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>Media queries in link elements </title>
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <link rel="stylesheet" media="all" href="base.css" />
  8.  
  9. <!--
  10. 逻辑是only
  11. 类型是screen
  12. 特性:min-width的值为480px
  13. -->
  14. <link rel="stylesheet" media="only screen and (min-width: 480px)" href="styles-480.css" />
  15. </head>
  16. <body>
  17. ...

图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等浏览器的基础程序。——译者注

除了orientationscangrid以外,上述属性均可添加min-max-前缀。min-前缀定位的是“大于或等于”对应值的目标,而max-前缀定位的则是“小于或等于”对应值的目标。在本章里,我们将着重介绍min-widthmax-width,因为它们是制作响应式页面时反复用到的两个媒体特性。CSS3媒体查询规范(www.w3.org/TR/css3-mediaqueries/#media1)中有对各项媒体特性的介绍。

现代桌面浏览器和移动电话浏览器对媒体查询的支持程度很高。不过,Internet Explorer 8及以下版本并不支持媒体查询(针对这些浏览器的min-widthmax-width解决方案见第一条提示)。

  1. 媒体查询语法和示例

Peter Gasston的The Book of CSS3(No Starch Press,2011)一书写得很棒。该书对媒体查询的语法做了很好的归纳。以下是媒体查询的基本语法。

  • 指向外部样式表的链接:
  1. <link rel="stylesheet" media="logic type and (feature: value)" href="your-stylesheet.css" />
  • 位于样式表中的媒体查询:
  1. @media logic type and (feature: value) {
  2.  
  3. /* 目标CSS样式规则写在这里 */
  4.  
  5. }

 

  1. /* 常规样式写在这里。每个设备都能获取它们,除非被媒体查询中的样式规则覆盖 */
  2. body {
  3. font-size: 100%;
  4. }
  5.  
  6. p {
  7. color: green;}
  8.  
  9. /*
  10. 逻辑是only
  11. 类型是screen
  12. 特性:min-width 的值为480px
  13. */@media only screen and (min-width:480px) {
  14. /* 针对这种情形的样式写在这里 */
  15. p {
  16. color: red;
  17. font-weight: bold;
  18. }
  19. }

图12.2.2 这个粗略的示例包含了默认的段落样式,接着是当媒体查询结果为真时对段落文本的修改。我将这份样式表保存为basic-media-query.css,并在如图12.2.3所示的页面中加载该文件。结果如图12.2.4、图12.2.5和图12.2.6所示

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>Basic media query example</title>
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <link rel="stylesheet"
  8. href="assets/css/basic-media-query.css" />
  9. </head>
  10. <body>
  11. <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>
  12. </body>
  13. </html>

图12.2.3 这个页面包含指向外部样式表(参见图12.2.2)的链接,该样式表包含一个基本的媒体查询示例

12.2 理解和实现媒体查询 - 图1

图12.2.4 在iPhone纵向模式下,Mobile Safari的视觉区域为320像素宽,因此文本仍为样式表中基准样式定义的绿色(它从浏览器的默认样式继承了font-weight的常规值)。不过,当页面显示在iPad中时……

12.2 理解和实现媒体查询 - 图2

图12.2.5 ……由于在iPad纵向模式下浏览器的视觉区域为768像素宽,而宽度大于或等于480像素时会触发媒体查询,因此文本变成以红色、粗体显示。在iPhone横向模式下该效果也会生效,因为该模式下视觉区域的宽度刚好为480像素

12.2 理解和实现媒体查询 - 图3

图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(逻辑)部分是可选的,其值可以是onlynotonly关键字可以确保旧的浏览器不读取余下的媒体查询,同时一并忽略链接的样式表。not关键字可以对媒体查询的结果求反,让其反面为真。例如,使用media="not screen"会在媒体类型为screen以外的任何类型时加载样式表。

  • type(类型)部分是媒体类型,如screenprint等。

  • feature: value对是可选的,但一旦包含它们,它们必须用括号包围且前面要有and这个字。feature是预定义的媒体特性,如min-widthmax-widthorientation等。对colorcolor-indexmonochrome特性来说,value是可选的。

可以使用and将多个特性和值的组合串接起来,还可以创建一系列媒体查询(使用逗号分隔每个媒体查询)。在用逗号分隔的媒体查询列表中,如果有一个媒体查询为真,则整个媒体查询列表为真。图12.2.7和图12.2.8显示了多种媒体查询。

  1. ...
  2.  
  3. <link rel="stylesheet" media="onlyscreen and (min-width: 480px) and (max-width: 767px)" href="styles.css" />
  4.  
  5. <link rel="stylesheet" media="only screen and (orientation: landscape)" href="styles.css" />
  6.  
  7. <link rel="stylesheet" media="only print and (color)" href="color-pages.css" />
  8.  
  9. <link rel="stylesheet" media="only print and (monochrome)" href="monochrome-pages.css" />
  10.  
  11. <link rel="stylesheet" media="only screen and (color), projection and (color)" href="styles.css" />
  12. </head>
  13. <body>
  14. ...

图12.2.7 当媒体查询为真时加载外部样式表的示例

  1. /* 基准样式
  2. ------------------------------- */
  3.  
  4. /* 针对所有设备的基准样式 */
  5.  
  6. /* 开始媒体查询
  7. ------------------------------- */
  8. @media only screen and (min-width:
  9. 480px) and (max-width: 767px) {
  10. /* 样式规则 */
  11. }
  12.  
  13. @media only screen and (orientation: landscape) {
  14. /* 样式规则 */
  15. }
  16.  
  17. @media only print and (color) {
  18. /* 样式规则 */
  19. }
  20.  
  21. @media only print and (monochrome) {
  22. /* 样式规则 */
  23. }
  24.  
  25. @media only screen and (color),
  26. projection and (color) {
  27. /* 样式规则 */
  28. }

图12.2.8 这些媒体查询与图12.2.7中的是相同的,只是直接出现在样式表中

  1. 指向外部样式表时定义媒体查询
  • 在希望使用有关样式表的每个HTML页面的head部分,输入

  • 输入media="以开始媒体查询。

  • 根据“定义媒体查询的步骤”,创建媒体查询。

  • 输入"以结束媒体查询。

  • 输入一个空格,再输入href="url.css",这里的url.css是当媒体查询为真时应该应用到页面的样式表的路径和名称。

  • 输入一个空格,最后输入/>。(如果你愿意,也可以不输入空格,直接输入>。这两种方式都是HTML5所允许的,其效果也是相同的。)

  1. 在样式表内定义媒体查询并关联样式规则
  • 在样式表内,输入@media和一个空格。

  • 根据“定义媒体查询的步骤”,创建媒体查询。

  • 输入一个空格和{

  • 在新的一行(可选)创建当媒体查询为真时应该应用到页面的样式规则。

  • 在新的一行(可选)输入}以结束媒体查询块。

  1. 定义媒体查询的步骤
  • 可选,输入only和一个空格。(尽管这一步是可选的,但我推荐包含only,除非指定了not。)如果不指定only,输入not和一个空格(可选),表示条件为媒体查询的反面为真。

  • 输入type,这里的type是媒体类型(通常为screenprint,参见8.6节)。

  • 可选,输入一个空格、and和另一个空格。再输入(feature: value),其中feature是某种预定义的媒体特性(包括widthheightdevice-widthdevice-heightorientationaspect-ratiodevice-aspect-ratiocolorcolor-indexmonochromeresolutionscan以及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 理解和实现媒体查询 - 图4

图12.2.9 我的测试页面包含一个320像素×480像素大小、绿色的div。Mobile Safari的视觉区域默认为980像素宽,因此iPhone会将该div缩小,以在320像素宽的屏幕内显示它。这就是这个绿色盒子大约占据屏幕宽度的三分之一(即320/980)的缘故

12.2 理解和实现媒体查询 - 图5

图12.2.10 这个测试页面的代码与图12.2.9中页面的代码相比,除了包含设置了width=de-vice-width的视觉区域meta元素以外,其他内容是完全相同的。如你所见,现在的视觉区域宽度与屏幕宽度是相同的

幸好,对于流式布局(即在CSS中使用百分数宽度建立的布局)有一种简单的解决方案。在页面的head部分添加视觉区域meta元素即可。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>Fancy page title</title>
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. </head>
  8. <body>

这段代码的重点是width=device-width。有了这条语句,视觉区域的宽度会被设成与设备宽度(对iPhone来说为320像素)相同的值,因此在纵向模式下该宽度的页面内容会填充整个屏幕(如图12.2.10所示)。如果不包含这一语句,使用媒体查询的min-widthmax-width特性将不会得到预期的结果。

代码中的initial-scale=1.0部分对widthdevice-width值没有影响,但通常会包含这一语句。它将页面的默认缩放级别设成了100%。你也可以指定小于1.0或大于1.0的值。

还有其他三种属性(不过这里并未演示)。将minimum-scale设成大于0且不超过10.0的值,可以有效地控制页面的最小缩放级别。关于maximum-scaleuser-scalable属性的信息,参见提示。