媒体查询入门指南

CSS 媒体查询为你提供了一种方式,仅在浏览器和设备环境与你指定的规则匹配时才应用 CSS,例如“视窗宽度大于 480 像素”。媒体查询是响应式 Web 设计的关键部分,因为它们允许你根据视窗大小创建不同的布局,但它们也可以用来检测运行网站的环境的其他方面,例如用户是使用触摸屏还是鼠标。在本课中,你将首先了解媒体查询中使用的语法,然后继续在一个工作示例中使用它们,展示如何使一个简单的设计变得响应式。

先决条件 HTML 基础知识(学习HTML 简介),以及对 CSS 工作原理的了解(学习CSS 入门CSS 构建块)。
目标 了解如何使用媒体查询,以及使用它们创建响应式设计的最常见方法。

媒体查询基础

最简单的媒体查询语法如下所示

css
@media media-type and (media-feature-rule) {
  /* CSS rules go here */
}

它由以下部分组成

  • 媒体类型,它告诉浏览器此代码适用于哪种媒体(例如,print 或 screen)。
  • 媒体表达式,它是一个规则或测试,必须通过才能应用包含的 CSS。
  • 一组 CSS 规则,如果测试通过且媒体类型正确,则将应用这些规则。

媒体类型

你可以指定的媒体类型包括

  • all
  • print
  • screen

以下媒体查询仅在打印页面时将 body 设置为 12pt。在浏览器中加载页面时不会应用它。

css
@media print {
  body {
    font-size: 12pt;
  }
}

注意:这里的媒体类型不同于所谓的MIME 类型

注意:级别 3 媒体查询规范中定义了许多其他媒体类型;这些类型已被弃用,应该避免使用。

注意:媒体类型是可选的;如果你在媒体查询中没有指定媒体类型,则媒体查询将默认适用于所有媒体类型。

媒体特性规则

指定类型后,你可以使用规则针对媒体特性。

宽度和高度

我们最常检测的特性,以便创建响应式设计(并且具有广泛的浏览器支持)是视窗宽度,我们可以使用 min-widthmax-widthwidth 媒体特性,在视窗宽度高于或低于某个特定宽度(或确切宽度)时应用 CSS。

这些特性用于创建响应不同屏幕尺寸的布局。例如,如果视窗宽度恰好为 600 像素,则将 body 文本颜色更改为红色,可以使用以下媒体查询。

css
@media screen and (width: 600px) {
  body {
    color: red;
  }
}

在浏览器中打开此示例,或查看源代码

width(和height)媒体特征可以用作范围,因此可以加前缀min-max-来表示给定值是最小值或最大值。例如,如果视窗宽度为 600 像素或更窄,则将颜色设置为蓝色,使用max-width

css
@media screen and (max-width: 600px) {
  body {
    color: blue;
  }
}

在浏览器中打开此示例,或查看源代码

在实际应用中,使用最小值或最大值对于响应式设计更有用,因此您很少会看到单独使用widthheight

您可以测试许多其他媒体特征,尽管媒体查询规范第 4 级和第 5 级中引入的一些较新特征的浏览器支持有限。每个特征在 MDN 上都有记录,以及浏览器支持信息,您可以在使用媒体查询:语法中找到完整的列表。

方向

一个得到良好支持的媒体特征是orientation,它允许我们测试纵向或横向模式。如果设备处于横向模式,则更改正文文本颜色,请使用以下媒体查询。

css
@media (orientation: landscape) {
  body {
    color: rebeccapurple;
  }
}

在浏览器中打开此示例,或查看源代码

标准桌面视图具有横向方向,而在此方向上效果良好的设计在手机或平板电脑上以纵向模式查看时可能效果不佳。测试方向可以帮助您创建针对纵向模式设备优化的布局。

指向设备的使用

作为第 4 级规范的一部分,引入了hover媒体特征。此特征意味着您可以测试用户是否能够将鼠标悬停在元素上,这实际上意味着他们使用的是某种指向设备;触摸屏和键盘导航不会悬停。

css
@media (hover: hover) {
  body {
    color: rebeccapurple;
  }
}

在浏览器中打开此示例,或查看源代码

如果我们知道用户无法悬停,我们可以默认显示一些交互式功能。对于可以悬停的用户,我们可能选择在将鼠标悬停在链接上时使其可用。

第 4 级中还有pointer媒体特征。它接受三个可能的值,nonefinecoarsefine指针是像鼠标或触控板这样的东西。它使用户能够精确地定位一个小区域。coarse指针是您在触摸屏上的手指。none值表示用户没有指向设备;也许他们只使用键盘或语音命令进行导航。

使用pointer可以帮助您设计更好的界面,以响应用户与屏幕交互的方式。例如,如果您知道用户正在以触摸屏的方式与设备交互,则可以创建更大的点击区域。

使用范围语法

一个常见的例子是检查视窗宽度是否在两个值之间

css
@media (min-width: 30em) and (max-width: 50em) {
  /* … */
}

如果您想提高可读性,可以使用“范围”语法

css
@media (30em <= width <= 50em) {
  /* … */
}

因此,在这种情况下,当视窗宽度在30em50em之间时,将应用样式。

更复杂的媒体查询

对于所有可能的媒体查询,您可能希望将它们组合起来,或创建查询列表——任何一个都可能匹配。

“and”逻辑在媒体查询中

要组合媒体特征,您可以使用and,就像我们上面使用and来组合媒体类型和特征一样。例如,我们可能希望测试min-widthorientation。只有当视窗宽度至少为 600 像素且设备处于横向模式时,正文文本才会变为蓝色。

css
@media screen and (min-width: 600px) and (orientation: landscape) {
  body {
    color: blue;
  }
}

在浏览器中打开此示例,或查看源代码

“or”逻辑在媒体查询中

如果您有一组查询,其中任何一个都可能匹配,那么您可以用逗号分隔这些查询。在下面的示例中,如果视窗宽度至少为 600 像素或设备处于横向模式,则文本将变为蓝色。如果这两个条件中的任何一个为真,则查询匹配。

css
@media screen and (min-width: 600px), screen and (orientation: landscape) {
  body {
    color: blue;
  }
}

在浏览器中打开此示例,或查看源代码

“not”逻辑在媒体查询中

您可以使用not运算符否定整个媒体查询。这将颠倒整个媒体查询的含义。因此,在下一个示例中,只有当方向为纵向时,文本才会变为蓝色。

css
@media not (orientation: landscape) {
  body {
    color: blue;
  }
}

在浏览器中打开此示例,或查看源代码

您还可以使用not来否定特定表达式。

css
@media (not (width < 600px)) and (not (width > 1000px)) {
  body {
    color: blue;
  }
}

如果视窗宽度在 600 和 1000 像素之间,这将应用样式。这等效于(600px <= width <= 1000px)

如何选择断点

在响应式设计的早期,许多设计师会尝试针对非常具体的屏幕尺寸。发布了流行手机和平板电脑屏幕尺寸的列表,以便可以创建与这些视窗完美匹配的设计。

现在有太多设备,尺寸差异很大,无法实现这一点。这意味着,与其为所有设计针对特定尺寸,不如在内容开始以某种方式中断的尺寸更改设计。也许行长变得太长,或者一个框起来的侧边栏被挤压,难以阅读。这就是您需要使用媒体查询来更改设计以适应可用空间的最佳点。这种方法意味着,无论使用的设备的确切尺寸如何,每个范围都得到了照顾。引入媒体查询的点被称为**断点**。

Firefox DevTools 中的响应式设计模式对于确定这些断点应该在哪里非常有用。您可以轻松地使视窗变小或变大,以查看在何处添加媒体查询并调整设计可以改善内容。

A screenshot of a layout in a mobile view in Firefox DevTools.

主动学习:移动优先响应式设计

总的来说,您可以采取两种方法进行响应式设计。您可以从桌面或最宽的视图开始,然后添加断点,随着视窗变小,将内容移动到其他位置,或者您可以从最小的视图开始,随着视窗变大,添加布局。第二种方法被称为**移动优先**响应式设计,通常是最佳方法。

对于最小的设备,视图通常是简单的一列内容,就像它在普通流中显示的一样。这意味着您可能不需要为小型设备进行很多布局——将源代码排序好,您默认情况下将拥有可读的布局。

下面的演练将带您了解这种方法,使用非常简单的布局。在生产站点中,您可能需要在媒体查询中调整更多内容,但是方法完全相同。

演练:一个简单的移动优先布局

我们的起点是一个 HTML 文档,其中应用了一些 CSS 来为布局的各个部分添加背景颜色。

css
* {
  box-sizing: border-box;
}

body {
  width: 90%;
  margin: 2em auto;
  font:
    1em/1.3 Arial,
    Helvetica,
    sans-serif;
}

a:link,
a:visited {
  color: #333;
}

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: #333;
  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;
}

我们没有进行任何布局更改,但是文档的源代码是按可读的方式排序的。这是重要的第一步,它确保如果内容要由屏幕阅读器读出,它将是可理解的。

html
<body>
  <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></p>
        </div>
        <aside class="related">
          <p></p>
        </aside>
      </article>

      <aside class="sidebar">
        <h2>External vegetable-based links</h2>
        <ul>
          <li></li>
        </ul>
      </aside>
    </main>

    <footer><p>&copy;2019</p></footer>
  </div>
</body>

这个简单的布局在移动设备上也能很好地工作。如果我们在 DevTools 中的响应式设计模式中查看布局,我们可以看到它作为站点的简单移动视图效果很好。

在浏览器中打开第 1 步,或查看源代码

如果您想继续并实施此示例,请在您的计算机上创建一个step1.html的本地副本。

从这一点开始,开始将响应式设计模式视图拖得更宽,直到您看到行长变得相当长,并且我们有空间让导航以水平线显示。在这里,我们将添加第一个媒体查询。我们将使用 em,这意味着如果用户增加了他们的文本大小,断点将在与文本大小较小的人相同的行长,但更宽的视窗处发生。

将以下代码添加到 step1.html CSS 的底部。

css
@media screen and (min-width: 40em) {
  article {
    display: grid;
    grid-template-columns: 3fr 1fr;
    column-gap: 20px;
  }

  nav ul {
    display: flex;
  }

  nav li {
    flex: 1;
  }
}

此 CSS 在文章内部为我们提供了一个两列布局,即文章内容和aside元素中的相关信息。我们还使用 flexbox 将导航放置在一行中。

在浏览器中打开第 2 步,或查看源代码

让我们继续扩展宽度,直到我们感觉有足够的空间让侧边栏也形成一个新的列。在媒体查询内部,我们将main元素做成一个两列网格。然后,我们需要删除article上的margin-bottom,以便两个侧边栏相互对齐,我们将在页脚顶部添加一个border。通常,这些小调整是您为使设计在每个断点处看起来不错而需要做的事情。

同样,将以下代码添加到 step1.html CSS 的底部。

css
@media screen and (min-width: 70em) {
  main {
    display: grid;
    grid-template-columns: 3fr 1fr;
    column-gap: 20px;
  }

  article {
    margin-bottom: 0;
  }

  footer {
    border-top: 1px solid #ccc;
    margin-top: 2em;
  }
}

在浏览器中打开第 3 步,或查看源代码

如果您以不同的宽度查看最终示例,您会看到设计是如何响应的,并作为一列、两列或三列工作,具体取决于可用宽度。这是一个非常简单的移动优先响应式设计的示例。

视窗元标签

如果您查看上面示例中的 HTML 源代码,您会看到以下元素包含在文档的头部

html
<meta name="viewport" content="width=device-width,initial-scale=1" />

这是视窗元标记——它作为一种控制移动浏览器渲染内容的方式存在。这是必要的,因为默认情况下,大多数移动浏览器会撒谎他们的视窗宽度。非响应式网站在窄视窗中渲染时通常看起来很糟糕,因此移动浏览器通常默认情况下使用比实际设备宽度更宽的视窗宽度(通常为 980 像素)渲染网站,然后缩小渲染结果以使其适合显示。

这很好,但这意味着响应式网站将无法按预期工作。如果视窗宽度报告为 980 像素,那么移动布局(例如使用@media screen and (max-width: 600px) { }创建的布局)将无法按预期渲染。

为了解决这个问题,在您的页面上包含像上面的视窗元标记这样的标记会告诉浏览器“不要使用 980 像素的视窗渲染内容——而是使用实际设备宽度渲染,并设置默认的初始缩放级别,以获得更好的一致性。”然后,媒体查询将按预期生效。

您可以在视窗元标记的content属性中放置许多其他选项——有关更多详细信息,请参阅使用视窗元标记来控制移动浏览器上的布局

你真的需要媒体查询吗?

Flexbox、Grid 和多列布局都为您提供了创建灵活甚至响应式组件的方法,而无需使用媒体查询。总是值得考虑这些布局方法是否可以在不添加媒体查询的情况下实现您想要的结果。例如,您可能希望有一组卡,它们至少有 200 像素宽,这些 200 像素尽可能多地适合主文章。这可以使用网格布局来实现,根本不使用媒体查询。

这可以通过以下方法实现

html
<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>
css
.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 #666;
  padding: 10px;
}

在浏览器中打开网格布局示例,或查看源代码

在浏览器中打开示例后,使屏幕变宽或变窄,以查看列轨道数量的变化。这种方法的好处在于,网格不是在查看视窗宽度,而是在查看它为此组件可用的宽度。这似乎很奇怪,在关于媒体查询的文章末尾建议您可能根本不需要它!但是,在实际操作中,您会发现,良好地使用现代布局方法,并使用媒体查询进行增强,将产生最佳效果。

测试你的技能!

您已经读完了这篇文章,但是您还记得最重要的信息吗?您可以在继续之前找到一个测试来验证您是否保留了这些信息——请参阅测试您的技能:响应式网页设计和媒体查询

总结

在本课中,您学习了媒体查询,并了解了如何将它们应用于实践,以创建移动优先响应式设计。

您可以使用我们创建的起点来测试更多媒体查询。例如,也许您可以使用pointer媒体特征,在检测到访问者具有粗指针时更改导航的大小。

您还可以尝试添加不同的组件,并查看添加媒体查询还是使用 Flexbox 或 Grid 这样的布局方法是使组件响应的最合适方式。通常情况下,没有正确或错误的方法——您应该尝试一下,看看哪种方法最适合您的设计和内容。