CSS3 媒体查询(Media Queries)深度解析与 10 个实战适配案例

8 阅读13分钟

引言:媒体查询的核心价值

在移动互联网主导的时代,用户可能通过 手机、平板、笔记本、桌面显示器 等多种设备访问同一网页。CSS3 媒体查询(Media Queries)作为响应式 Web 设计(Responsive Web Design, RWD)的核心技术,允许开发者根据 设备特性(如屏幕宽度、分辨率、方向) 动态调整 CSS 样式,实现“一套代码适配多端”,无需为不同设备开发独立版本。

媒体查询的本质是:“当满足某个设备条件时,应用对应的 CSS 规则”。它解决了传统固定布局在多设备上“要么溢出、要么留白”的痛点,是现代前端开发的必备技能。

一、媒体查询核心基础

要灵活使用媒体查询,必须先掌握其语法结构、媒体类型、媒体特性与逻辑操作符。

1.1 核心语法

媒体查询通过 @media 规则定义,基本结构如下:

/* 语法格式 */
@media [媒体类型] and (媒体特性: 值) {
  /* 满足条件时应用的 CSS 样式 */
  选择器 { 样式属性: 值; }
}

/* 示例:屏幕宽度 ≥ 1200px 时,设置容器宽度为 1140px */
@media screen and (min-width: 1200px) {
  .container { width: 1140px; }
}
  • 可独立引入外部样式表(适用于样式较多的场景):
    <link rel="stylesheet" media="screen and (max-width: 768px)" href="mobile.css">
    

1.2 媒体类型(Media Type)

指定样式适用的设备类型,目前主流仅需关注 3 种(其他类型如 tvprojection 已极少使用):

媒体类型说明应用场景
all所有设备(默认值,可省略)通用适配
screen彩色屏幕设备(手机、电脑、平板等)绝大多数 Web 场景
print打印机或打印预览模式打印样式优化(如隐藏导航栏)

注意screen 是最常用的类型,且可省略(如 @media (min-width: 768px) 等价于 @media screen and (min-width: 768px))。

1.3 媒体特性(Media Feature)

描述设备的具体属性,需用括号 () 包裹,常见特性如下(重点掌握前 4 个):

媒体特性说明单位示例
width视口(viewport)宽度px、em、rem(min-width: 768px)(视口 ≥ 768px)
height视口高度px、em、rem(max-height: 600px)(视口 ≤ 600px)
device-width设备物理屏幕宽度px不推荐:受设备像素比(DPR)影响,准确性低
orientation设备方向portrait(竖屏)、landscape(横屏)(orientation: landscape)
prefers-color-scheme用户系统颜色偏好light(浅色)、dark(深色)(prefers-color-scheme: dark)
resolution屏幕分辨率dpi、dpcm(min-resolution: 2dppx)(Retina 屏)

关键区别width 是“视口宽度”(浏览器显示内容的区域),device-width 是“设备物理屏幕宽度”。推荐使用 width,因为它更贴合网页实际显示效果。

1.4 逻辑操作符

组合多个条件,实现更精确的适配规则:

  • and:同时满足多个条件(例:screen and (min-width: 768px) and (max-width: 1199px),平板屏幕)。
  • ,(逗号):满足任意一个条件(例:(max-width: 767px), (orientation: portrait),移动端或竖屏)。
  • not:排除某个条件(例:not print,非打印设备)。
  • only:仅当设备完全匹配条件时生效(避免老旧浏览器误解析,例:only screen and (min-width: 768px))。

二、关键工作原理与 Viewport

媒体查询生效的前提是 正确配置 Viewport(视口),否则即使写了媒体查询,也可能出现“样式错乱”。

2.1 浏览器解析流程

  1. 浏览器加载 HTML 时,读取 <meta name="viewport"> 标签,确定视口大小。
  2. 解析 CSS 样式,识别 @media 规则。
  3. 检测当前设备特性(如屏幕宽度、方向),匹配对应的媒体查询条件。
  4. 应用满足条件的 CSS 规则,覆盖默认样式。

2.2 Viewport 元标签的必要性

移动设备默认视口宽度约为 980px(模拟桌面端),若不配置 Viewport,网页会被“缩放”以适应屏幕,导致媒体查询失效。

必须在 HTML 的 <head> 中添加以下代码

<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
  • device-width:让视口宽度等于设备屏幕宽度。
  • initial-scale=1.0:初始缩放比例为 1(无缩放)。
  • shrink-to-fit=no:禁止浏览器自动收缩内容(适配 iOS 设备)。

三、进阶策略:移动优先 vs 桌面优先

媒体查询的适配思路分为两种,选择哪种直接影响代码结构和维护成本。

3.1 移动优先(推荐)

  • 核心逻辑:先写 移动端样式(默认样式),再用 min-width 向上适配平板、PC。
  • 优势:移动设备用户占比高,代码更简洁(避免大量 max-width 覆盖)。
  • 示例
    /* 移动端默认样式(≤ 767px) */
    .container { width: 100%; padding: 0 15px; }
    
    /* 平板(≥ 768px) */
    @media (min-width: 768px) {
      .container { width: 750px; margin: 0 auto; }
    }
    
    /* PC(≥ 1200px) */
    @media (min-width: 1200px) {
      .container { width: 1140px; }
    }
    

3.2 桌面优先

  • 核心逻辑:先写 PC 端样式(默认样式),再用 max-width 向下适配平板、移动端。
  • 劣势:需频繁覆盖 PC 样式,代码冗余度高。
  • 示例
    /* PC 默认样式(≥ 1200px) */
    .container { width: 1140px; margin: 0 auto; }
    
    /* 平板(≤ 1199px) */
    @media (max-width: 1199px) {
      .container { width: 750px; }
    }
    
    /* 移动端(≤ 767px) */
    @media (max-width: 767px) {
      .container { width: 100%; padding: 0 15px; }
    }
    

3.3 两者对比

维度移动优先(min-width)桌面优先(max-width)
默认样式移动端PC 端
适配方向从小到大(向上)从大到小(向下)
代码冗余度低(少覆盖)高(多覆盖)
推荐场景移动端用户为主的项目传统 PC 项目迁移

四、10 个实战适配案例(一套代码适配 H5/PC)

以下案例均采用 移动优先策略,基于行业通用断点:

  • 移动端:≤ 767px
  • 平板:768px ~ 1199px
  • PC:≥ 1200px

每个案例包含 完整 HTML + CSS 代码 及适配逻辑解析。

案例 1:基础两栏/单列布局切换

需求:移动端显示单列内容,PC 端显示“侧边栏+主内容”两栏布局。

<!-- HTML -->
<div class="layout">
  <aside class="sidebar">侧边栏(导航/广告)</aside>
  <main class="content">主内容区域(文章/列表)</main>
</div>
/* CSS:移动优先 */
.layout {
  display: flex;
  flex-direction: column; /* 移动端默认单列 */
  gap: 20px; /* 元素间距 */
  padding: 0 15px;
}

.sidebar, .content {
  padding: 20px;
  border: 1px solid #eee;
}

/* 平板及以上(≥ 768px):两栏布局 */
@media (min-width: 768px) {
  .layout {
    flex-direction: row; /* 横向排列 */
    max-width: 1140px;
    margin: 0 auto;
  }
  .sidebar {
    width: 25%; /* 侧边栏占 25% */
  }
  .content {
    width: 75%; /* 主内容占 75% */
  }
}

/* PC 端(≥ 1200px):优化宽度 */
@media (min-width: 1200px) {
  .layout {
    max-width: 1320px;
  }
}

案例 2:响应式字体大小

需求:屏幕越小,字体越小(避免移动端文字溢出),且保持可读性。

<!-- HTML -->
<div class="text-container">
  <h1>响应式标题</h1>
  <p>这是一段响应式文本,在手机和电脑上的字体大小会自动调整,确保阅读体验。</p>
</div>
/* CSS:移动优先 */
.text-container {
  padding: 0 15px;
}

h1 {
  font-size: 1.8rem; /* 移动端标题大小 */
  margin-bottom: 1rem;
}

p {
  font-size: 1rem; /* 移动端文本大小 */
  line-height: 1.6;
  color: #333;
}

/* 平板(≥ 768px) */
@media (min-width: 768px) {
  h1 { font-size: 2.2rem; }
  p { font-size: 1.1rem; }
}

/* PC(≥ 1200px) */
@media (min-width: 1200px) {
  .text-container {
    max-width: 800px;
    margin: 0 auto;
  }
  h1 { font-size: 2.5rem; }
  p { font-size: 1.2rem; }
}

案例 3:图片自适应与艺术方向

需求:1. 图片宽度自适应容器;2. 移动端显示裁剪后的图片(突出主体),PC 端显示完整图片。

<!-- HTML:用 picture 标签实现“艺术方向” -->
<div class="img-container">
  <picture>
    <!-- 移动端(≤ 767px):加载裁剪图 -->
    <source media="(max-width: 767px)" srcset="image-mobile.jpg">
    <!-- 平板及以上:加载完整图 -->
    <img src="image-desktop.jpg" alt="响应式图片" class="responsive-img">
  </picture>
</div>
/* CSS */
.img-container {
  padding: 0 15px;
  max-width: 1200px;
  margin: 0 auto;
}

.responsive-img {
  width: 100%; /* 图片宽度自适应容器 */
  height: auto; /* 保持宽高比,避免拉伸 */
  border-radius: 8px;
}

案例 4:导航栏(横向 → 汉堡菜单)

需求:移动端显示“汉堡按钮”(点击展开菜单),PC 端显示横向导航。

<!-- HTML -->
<nav class="navbar">
  <!-- 汉堡按钮(移动端显示) -->
  <button class="hamburger" id="hamburger"></button>
  <!-- 导航菜单 -->
  <ul class="nav-menu" id="navMenu">
    <li><a href="#">首页</a></li>
    <li><a href="#">产品</a></li>
    <li><a href="#">关于</a></li>
    <li><a href="#">联系</a></li>
  </ul>
</nav>
/* CSS:移动优先 */
.navbar {
  background-color: #333;
  padding: 0 15px;
}

/* 汉堡按钮(移动端显示) */
.hamburger {
  background: none;
  border: none;
  color: white;
  font-size: 1.5rem;
  padding: 15px 0;
  cursor: pointer;
}

/* 导航菜单(移动端默认隐藏,点击展开) */
.nav-menu {
  list-style: none;
  margin: 0;
  padding: 0;
  display: none; /* 初始隐藏 */
  flex-direction: column;
  gap: 10px;
}

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

.nav-menu a {
  color: white;
  text-decoration: none;
  padding: 10px 0;
  display: block;
}

/* 平板及以上(≥ 768px):隐藏汉堡按钮,显示横向菜单 */
@media (min-width: 768px) {
  .hamburger {
    display: none; /* 隐藏汉堡按钮 */
  }
  .nav-menu {
    display: flex; /* 显示菜单 */
    flex-direction: row; /* 横向排列 */
    gap: 20px;
    padding: 15px 0;
  }
}
// 简单 JS 实现汉堡按钮切换
const hamburger = document.getElementById('hamburger');
const navMenu = document.getElementById('navMenu');

hamburger.addEventListener('click', () => {
  navMenu.classList.toggle('active');
});

案例 5:表格移动端横向滚动

需求:PC 端正常显示表格,移动端表格可横向滚动(避免单元格挤压变形)。

<!-- HTML:给表格外层加容器 -->
<div class="table-container">
  <table class="responsive-table">
    <thead>
      <tr>
        <th>姓名</th>
        <th>年龄</th>
        <th>邮箱</th>
        <th>电话</th>
        <th>地址</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>张三</td>
        <td>25</td>
        <td>zhangsan@example.com</td>
        <td>13800138000</td>
        <td>北京市朝阳区XXX路</td>
      </tr>
      <!-- 更多数据... -->
    </tbody>
  </table>
</div>
/* CSS */
.table-container {
  padding: 0 15px;
  overflow-x: auto; /* 移动端横向滚动 */
  max-width: 1200px;
  margin: 0 auto;
}

.responsive-table {
  width: 100%;
  border-collapse: collapse;
  margin: 20px 0;
}

.responsive-table th,
.responsive-table td {
  padding: 12px 15px;
  border: 1px solid #ddd;
  text-align: left;
}

.responsive-table th {
  background-color: #f5f5f5;
  font-weight: bold;
}

/* PC 端(≥ 1200px):优化样式 */
@media (min-width: 1200px) {
  .table-container {
    overflow-x: visible; /* 取消滚动 */
  }
  .responsive-table tr:hover {
    background-color: #f9f9f9; /*  hover 效果 */
  }
}

案例 6:卡片布局(多列 → 单列)

需求:移动端单列卡片,平板双列,PC 四列,实现“自适应网格”。

<!-- HTML -->
<div class="card-container">
  <div class="card">卡片 1</div>
  <div class="card">卡片 2</div>
  <div class="card">卡片 3</div>
  <div class="card">卡片 4</div>
</div>
/* CSS:移动优先 */
.card-container {
  display: grid;
  grid-template-columns: 1fr; /* 移动端单列 */
  gap: 20px;
  padding: 0 15px;
  max-width: 1200px;
  margin: 0 auto;
}

.card {
  padding: 20px;
  background-color: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

/* 平板(≥ 768px):双列 */
@media (min-width: 768px) {
  .card-container {
    grid-template-columns: repeat(2, 1fr); /* 2 列等分 */
  }
}

/* PC(≥ 1200px):四列 */
@media (min-width: 1200px) {
  .card-container {
    grid-template-columns: repeat(4, 1fr); /* 4 列等分 */
  }
}

案例 7:元素显示/隐藏控制

需求:移动端隐藏“PC 专属广告位”,PC 端隐藏“移动端悬浮按钮”。

<!-- HTML -->
<div class="ad-pc">PC 端专属广告</div>
<button class="float-btn-mobile">移动端悬浮按钮(联系客服)</button>
/* CSS:移动优先 */
/* 移动端:显示悬浮按钮,隐藏 PC 广告 */
.float-btn-mobile {
  position: fixed;
  bottom: 20px;
  right: 20px;
  padding: 10px 20px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 50px;
  cursor: pointer;
}

.ad-pc {
  display: none; /* 移动端隐藏 PC 广告 */
  padding: 20px;
  background-color: #fff3cd;
  margin: 20px 0;
}

/* PC 端(≥ 1200px):隐藏悬浮按钮,显示 PC 广告 */
@media (min-width: 1200px) {
  .float-btn-mobile {
    display: none;
  }
  .ad-pc {
    display: block;
    max-width: 1200px;
    margin: 20px auto;
  }
}

案例 8:按钮尺寸与间距适配

需求:屏幕越小,按钮越小、间距越小(避免移动端按钮占满屏幕)。

<!-- HTML -->
<div class="btn-group">
  <button class="btn primary-btn">确认</button>
  <button class="btn secondary-btn">取消</button>
</div>
/* CSS:移动优先 */
.btn-group {
  display: flex;
  gap: 10px; /* 移动端按钮间距 */
  padding: 0 15px;
  max-width: 500px;
  margin: 20px auto;
}

.btn {
  padding: 8px 16px; /* 移动端按钮内边距 */
  border-radius: 4px;
  border: none;
  font-size: 0.9rem;
  cursor: pointer;
}

.primary-btn {
  background-color: #007bff;
  color: white;
}

.secondary-btn {
  background-color: #6c757d;
  color: white;
}

/* 平板(≥ 768px):增大按钮和间距 */
@media (min-width: 768px) {
  .btn-group {
    gap: 15px;
  }
  .btn {
    padding: 10px 20px;
    font-size: 1rem;
  }
}

/* PC(≥ 1200px):进一步优化 */
@media (min-width: 1200px) {
  .btn:hover {
    opacity: 0.9; /* hover 效果 */
  }
}

案例 9:视频/iframe 响应式

需求:视频/iframe(如嵌入的 YouTube 视频)宽度自适应,且保持 16:9 比例(避免拉伸变形)。

<!-- HTML:给视频外层加容器 -->
<div class="video-container">
  <iframe 
    src="https://www.youtube.com/embed/dQw4w9WgXcQ" 
    frameborder="0" 
    allowfullscreen
  ></iframe>
</div>
/* CSS:通用适配(无需媒体查询,通过 padding 实现比例) */
.video-container {
  position: relative;
  width: 100%;
  padding-bottom: 56.25%; /* 16:9 比例 = 9/16 = 56.25% */
  height: 0; /* 隐藏容器高度,由 padding 撑开 */
  overflow: hidden;
  max-width: 1200px;
  margin: 0 auto;
  padding-left: 15px;
  padding-right: 15px;
}

.video-container iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%; /* 视频占满容器 */
}

/* PC 端(≥ 1200px):添加阴影 */
@media (min-width: 1200px) {
  .video-container iframe {
    box-shadow: 0 4px 8px rgba(0,0,0,0.2);
  }
}

案例 10:跟随系统偏好的深色模式

需求:根据用户系统设置(浅色/深色)自动切换网页主题,且支持手动切换。

<!-- HTML -->
<div class="theme-container">
  <h2>主题自适应示例</h2>
  <p>当前主题:<span id="theme-text">浅色</span></p>
  <button id="theme-toggle">切换主题</button>
</div>
/* CSS:默认浅色主题 + 媒体查询监听系统偏好 */
:root {
  --bg-color: white;
  --text-color: #333;
  --btn-bg: #007bff;
}

.theme-container {
  padding: 20px 15px;
  background-color: var(--bg-color);
  color: var(--text-color);
  min-height: 200px;
  max-width: 800px;
  margin: 0 auto;
  border-radius: 8px;
}

#theme-toggle {
  padding: 8px 16px;
  background-color: var(--btn-bg);
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

/* 监听系统深色偏好(无需手动切换也能生效) */
@media (prefers-color-scheme: dark) {
  :root {
    --bg-color: #1a1a1a;
    --text-color: white;
    --btn-bg: #0056b3;
  }
  #theme-text {
    content: "深色(系统偏好)";
  }
}

/* PC 端(≥ 1200px):优化间距 */
@media (min-width: 1200px) {
  .theme-container {
    padding: 30px;
  }
}
// 手动切换主题(覆盖系统偏好)
const themeToggle = document.getElementById('theme-toggle');
const themeText = document.getElementById('theme-text');
const root = document.documentElement;

let isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;

// 初始化主题文本
themeText.textContent = isDark ? '深色(系统偏好)' : '浅色(系统偏好)';

themeToggle.addEventListener('click', () => {
  isDark = !isDark;
  if (isDark) {
    root.style.setProperty('--bg-color', '#1a1a1a');
    root.style.setProperty('--text-color', 'white');
    root.style.setProperty('--btn-bg', '#0056b3');
    themeText.textContent = '深色(手动切换)';
  } else {
    root.style.setProperty('--bg-color', 'white');
    root.style.setProperty('--text-color', '#333');
    root.style.setProperty('--btn-bg', '#007bff');
    themeText.textContent = '浅色(手动切换)';
  }
});

五、常见问题与解决方案

  1. 媒体查询不生效?

    • 检查是否添加 viewport 元标签(必加)。
    • 确认媒体特性的单位(如 min-width: 768 漏写 px)。
    • 避免使用 device-width,优先用 width(适配视口更准确)。
  2. 样式优先级冲突?

    • 媒体查询的选择器权重与普通 CSS 一致,若要覆盖默认样式,需保证选择器权重更高(例:.container 无法覆盖 div.container)。
    • 避免滥用 !important,优先通过调整选择器权重解决。
  3. 断点如何选择?

    • 参考行业通用断点(320px、768px、1200px),而非针对特定设备(如 iPhone 14 的 390px)。
    • 按“内容断点”调整:当内容出现溢出/留白时,再添加断点(而非固定设备尺寸)。

六、总结与未来趋势

CSS3 媒体查询是响应式设计的“基石”,通过它可实现“一套代码适配全端”,大幅降低开发和维护成本。目前,媒体查询仍是前端适配的核心技术,但未来会与 容器查询(Container Queries) 互补——容器查询允许根据“父容器尺寸”适配样式(而非仅依赖视口),更适合组件化开发。