跳至正文
来两杯美式
返回

CSS 基础(七):响应式设计与媒体查询

By 来两杯美式
发布于更新于

先问一个问题

你用手机打开某个网站,发现字小得看不清,必须左右滑动才能看全内容,体验极差。这种网站就是没有做响应式设计。

响应式的核心:同一个 HTML 页面,在不同屏幕尺寸下展示不同的布局效果。用户不管用什么设备访问,都能获得良好的体验。

viewport meta:响应式第一步

没有这个标签,移动端会默认按桌面宽度(约 980px)渲染,然后把整个页面缩放显示。你在手机上看到的网页被缩成了一小块。

<!-- 必须加在 <head> 里 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

记住:所有响应式页面都必须加这个标签,否则移动端体验必然很差。

媒体查询基础

媒体查询允许我们根据设备特性(主要是屏幕宽度)应用不同的样式。

语法

/* 最小宽度 768px 时生效(移动优先,推荐) */
@media (min-width: 768px) {
  .container {
    max-width: 1200px;
  }
}

/* 最大宽度 767px 时生效(桌面优先) */
@media (max-width: 767px) {
  .container {
    padding: 0 16px;
  }
}

移动优先 vs 桌面优先

有两种策略:

策略写法适用场景
移动优先(推荐)先写移动端样式,用 min-width 逐步增强大多数场景
桌面优先先写桌面样式,用 max-width 逐步削弱旧项目迁移

为什么推荐移动优先

  1. 移动端用户占比更高(流量、用户量)
  2. 逐步增强比逐步削弱更容易维护
  3. Tailwind 默认就是移动优先

Tailwind 响应式前缀

Tailwind 把常用断点做成了前缀,让你不用写媒体查询:

断点最小宽度Tailwind 前缀典型设备
sm640pxsm:大手机
md768pxmd:平板
lg1024pxlg:笔记本
xl1280pxxl:桌面
2xl1536px2xl:大桌面

使用方式

在任意 Tailwind 类前加断点前缀,该样式只在该断点及以上生效:

<!-- 移动端 1 列,平板 2 列,桌面 3 列 -->
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
  <div class="rounded bg-red-200 p-4">卡片1</div>
  <div class="rounded bg-blue-200 p-4">卡片2</div>
  <div class="rounded bg-green-200 p-4">卡片3</div>
</div>
<!-- 移动端隐藏,桌面显示 -->
<div class="hidden lg:block">只在桌面端显示</div>

<!-- 移动端红色背景,桌面蓝色背景 -->
<div class="bg-red-500 lg:bg-blue-500">响应式颜色</div>

常见断点用法

响应式文字大小

<!-- 移动 14px,平板 16px,桌面 18px -->
<p class="text-sm md:text-base lg:text-lg">响应式文本大小</p>

响应式间距

<!-- 移动端小间距,桌面大间距 -->
<div class="p-4 md:p-6 lg:p-8">响应式内边距</div>

响应式隐藏/显示

<!-- 移动端显示"菜单按钮",桌面端显示导航链接 -->
<nav class="flex items-center justify-between p-4">
  <div class="font-bold">Logo</div>
  <!-- 移动端:显示菜单按钮 -->
  <button class="rounded bg-gray-200 px-4 py-2 lg:hidden">菜单</button>
  <!-- 桌面端:显示导航链接 -->
  <div class="hidden gap-4 lg:flex">
    <a href="#">首页</a>
    <a href="#">文章</a>
    <a href="#">关于</a>
  </div>
</nav>

响应式 Flex 方向

<!-- 移动端垂直排列,桌面端水平排列 -->
<div class="flex flex-col gap-4 md:flex-row">
  <div class="bg-red-200 p-4">左侧内容</div>
  <div class="bg-blue-200 p-4">右侧内容</div>
</div>

实战:完整响应式页面

用一个完整的博客页面演示所有技巧:

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <!-- 必须加 viewport,否则移动端无法正常响应式 -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>响应式博客页面</title>
    <script src="https://cdn.tailwindcss.com"></script>
  </head>
  <body class="bg-gray-50 text-gray-800">
    <!-- Header:移动端垂直排列,桌面端水平排列 -->
    <header class="bg-white shadow-sm">
      <nav
        class="mx-auto flex max-w-6xl flex-col items-center justify-between gap-4 px-4 py-4 sm:flex-row"
      >
        <div class="text-xl font-bold">我的博客</div>
        <!-- 移动端显示菜单按钮,桌面端隐藏 -->
        <button class="rounded bg-gray-200 px-4 py-2 text-sm sm:hidden">
          菜单
        </button>
        <!-- 桌面端显示完整导航,移动端隐藏 -->
        <div class="hidden gap-6 text-sm sm:flex">
          <a href="#" class="hover:text-blue-500">首页</a>
          <a href="#" class="hover:text-blue-500">文章</a>
          <a href="#" class="hover:text-blue-500">项目</a>
          <a href="#" class="hover:text-blue-500">关于</a>
        </div>
      </nav>
    </header>

    <!-- Hero:响应式间距和文字大小 -->
    <section class="px-4 py-12 text-center md:py-20">
      <h1 class="mb-4 text-3xl font-bold md:text-4xl lg:text-5xl">
        欢迎来到我的技术博客
      </h1>
      <p class="mx-auto mb-6 max-w-2xl text-base text-gray-600 md:text-lg">
        这里分享前端开发、技术管理和成长思考
      </p>
      <button
        class="rounded-lg bg-blue-500 px-6 py-3 text-white transition hover:bg-blue-600"
      >
        开始阅读
      </button>
    </section>

    <!-- 文章列表:响应式网格 -->
    <main class="mx-auto max-w-6xl px-4 py-8">
      <h2 class="mb-6 text-2xl font-bold">最新文章</h2>
      <!-- 移动端 1 列,平板 2 列,桌面 3 列 -->
      <div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
        <article
          class="rounded-lg bg-white p-6 shadow transition hover:shadow-lg"
        >
          <div class="mb-2 text-sm text-blue-500">前端</div>
          <h3 class="mb-2 text-lg font-bold">CSS Flexbox 入门指南</h3>
          <p class="mb-4 text-sm text-gray-600">
            Flexbox 是现代 CSS 布局的核心技能...
          </p>
          <div class="text-xs text-gray-400">2024-01-15</div>
        </article>
        <article
          class="rounded-lg bg-white p-6 shadow transition hover:shadow-lg"
        >
          <div class="mb-2 text-sm text-green-500">架构</div>
          <h3 class="mb-2 text-lg font-bold">微服务架构设计原则</h3>
          <p class="mb-4 text-sm text-gray-600">
            微服务不是银弹,适合的才是最好的...
          </p>
          <div class="text-xs text-gray-400">2024-01-10</div>
        </article>
        <article
          class="rounded-lg bg-white p-6 shadow transition hover:shadow-lg"
        >
          <div class="mb-2 text-sm text-purple-500">工具</div>
          <h3 class="mb-2 text-lg font-bold">Git 工作流最佳实践</h3>
          <p class="mb-4 text-sm text-gray-600">
            如何组织团队的 Git 分支管理...
          </p>
          <div class="text-xs text-gray-400">2024-01-05</div>
        </article>
      </div>
    </main>

    <!-- Footer:移动端小间距,桌面端正常 -->
    <footer class="mt-12 bg-gray-800 py-8 text-white">
      <div class="mx-auto max-w-6xl px-4 text-center">
        <div class="mb-4 text-sm text-gray-400">Made with passion in 2024</div>
        <div class="text-xs text-gray-500">All rights reserved.</div>
      </div>
    </footer>
  </body>
</html>

不用媒体查询的响应式:Auto Fit + Minmax

结合 Grid 的 auto-fitminmax,可以实现真正的”零媒体查询”响应式:

<!-- 不需要任何 sm: md: lg: 前缀,Grid 自动适应 -->
<div
  class="grid gap-4"
  style="grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));"
>
  <div class="rounded bg-red-200 p-6">响应式卡片1,内容足够多时会换行</div>
  <div class="rounded bg-blue-200 p-6">响应式卡片2</div>
  <div class="rounded bg-green-200 p-6">响应式卡片3</div>
  <div class="rounded bg-yellow-200 p-6">响应式卡片4</div>
</div>

记住这个公式repeat(auto-fit, minmax(最小宽度, 1fr)) = 自动响应式网格。

Flex + Wrap 实现响应式

对于不需要对齐的卡片列表,用 Flex + Wrap 也能实现响应式:

<div class="flex flex-wrap gap-4">
  <div
    class="w-full bg-gray-100 p-4 sm:w-[calc(50%-8px)] lg:w-[calc(33.33%-11px)]"
  >
    响应式卡片
  </div>
</div>

不过这种方式需要手动计算宽度,不如 Grid 的 auto-fit 方便。

常见踩坑与避坑指南

踩坑 1:没有 viewport meta

这是移动端显示问题的第一大原因。必须在 <head> 中加上 viewport meta 标签

<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <!-- 其他 head 内容 -->
</head>

踩坑 2:断点覆盖顺序错误

使用 max-width 媒体查询时,要从大到小排序;使用 min-width 时,从小到大排序。

/* 错误:顺序不对可能导致样式冲突 */
@media (max-width: 767px) { ... }
@media (min-width: 768px) { ... }

/* 正确:min-width 从小到大 */
@media (min-width: 640px) { ... }
@media (min-width: 768px) { ... }
@media (min-width: 1024px) { ... }

Tailwind 的断点前缀已经帮你处理好了这个问题,所以尽量用 Tailwind 前缀而不是自己写媒体查询。

踩坑 3:图片溢出

图片默认不会自动适应容器宽度,可能导致横向滚动。

/* CSS 原生解决方案 */
img {
  max-width: 100%;
  height: auto;
}
<!-- Tailwind 解决方案 -->
<img src="..." class="h-auto w-full" />

踩坑 4:flex/grid 容器没有限制导致溢出

有时候子元素会撑破容器,导致横向滚动条。给容器加 overflow-hidden 或限制 max-width

<div class="overflow-hidden">
  <!-- 子元素不会撑破这里 -->
</div>

速查表

功能CSS 原生Tailwind
viewport 设置<meta name="viewport" content="width=device-width, initial-scale=1.0">-(HTML 层面)
最小宽度 768px@media (min-width: 768px)md:
最大宽度 767px@media (max-width: 767px)-(用 hidden md:block 实现)
隐藏元素display: nonehidden
显示元素display: blockblock
响应式文字font-size: 14px; @media (min-width: 768px) { font-size: 16px }text-sm md:text-base
响应式网格grid-template-columns: repeat(auto-fit, minmax(280px, 1fr))grid-cols-1 sm:grid-cols-2 lg:grid-cols-3
响应式 flex 方向flex-direction: column; @media (min-width: 768px) { flex-direction: row }flex-col md:flex-row
响应式间距padding: 16px; @media (min-width: 768px) { padding: 24px }p-4 md:p-6

总结

记住响应式设计的三个核心

  1. viewport meta 是响应的第一步,没有它一切免谈
  2. 移动优先是推荐的策略,先做移动端,再用 min-width 逐步增强
  3. Tailwind 前缀sm: md: lg:)让你不用写媒体查询,但你要理解底层原理

响应式不是为每个屏幕写一套 HTML,而是让同一个 HTML 在不同屏幕下展现不同的布局。这才是现代前端开发的正确姿势。


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
所属专题
CSS
第 7 / 7 篇
查看系列全部文章
  1. 01.CSS 基础(一):元素类型与 display 属性
  2. 02.CSS 基础(二):盒模型
  3. 03.CSS 基础(三):浮动
  4. 04.CSS 基础(四):定位
  5. 05.CSS 基础(五):Flex 弹性布局
  6. 06.CSS 基础(六):Grid 网格布局
  7. 07.CSS 基础(七):响应式设计与媒体查询

上一篇
前端核心(一):DOM 入门
下一篇
CSS 基础(六):Grid 网格布局