文章目录
《CSS in Depth》新版封面
7.2 媒体查询 Media queries
响应式设计的第二个原则是使用 媒体查询。媒体查询(media queries) 允许某些样式仅在页面满足特定条件时才生效。这样就可以根据屏幕尺寸定制样式。可以先针对小屏设备定义一套样式,再针对中等屏幕设备定义另一套样式,最后针对大屏设备再定义一套样式,这样就能让页面内容呈现多种布局。
媒体查询使用写作 @media
的 @规则 选中符合特定条件的设备。一条简单的媒体查询写法如以下代码所示:
@media (min-width: 560px) {
.title > h1 {
font-size: 2.25rem;
}
}
在最外层的大括号内可以定义任意的样式规则。@media
规则会进行条件检查,只有满足所有条件时,才会将这些样式应用到页面上。本例中浏览器会检查 min-width: 560px;
,即仅当设备的视口宽度大于等于 560px
时,样式类 title
下的一级标题 h1
元素才能设为 2.25rem
的大号字;若视口小于 560px
,则内部规则集都会被忽略。
媒体查询中的规则仍然遵循常规的层叠原理。它们既可以覆盖媒体查询外部的样式规则(根据选择器的优先级或源码顺序等),也可能被这些样式规则覆盖掉。而媒体查询本身不会影响到它里面的选择器优先级。
接下来演示几个给页面设置媒体查询的例子。找到样式表中的 .title
样式,并按照代码清单 7.7 中的样式添加媒体查询,让页面标题拥有响应式行为。
代码清单 7.7 给页面标题样式添加断点
.title > h1 {
color: #333;
text-transform: uppercase;
font-size: 1.5rem;
margin-block: 0.2em;
}
@media (min-width: 560px) { /* 匹配宽度在 560px 及以上的视口 */
.title > h1 {
font-size: 2.25rem; /* 用更大的字号覆盖移动端的小号字(1.5rem) */
}
}
此时,根据视口大小的不同,页面标题就有了两种不同的字号:视口宽度不足 560px
时字号为 1.5rem
;超过 560px
则为 2.25rem
(译注:刚好等于 560px
时也是 2.25rem
)。
通过缩放浏览器窗口就能测出标题的样式:窗口很窄的时候,看到的是适配移动端的小字号;慢慢扩大浏览器窗口,字号也会平滑过渡,因为页面通过 clamp()
(详见代码清单 7.2)事先设置了响应式的字号;而当页面宽度达到 560px
时,标题的字号则会立马变为 2.25rem
。
窗口宽 560px
的这个临界点,就被称为一个 断点(breakpoint)。大多数情况下,整个样式表里的媒体查询只会复用几个为数不多的断点。本章稍后会介绍如何挑选合适的断点。
7.2.1 深入理解媒体查询的类型 Understanding types of media queries
还可以进一步将两个条件用 and
关键字联合起来,组合为 一个 媒体查询:
@media (min-width: 320px) and (max-width: 560px) { ... }
这样的组合式媒体查询仅在设备同时满足这两个条件时才会生效。如果设备只需要满足其中一个条件,可以用逗号分隔,写作:
@media (max-width: 320px), (min-width: 560px) { ... }
上述媒体查询将匹配宽度小于等于 320px
、或者大于等于 560px
的视口。另外,关键字 or
已收入 W3C 媒体查询第四级规范(W3C Media Queries Level 4 specification),与这里的逗号等效。该写法相对较新,仅在最近版本的 Chrome
、Firefox
及 Safari
浏览器中有效。
1 最小宽度、最大宽度及其他 min-width, max-width, and beyond
刚才那段代码中,min-width
用于匹配视口大于特定宽度的设备;max-width
则相反,用于匹配视口小于特定宽度的设备。它们被统称为 媒体特征(media feature)。
min-width
和 max-width
是目前使用最为广泛的媒体特征,但还有一些别的媒体特征可供选用。下面列出了其中的部分写法:
(min-height: 320px)
—— 匹配高度不低于320px
的视口。(max-height: 320px)
—— 匹配高度不超过320px
的视口。(orientation: landscape)
—— 匹配宽度大于高度的视口。(orientation: portrait)
—— 匹配高度大于宽度的视口。(min-resolution: 2dppx)
—— 匹配屏幕分辨率不小于2dppx
(即每个 CSS 像素里包含两个物理像素点)的设备,比如“视网膜”("retina"
)屏慕。(max-resolution: 2dppx)
—— 匹配屏幕分辨率不超过2dppx
的设备。(pointer: coarse)
—— 匹配不具备精确指向方法(precise pointing method,比如鼠标)的设备。通常匹配的是触摸屏设备,因为用户手指无法准确选中太小的按钮;可以用它来放大这些点击目标。(pointer: fine)
—— 匹配具备精确指向方法的设备,例如鼠标。
查看完整的媒体特征列表,详见 MDN 官方文档:https://developer.mozilla.org/en-US/docs/Web/CSS/@media
基于分辨率的媒体查询对于能够渲染更高分辨率的图像或图标的设备屏幕非常有用。这样一来,屏幕分辨率较低的用户在加载较大的图像时就不会浪费带宽,因为他们看不出差异。本章稍后还将进一步介绍响应式图像的相关知识。
此外,还有个关键点值得注意:在媒体查询中无法访问自定义属性。也就是说,像 @media (min-width: var(--breakpoint))
这样的写法是无效的,因为 var()
的使用场景仅限于在给某个属性(property)的样式声明赋上某个值时使用。
2 媒体查询中的范围表示法 Range syntax in media queries
媒体查询还有一种新的语法,可以使用小于和大于符号。例如,之前的 @media (min-width: 800px)
可以直接写成 @media (width >= 800px)
。此外,还可以为查询提供一组上下边界(upper and lower bound),例如写作 @media (800px < width < 1200px)
,表示仅对宽度介于 800px
到 1200px
之间的视口生效。
该语法较之传统写法有两个明显优势:首先,使用了该语法的媒体查询读起来更加直观,尤其是在定义上下边界时,像 (800px <= width <= 1200px)
的写法比之前冗长的 (min-width: 800px) and (max-width: 1200px)
更容易理解。
而该语法的第二个好处,则是提供了小于等于(<=
)和大于等于(>=
)符号的配置选项。使用传统写法的媒体查询时,假设某个应用场景中同时存在像 max-width: 30em
与 min-width: 30em
这样的两个媒体查询。如果视口宽度恰巧为 30em
,则二者都将生效,从而可能带来一些不符合预期的效果。而使用新的范围表示方法,就能通过 是否使用等号 来准确描述目标范围在对应边界上的包含情况。再来看几个类似的用法:
@media (480px <= width < 1200px) { ... }
@media (800px < height) { ... }
@media (width = 1600px) { ... }
该语法尽管仍然相对较新,但所有主流浏览器的最新版本都对其提供了支持。获取该语法在各版本浏览器中的最新兼容情况,详见:https://caniuse.com/css-media-range-syntax。
3 浅色主题与深色主题 Light and dark themes
此外,您还可以使用媒体查询来检测用户的操作系统是否设置成了深色模式(dark mode)并据此来为页面提供浅色或深色背景,以匹配用户的偏好:
@media (prefers-color-scheme: dark) {
:root {
--theme-font-color: white;
--theme-background: #222;
}
}
或者匹配浅色主题来进行设置:
@media (prefers-color-scheme: light) {
:root {
--theme-font-color: #222;
--theme-background: #eee;
}
}
我发现,像上述代码这样充分利用自定义属性,不失为更改整个页面样式的一种相对简单的做法,只要能确保在样式表中始终如一地使用自定义属性就行。
实际运用过程中,完成这样的任务肯定不止这两个自定义变量。后续章节将进一步深入探讨颜色变量的管理。
4 媒体类型 Media types
最后一个要介绍的媒体查询配置选项,为 媒体类型(media type)。常见的两种类型为 screen
和 print
。使用 print
媒体查询可以控制打印时的页面布局,这样就能在打印时去掉背景图(为了省墨),或者隐藏不必要的导航栏。毕竟用户打印网页时,通常只想打印主体内容。
要编写仅在打印时生效的样式(即打印样式),需使用查询语句 @media print
。与 min-width
及其他媒体特征一样,该语句不用加小括号。而针对屏幕样式,则使用 @media screen
。
开发 CSS 的时候,通常在事后才会处理打印样式(an afterthought),而且只在确实需要打印时才会考虑;但还是有必要思考用户是否想要打印该网页。为了帮助用户打印出网页,需要采取一些通用步骤。大多数情况下,都需要将基础打印样式放在 @media print {...}
的媒体查询内。
要使用 display: none
来隐藏像导航菜单、页脚这样的次要内容。用户打印网页时,他们绝大多数情况下只关心网页的主体内容。
还可以将整体的字体颜色设置为黑色,并去掉文字后面的背景图片或背景色。大多数情况下,使用通用选择器就能搞定这一切。以下代码使用了 !important
标记,这样就不用担心被后面的样式代码覆盖掉。
@media print {
* {
color: black !important;
background: none !important;
}
}
花费一些时间来优化打印样式,对用户来说是一项很不错的服务。如果要开发的网站预计会有很多打印需求(例如食谱类网站),那就应该花更多时间确保所有的样式都能正常打印。
第 1 版 | 第 2 版 | |
---|---|---|
读者评分 | 原版:4.7(亚马逊);中文版:9.3(豆瓣) | 原版:5.0(亚马逊);中文版:暂无,待出版 |
出版时间 | 原版:2018 年 3 月;中文版:2020 年 4 月 | 原版:2024 年 7 月;中文版:暂无,待出版 |
原价 | 原版:$44.99;中文版:¥139.00 | 原版:$59.99;中文版:暂无,待出版 |
现价 | 原版:$36.49;中文版:¥52.54 起步 | 原版:$52.09;中文版:暂无,待出版 |
原版国内预订 | 起步价 ¥461.00 | 起步价 ¥750.00 |
本专栏为该书第 2 版高分译文专栏,全网首发,精译精校,持续更新,计划今年内完成全书翻译,敬请期待!!!
目前已完结的章节(可进入本专栏查看详情,连载期间完全免费):