Skip to content

媒体查询:响应式设计的基石

想象你是一位服装设计师,你的任务是为不同身材的顾客设计合身的衣服。你不可能让所有人都穿同一个尺码——你需要为不同体型的人准备不同的版本。在 Web 开发中,CSS 媒体查询(Media Queries)就扮演着类似的角色:它能让你的网站根据不同设备的特性自动调整样式,确保在手机、平板、桌面电脑上都能完美呈现。

媒体查询是什么?

媒体查询是 CSS3 引入的一项强大功能,它允许你根据设备的特性(如屏幕宽度、高度、分辨率、方向等)来应用不同的样式规则。简单来说,媒体查询就像一个智能开关:当设备满足特定条件时,相应的样式就会被激活;不满足时,这些样式就会被忽略。

在媒体查询出现之前,开发者要想适配不同设备,往往需要创建多个版本的页面,维护成本极高。媒体查询的出现彻底改变了这一局面,让一套代码适配多端成为可能。

基本语法

媒体查询的基本语法结构如下:

css
/* 基础语法 */
@media media-type and (media-feature) {
  /* 当条件满足时应用的样式 */
  .element {
    property: value;
  }
}

让我们看一个实际例子:

css
/* 当屏幕宽度小于或等于 768px 时 */
@media screen and (max-width: 768px) {
  .container {
    width: 100%;
    padding: 10px;
  }

  .sidebar {
    display: none; /* 在小屏幕上隐藏侧边栏 */
  }
}

这个媒体查询的含义是:当用户使用屏幕设备(screen)并且屏幕宽度不超过 768px 时,应用大花括号内的样式规则。在这个例子中,容器会占据全部宽度,侧边栏会被隐藏,从而为小屏幕提供更好的用户体验。

媒体类型

媒体类型用于指定设备的类别。虽然 CSS 规范定义了多种媒体类型,但在实际开发中最常用的有:

screen - 屏幕设备

这是最常用的媒体类型,适用于电脑屏幕、平板、手机等所有屏幕设备:

css
@media screen {
  body {
    font-family: Arial, sans-serif;
  }
}

当用户打印页面时应用这些样式。打印样式通常会隐藏导航栏、侧边栏等非必要元素,优化纸张使用:

css
@media print {
  .navigation,
  .sidebar,
  .footer {
    display: none; /* 打印时移除这些元素 */
  }

  body {
    font-size: 12pt; /* 打印使用点(pt)单位更合适 */
    color: black;
    background: white;
  }
}

all - 所有设备

适用于所有媒体类型。如果不指定媒体类型,默认就是 all

css
/* 这两种写法效果相同 */
@media all and (min-width: 600px) {
}
@media (min-width: 600px) {
}

在现代开发中,由于 screen 涵盖了绝大多数场景,很多开发者会省略媒体类型,直接写媒体特性。

媒体特性

媒体特性是媒体查询的核心,它们描述了设备的具体特征。让我们详细了解最常用的几种。

宽度相关特性

max-width - 最大宽度

当视口宽度小于或等于指定值时匹配:

css
/* 适配移动设备:屏幕宽度不超过 480px */
@media (max-width: 480px) {
  .header {
    font-size: 18px;
  }

  .content {
    padding: 8px;
  }
}

假设用户用手机访问(屏幕宽度 375px),由于 375 ≤ 480,这些样式就会生效。但如果用户用桌面电脑访问(屏幕宽度 1920px),这些样式就不会应用。

min-width - 最小宽度

当视口宽度大于或等于指定值时匹配:

css
/* 适配大屏设备:屏幕宽度至少 1024px */
@media (min-width: 1024px) {
  .container {
    max-width: 1200px;
    margin: 0 auto; /* 居中容器 */
  }

  .sidebar {
    width: 300px;
    float: left;
  }
}

当屏幕宽度为 1440px 时,由于 1440 ≥ 1024,这些样式会生效,页面会显示侧边栏并使用更宽松的布局。

width - 精确宽度

精确匹配特定宽度(实际应用中很少使用,因为难以精确控制):

css
@media (width: 768px) {
  /* 只有屏幕宽度恰好是 768px 时才生效 */
}

高度相关特性

高度特性与宽度特性类似,但针对的是视口高度:

css
/* 当视口高度较小时(如横屏手机) */
@media (max-height: 500px) {
  .header {
    height: 50px; /* 缩小头部高度 */
  }

  .content {
    padding-top: 10px; /* 减少内边距以节省垂直空间 */
  }
}

这在处理横屏设备时特别有用,可以帮助你优化垂直空间的利用。

orientation - 设备方向

检测设备是横屏还是竖屏:

css
/* 竖屏(portrait):高度大于宽度 */
@media (orientation: portrait) {
  .gallery {
    grid-template-columns: 1fr 1fr; /* 两列布局 */
  }
}

/* 横屏(landscape):宽度大于高度 */
@media (orientation: landscape) {
  .gallery {
    grid-template-columns: repeat(4, 1fr); /* 四列布局 */
  }
}

当用户旋转手机从竖屏切换到横屏时,图片画廊会自动从两列变成四列,充分利用横向空间。

aspect-ratio - 宽高比

检测视口的宽高比:

css
/* 16:9 宽屏显示器 */
@media (aspect-ratio: 16/9) {
  .video-container {
    width: 100%;
  }
}

/* 最小宽高比 */
@media (min-aspect-ratio: 1/1) {
  /* 宽度大于等于高度时 */
}

resolution - 分辨率

用于检测设备的像素密度,常用于适配高清屏幕(如 Retina 显示屏):

css
/* 标准屏幕 */
.logo {
  background-image: url("logo-1x.png");
}

/* 高清屏幕(2倍像素密度) */
@media (min-resolution: 192dpi), (min-resolution: 2dppx) {
  .logo {
    background-image: url("logo-2x.png");
    background-size: 100px 50px; /* 显示大小保持不变 */
  }
}

在 iPhone 或 MacBook 等视网膜屏幕上,这段代码会加载高分辨率的图片,确保图标清晰锐利。

逻辑运算符

媒体查询支持逻辑运算符,让你可以组合多个条件。

and - 逻辑与

所有条件都必须满足:

css
/* 必须同时满足:屏幕设备 + 宽度在 600px 到 900px 之间 */
@media screen and (min-width: 600px) and (max-width: 900px) {
  .container {
    width: 90%;
    padding: 20px;
  }
}

只有当用户使用屏幕设备,并且视口宽度在 600px 至 900px 之间时,这些样式才会生效。如果宽度是 500px 或 1000px,样式都不会应用。

, (逗号) - 逻辑或

满足任一条件即可,相当于"或"运算:

css
/* 宽度小于 480px 或 大于 1200px 时都应用 */
@media (max-width: 480px), (min-width: 1200px) {
  .responsive-text {
    font-size: 14px;
  }
}

这在同时适配移动端和超大屏时很有用——两种极端情况可以共享相同的样式处理。

not - 逻辑非

排除特定条件:

css
/* 非屏幕设备(如打印) */
@media not screen {
  body {
    background: white;
    color: black;
  }
}

/* 宽度不在 600px 到 900px 之间 */
@media not all and (min-width: 600px) and (max-width: 900px) {
  /* 只在宽度 < 600px 或 > 900px 时生效 */
}

需要注意的是,not 会否定整个媒体查询,而不是单个条件。

only - 限定符

only 主要用于兼容旧浏览器,防止不支持媒体查询的浏览器错误应用样式:

css
@media only screen and (min-width: 768px) {
  /* 只有支持媒体查询的屏幕设备会应用这些样式 */
}

在现代开发中,由于旧浏览器已经很少见,only 的使用频率已经降低。

实际应用场景

响应式导航栏

让我们看一个完整的例子,展示如何用媒体查询创建响应式导航栏:

css
/* 默认样式(桌面端) */
.navbar {
  display: flex;
  justify-content: space-between;
  padding: 15px 30px;
  background-color: #333;
}

.nav-menu {
  display: flex;
  gap: 20px;
  list-style: none;
}

.nav-toggle {
  display: none; /* 桌面端隐藏汉堡菜单按钮 */
}

/* 平板端:768px 到 1024px */
@media (min-width: 768px) and (max-width: 1024px) {
  .navbar {
    padding: 12px 20px;
  }

  .nav-menu {
    gap: 15px;
    font-size: 14px;
  }
}

/* 移动端:小于 768px */
@media (max-width: 767px) {
  .navbar {
    flex-direction: column;
    padding: 10px 15px;
  }

  .nav-toggle {
    display: block; /* 显示汉堡菜单按钮 */
    cursor: pointer;
  }

  .nav-menu {
    display: none; /* 默认隐藏菜单 */
    flex-direction: column;
    width: 100%;
    gap: 0;
  }

  .nav-menu.active {
    display: flex; /* 点击按钮后显示 */
  }

  .nav-menu li {
    padding: 12px 0;
    border-bottom: 1px solid #555;
  }
}

在这个例子中:

  • 桌面端(宽度 ≥ 1024px):显示水平导航栏,菜单项并排显示
  • 平板端(768px ≤ 宽度 < 1024px):微调间距和字号,适应中等屏幕
  • 移动端(宽度 < 768px):转为垂直布局,使用汉堡菜单,节省水平空间

响应式网格系统

css
.grid-container {
  display: grid;
  gap: 20px;
  padding: 20px;
}

/* 大屏:4 列 */
@media (min-width: 1200px) {
  .grid-container {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* 中屏:3 列 */
@media (min-width: 900px) and (max-width: 1199px) {
  .grid-container {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* 平板:2 列 */
@media (min-width: 600px) and (max-width: 899px) {
  .grid-container {
    grid-template-columns: repeat(2, 1fr);
    gap: 15px;
  }
}

/* 手机:1 列 */
@media (max-width: 599px) {
  .grid-container {
    grid-template-columns: 1fr;
    gap: 10px;
    padding: 10px;
  }
}

随着屏幕宽度的变化,网格会自动调整列数。在 1400px 的桌面显示器上显示 4 列,在 750px 的平板上显示 2 列,在 375px 的手机上显示 1 列。

嵌套媒体查询

虽然不常见,但在需要时可以嵌套使用媒体查询:

css
@media screen {
  .container {
    padding: 20px;
  }

  @media (max-width: 768px) {
    .container {
      padding: 10px; /* 小屏幕上减少内边距 */
    }
  }
}

不过,现代开发中更推荐使用扁平的、独立的媒体查询,这样更易读易维护。

在 HTML 中使用媒体查询

除了在 CSS 中使用,媒体查询也可以直接在 HTML 的 <link> 标签中使用:

html
<!-- 默认样式表 -->
<link rel="stylesheet" href="base.css" />

<!-- 只在大屏幕上加载 -->
<link rel="stylesheet" href="desktop.css" media="(min-width: 1024px)" />

<!-- 只在小屏幕上加载 -->
<link rel="stylesheet" href="mobile.css" media="(max-width: 767px)" />

<!-- 打印样式 -->
<link rel="stylesheet" href="print.css" media="print" />

这种方式的优势是可以减少不必要的 CSS 下载。例如,在移动设备上访问时,desktop.css 根本不会被下载,节省了带宽。

使用 JavaScript 检测媒体查询

有时你需要在 JavaScript 中根据媒体查询的结果执行不同的逻辑:

javascript
// 创建媒体查询对象
const mediaQuery = window.matchMedia("(max-width: 768px)");

// 检查当前是否匹配
if (mediaQuery.matches) {
  console.log("当前是移动设备");
  // 执行移动端特定逻辑
} else {
  console.log("当前是桌面设备");
}

// 监听媒体查询变化
mediaQuery.addEventListener("change", (e) => {
  if (e.matches) {
    console.log("切换到移动视图");
    // 调整 UI 组件
  } else {
    console.log("切换到桌面视图");
  }
});

这在需要根据屏幕大小动态加载组件、初始化插件或调整交互行为时非常有用。例如,在桌面端使用 hover 效果,在移动端使用 touch 事件。

常见问题与最佳实践

问题 1:媒体查询不生效

最常见的原因是忘记在 HTML 中添加 viewport meta 标签:

html
<!-- 必须添加此标签,否则移动设备会以桌面模式渲染 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

没有这个标签,手机浏览器会假装自己是桌面浏览器(通常 980px 宽),导致你的移动端媒体查询永远不会触发。

问题 2:断点设置混乱

建议使用一致的断点系统,而不是随意设置。推荐使用移动优先的方法(从小到大):

css
/* 推荐:移动优先的断点系统 */
/* 移动端(默认,无需媒体查询) */
/* 0 - 767px */

/* 平板端 */
@media (min-width: 768px) {
  /* 768px 及以上 */
}

/* 桌面端 */
@media (min-width: 1024px) {
  /* 1024px 及以上 */
}

/* 大屏桌面 */
@media (min-width: 1200px) {
  /* 1200px 及以上 */
}

这种移动优先的方式比桌面优先(使用 max-width)更符合现代开发实践,性能也更好。避免使用过多的断点(建议不超过 4-5 个),否则会让代码难以维护。

问题 3:样式覆盖顺序

媒体查询的顺序很重要。如果你使用 min-width(移动优先),应该从小到大排列:

css
/* ✅ 正确:从小到大 */
.container {
  width: 100%;
} /* 基础样式(移动端) */

@media (min-width: 600px) {
  .container {
    width: 90%;
  }
}

@media (min-width: 1024px) {
  .container {
    width: 1000px;
  }
}

如果使用 max-width(桌面优先),应该从大到小排列:

css
/* ✅ 正确:从大到小 */
.container {
  width: 1000px;
} /* 基础样式(桌面端) */

@media (max-width: 1023px) {
  .container {
    width: 90%;
  }
}

@media (max-width: 599px) {
  .container {
    width: 100%;
  }
}

最佳实践建议

  1. 移动优先:优先为小屏幕编写样式,然后用 min-width 逐步增强,这样可以确保移动端性能最优。

  2. 使用相对单位:在媒体查询中使用 emrem 而不是 px,这样当用户调整浏览器默认字号时,断点也会相应调整:

css
/* 使用 em:1em ≈ 16px(浏览器默认) */
@media (min-width: 48em) {
  /* 约 768px */
}
  1. 避免针对特定设备:不要写"iPhone 6 专用"或"iPad 专用"的媒体查询。设备在不断变化,应该基于内容的实际需求设置断点。

  2. 测试真实设备:浏览器开发者工具的设备模拟很有用,但务必在真实设备上测试,因为实际渲染可能有细微差别。

总结

媒体查询是响应式设计的核心工具,它让你能够根据设备特性智能地调整页面样式。通过合理使用媒体类型、媒体特性和逻辑运算符,你可以创建在任何设备上都表现出色的网站。

关键要点:

  • 始终添加 viewport meta 标签
  • 使用标准化的断点系统
  • 注意媒体查询的顺序
  • 优先考虑移动端体验
  • 基于内容而非设备设计断点