媒体查询基础
CSS 媒体查询提供了一种只有当浏览器和设备环境符合你指定的规则时才应用 CSS 的方法,例如“视口宽度大于 480 像素”。媒体查询是响应式 Web 设计的关键部分,因为它们允许你根据视口大小创建不同的布局,但它们也可以用来检测你的网站运行环境的其他信息,例如用户使用的是触摸屏而不是鼠标。
在本课中,你将首先学习媒体查询中使用的语法,然后通过示例了解如何使基本设计具有响应性。
| 预备知识 | 使用 HTML 构造内容、CSS 样式基础、文本和字体样式基础,熟悉CSS 布局基本概念。 |
|---|---|
| 学习成果 |
|
媒体查询基础知识
最简单的媒体查询语法如下所示
@media media-type and (media-feature-rule) {
/* CSS rules go here */
}
它由以下部分组成
- 一个媒体类型,告诉浏览器此代码适用于哪种媒体(打印或屏幕)。
- 一个媒体表达式,它是一个规则或测试,必须通过才能应用其中包含的 CSS。
- 一组 CSS 规则,如果测试通过且媒体类型正确,这些规则将被应用。
媒体类型
你可以指定的媒体类型有
all打印screen
以下媒体查询只会在打印页面时将正文设置为 12pt。当页面在浏览器中加载时,它不会应用。
@media print {
body {
font-size: 12pt;
}
}
注意:这里的媒体类型与所谓的MIME 类型不同。媒体查询级别 3 规范中定义了许多其他媒体类型;这些已被弃用,应避免使用。媒体类型是可选的;如果你在媒体查询中未指明媒体类型,则媒体查询将默认为所有媒体类型。
媒体特性规则
指定类型后,你可以使用规则定位媒体特性。以下示例展示了如何使用不同的媒体查询。要更改屏幕的宽度,请更改浏览器大小或旋转手持设备。
注意:另外,你可以使用浏览器开发者工具的响应式尺寸调整功能(例如 Firefox 响应式设计模式)来模拟不同的设备宽度。
宽度和高度
我们为了创建响应式设计而最常检测的特性(并且具有广泛的浏览器支持)是视口宽度,我们可以使用 width 媒体特性,并根据需要添加 min- 或 max- 前缀,在视口宽度高于或低于某个特定宽度,或精确宽度时应用 CSS。
这些特性用于创建适应不同屏幕尺寸的布局。例如,如果视口宽度恰好是 600 像素,要将正文文本颜色设置为红色,你将使用以下媒体查询。
@media screen and (width: 600px) {
body {
color: red;
}
}
<p>
One November night in the year 1782, so the story runs, two brothers sat over
their winter fire in the little French town of Annonay, watching the grey
smoke-wreaths from the hearth curl up the wide chimney. Their names were
Stephen and Joseph Montgolfier, they were papermakers by trade, and were noted
as possessing thoughtful minds and a deep interest in all scientific knowledge
and new discovery.
</p>
尝试调整浏览器窗口宽度,看看你是否能找到上面演示正好是 600px 宽的“最佳点”,使文本变成红色。
width(和 height)媒体特性可以用作范围,因此可以前缀 min- 或 max- 来指示给定值是最小值或最大值。例如,如果视口宽度为 600 像素或更窄,要使颜色变为蓝色,请使用 max-width
@media screen and (max-width: 600px) {
body {
color: blue;
}
}
尝试缩小窗口,直到上面的文本变为蓝色。
实际上,使用最小值或最大值对于响应式设计更有用,所以你很少会看到 width 或 height 单独使用。
你可以测试许多其他媒体特性,尽管媒体查询规范级别 4 和 5 中引入的一些较新特性具有有限的浏览器支持。每个特性都在 MDN 上有文档,并附带浏览器支持信息,你可以在使用媒体查询:语法中找到完整的列表。
方向
一个支持良好的媒体特性是 orientation,它允许我们测试纵向或横向。要更改设备处于横向时正文文本的颜色,请使用以下媒体查询。
@media (orientation: landscape) {
body {
color: rebeccapurple;
}
}
上面的示例很难在页面内测试;要查看其效果,建议你将上面的代码复制到本地 HTML 文件中,并在自己的标签页中打开它。
标准的桌面视图具有横向,在这种方向下效果良好的设计在手机或平板电脑的纵向模式下可能效果不佳。测试方向可以帮助你创建针对纵向模式设备优化的布局。
指向设备的使用
作为 Level 4 规范的一部分,引入了 hover 媒体特性。此特性意味着你可以测试用户是否能够悬停在元素上,这实际上意味着他们正在使用某种指向设备;触摸屏和键盘导航不支持悬停。
@media screen and (hover: hover) {
body:hover {
color: white;
background: black;
}
}
上面的示例在悬停时文本变为白色,背景变为黑色,但仅在支持悬停的设备上。如果我们知道用户不能悬停,我们可以默认显示一些交互功能。对于可以悬停的用户,我们可以选择在链接悬停时使其可用。
在 Level 4 中还有 pointer 媒体特性。它有三个可能的值:none、fine 和 coarse。fine 指针类似于鼠标或触控板。它使用户能够精确地定位小区域。coarse 指针是触摸屏上的手指。值 none 表示用户没有指向设备;也许他们只使用键盘或语音命令进行导航。
使用 pointer 可以帮助你设计更好的界面,以响应用户与屏幕的交互类型。例如,如果你知道用户正在以触摸屏方式与设备交互,则可以创建更大的点击区域。
使用范围语法
一个常见的情况是检查视口宽度是否在两个值之间
@media (min-width: 30em) and (max-width: 50em) {
/* … */
}
如果你想提高可读性,可以使用“范围”语法
@media (30em <= width <= 50em) {
/* … */
}
因此,在这种情况下,当视口宽度在 30em 和 50em 之间时,样式将被应用。
更复杂的媒体查询
对于所有这些不同的媒体查询,你可能想要组合它们,或者创建查询列表 — 任何一个都可能匹配。
和以前一样,尝试通过调整浏览器宽度来测试本节中的示例。
媒体查询中的“and”逻辑
为了组合媒体特性,你可以使用 and,就像我们上面使用 and 组合媒体类型和特性一样。例如,我们可能需要测试 width 和 orientation。只有当视口宽度至少为 600 像素且设备处于横向模式时,正文文本才会变为蓝色。
@media screen and (width >= 600px) and (orientation: landscape) {
body {
color: blue;
}
}
媒体查询中的“or”逻辑
如果你有一组查询,其中任何一个都可以匹配,那么你可以用逗号分隔这些查询。在下面的示例中,如果视口宽度至少为 600 像素或者设备处于横向,则文本将变为蓝色。如果其中任何一个条件为真,则查询匹配。
@media screen and (width >= 600px), screen and (orientation: landscape) {
body {
color: blue;
}
}
媒体查询中的“not”逻辑
你可以使用 not 运算符来否定整个媒体查询。这会反转整个媒体查询的含义。因此,在下一个示例中,只有当视口宽度不至少为 600 像素时,文本才会变为蓝色。
@media not (width >= 600px) {
body {
color: blue;
}
}
你还可以使用 not 来否定特定的表达式。
@media (not (width < 600px)) and (not (width > 1000px)) {
body {
color: blue;
}
}
如果视口宽度在 600 到 1000 像素之间,这将应用样式。这相当于 (600px <= width <= 1000px)。
如何选择断点
在响应式设计的早期,许多设计师会尝试针对非常具体的屏幕尺寸。流行手机和平板电脑的屏幕尺寸列表被发布,以便可以创建设计来精确匹配这些视口。
现在设备种类繁多,尺寸也千差万别,这使得这种做法不再可行。这意味着,与其为所有设计针对特定尺寸,不如在内容开始出现某种程度的“破裂”时改变设计。也许行长变得过长,或者侧边栏被挤压得难以阅读。这就是你需要使用媒体查询来改变设计,使其更适合可用空间的时候。这种方法意味着无论使用的设备尺寸确切是多少,都无关紧要;每个范围都得到了照顾。引入媒体查询的点称为断点。
Firefox DevTools 中的响应式设计模式对于确定这些断点的位置非常有用。你可以轻松地缩小和放大视口,以查看在何处通过添加媒体查询和调整设计来改进内容。

移动优先的响应式设计
大体上,响应式设计有两种方法。你可以从桌面或最宽的视图开始,然后随着视口变小而添加断点来移动元素;或者你可以从最小的视图开始,然后随着视口变大而添加布局。后一种方法被称为移动优先响应式设计,通常是最好的方法。
最小设备的视图通常是一个简单的单列内容,就像它出现在正常流中一样。这意味着你可能不需要为小型设备做很多布局——组织好你的源代码,默认情况下你将获得一个可读的布局。
创建自己的移动优先设计
现在轮到你了;在本教程部分,你将构建自己的基本移动优先响应式设计。在生产站点中,你可能需要在媒体查询中调整更多内容,但方法将完全相同。
入门
我们的起点是一个 HTML 文档,其中应用了一些 CSS,为布局的各个部分添加了背景颜色。
首先,将下方代码块中的 HTML 代码复制到文本编辑器中,将其保存为计算机上的 HTML 文件,然后在浏览器中打开它。
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Media Queries: a simple mobile first design, step 1</title>
<style>
/* Add styles here */
</style>
</head>
<div class="wrapper">
<header>
<nav>
<ul>
<li><a href="">About</a></li>
<li><a href="">Contact</a></li>
<li><a href="">Meet the team</a></li>
<li><a href="">Blog</a></li>
</ul>
</nav>
</header>
<main>
<article>
<div class="content">
<h1>Veggies!</h1>
<p>
Veggies es bonus vobis, proinde vos postulo essum magis kohlrabi welsh
onion daikon amaranth tatsoi tomatillo melon azuki bean garlic.
</p>
<p>
Gumbo beet greens corn soko endive gumbo gourd. Parsley shallot
courgette tatsoi pea sprouts fava bean collard greens dandelion okra
wakame tomato. Dandelion cucumber earthnut pea peanut soko zucchini.
</p>
<p>
Turnip greens yarrow ricebean rutabaga endive cauliflower sea lettuce
kohlrabi amaranth water spinach avocado daikon napa cabbage asparagus
winter purslane kale. Celery potato scallion desert raisin horseradish
spinach carrot soko. Lotus root water spinach fennel kombu maize
bamboo shoot green bean swiss chard seakale pumpkin onion chickpea
gram corn pea. Brussels sprout coriander water chestnut gourd swiss
chard wakame kohlrabi beetroot carrot watercress. Corn amaranth
salsify bunya nuts nori azuki bean chickweed potato bell pepper
artichoke.
</p>
<p>
Nori grape silver beet broccoli kombu beet greens fava bean potato
quandong celery. Bunya nuts black-eyed pea prairie turnip leek lentil
turnip greens parsnip. Sea lettuce lettuce water chestnut eggplant
winter purslane fennel azuki bean earthnut pea sierra leone bologi
leek soko chicory celtuce parsley jícama salsify.
</p>
</div>
<aside class="related">
<p>
All these veggies are brought to you by the
<a href="https://veggieipsum.com/">Veggie Ipsum generator</a>.
</p>
</aside>
</article>
<aside class="sidebar">
<h2>External vegetable-based links</h2>
<ul>
<li>
<a
href="https://www.thekitchn.com/how-to-cook-broccoli-5-ways-167323">
How to cook broccoli
</a>
</li>
<li>
<a href="https://www.bbcgoodfood.com/glossary/swiss-chard">
Swiss Chard
</a>
</li>
<li>
<a
href="https://www.bbcgoodfood.com/recipes/collection/christmas-parsnip">
Christmas Parsnip Recipes
</a>
</li>
</ul>
</aside>
</main>
<footer>
<p>© 2024</p>
</footer>
</div>
文档的源代码以一种使内容可读的方式进行排序。这是重要的第一步,它确保了即使内容被屏幕阅读器朗读,也能被理解。
我们示例的初始样式如下;将它们复制到你的 HTML 文件中 <style></style> 标签内,替换 /* Add styles here */ 注释。
* {
box-sizing: border-box;
}
body {
width: 90%;
margin: 2em auto;
font:
1em/1.3 "Helvetica",
"Arial",
sans-serif;
}
a:link,
a:visited {
color: #333333;
}
nav ul,
aside ul {
list-style: none;
padding: 0;
}
nav a:link,
nav a:visited {
background-color: rgb(207 232 220 / 20%);
border: 2px solid rgb(79 185 227);
text-decoration: none;
display: block;
padding: 10px;
color: #333333;
font-weight: bold;
}
nav a:hover {
background-color: rgb(207 232 220 / 70%);
}
.related {
background-color: rgb(79 185 227 / 30%);
border: 1px solid rgb(79 185 227);
padding: 10px;
}
.sidebar {
background-color: rgb(207 232 220 / 50%);
padding: 10px;
}
article {
margin-bottom: 1em;
}
如果你在开发者工具的响应式设计模式中查看布局,或者将浏览器窗口缩小到类似手机的宽度,你会发现它作为一个简单的网站移动视图运行得相当好。
为中等宽度创建两列布局
将窗口拖宽,直到你看到行长变得相当长;此时你就有空间让导航横向显示。这就是我们将添加第一个媒体查询的地方。我们将使用 em 单位,这意味着如果用户增加了文本大小,断点将在相似的行长但更宽的视口处发生,而不是文本大小较小的用户。
将以下内容添加到你的 CSS 底部
@media screen and (width >= 40em) {
article {
display: grid;
grid-template-columns: 3fr 1fr;
column-gap: 20px;
}
nav ul {
display: flex;
}
nav li {
flex: 1;
}
}
此 CSS 为 <article> 内部的文章内容和 <aside> 元素中的相关信息提供了一个两列布局。我们还使用了 flexbox 将导航放在一行中。
为更宽的屏幕添加第三列
让我们继续扩大宽度,直到我们觉得有足够的空间让侧边栏也形成一个新列。在一个媒体查询中,我们将把 <main> 元素变成一个两列网格。然后我们需要移除文章上的 margin-bottom,以便两个侧边栏相互对齐,并且我们会在页脚顶部添加一个 border。通常,这些小的调整就是你为了让设计在每个断点处看起来美观而会做的事情。
将以下内容添加到你的 CSS 底部
@media screen and (width >= 70em) {
main {
display: grid;
grid-template-columns: 3fr 1fr;
column-gap: 20px;
}
article {
margin-bottom: 0;
}
footer {
border-top: 1px solid #cccccc;
margin-top: 2em;
}
}
示例已完成。如果你以不同宽度查看结果,你可以看到设计如何根据可用宽度响应并以单列、两列或三列工作。这是一个移动优先响应式设计的简单示例。
视口元标签
如果你查看上面示例中的 HTML 源代码,你会看到文档头部包含了以下元素
<meta name="viewport" content="width=device-width,initial-scale=1" />
这是 viewport 元标签 — 它的存在是为了控制移动浏览器如何渲染内容,确保它们尊重你的媒体查询。上面的标签告诉移动浏览器“不要以 980 像素的视口渲染内容 — 而是使用真实的设备宽度渲染,并设置一个默认的初始缩放级别以获得更好的一致性。” 然后媒体查询将按预期启动。
有关为什么需要此内容的更多信息,请参阅上一篇文章中的视口元标签部分。
你真的需要媒体查询吗?
Flexbox 和 CSS Grid 提供了无需媒体查询即可创建灵活甚至响应式组件的方法:始终值得考虑是否真的需要一个。例如,你可能需要一组至少 200 像素宽的卡片,并尽可能多地将这些 200 像素的卡片横跨主内容列排列,无论其宽度如何。
这可以通过 CSS Grid 实现,完全不需要媒体查询
<ul class="grid">
<li>
<h2>Card 1</h2>
<p>…</p>
</li>
<li>
<h2>Card 2</h2>
<p>…</p>
</li>
<li>
<h2>Card 3</h2>
<p>…</p>
</li>
<li>
<h2>Card 4</h2>
<p>…</p>
</li>
<li>
<h2>Card 5</h2>
<p>…</p>
</li>
</ul>
body {
font: 1.2em / 1.5 sans-serif;
}
.grid {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: 20px;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
.grid li {
border: 1px solid #666666;
padding: 10px;
}
尝试放大和缩小浏览器窗口,查看列轨道的数量变化。
这种方法的好处是网格不关注视口宽度,而是关注它为该组件可用的宽度。用一个建议你可能根本不需要媒体查询来结束一个关于媒体查询的部分,这可能看起来很奇怪!然而,在实践中你会发现,结合媒体查询良好地使用现代布局方法,将产生最佳效果。
总结
在本课中,你学习了媒体查询,并发现了如何在实践中使用它们来创建移动优先的响应式设计。
你可以使用我们创建的起点来测试更多的媒体查询。例如,你也许可以使用 pointer 媒体特性,在检测到访问者拥有粗糙指针时更改导航的大小。
你还可以尝试添加不同的组件,并查看是添加媒体查询,还是使用 flexbox 或 grid 等布局方法,是使组件具有响应性的最合适方式。很多时候没有对错之分——你应该尝试并看看哪种方法最适合你的设计和内容。
好的,我们快要结束这个模块了。在下一篇文章中,我们将提供一些测试,你可以用来检查自己对前面几篇文章中提供的所有响应式网页设计和媒体查询信息的理解和掌握程度。