先问一个问题
你用手机打开某个网站,发现字小得看不清,必须左右滑动才能看全内容,体验极差。这种网站就是没有做响应式设计。
响应式的核心:同一个 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 逐步削弱 | 旧项目迁移 |
为什么推荐移动优先:
- 移动端用户占比更高(流量、用户量)
- 逐步增强比逐步削弱更容易维护
- Tailwind 默认就是移动优先
Tailwind 响应式前缀
Tailwind 把常用断点做成了前缀,让你不用写媒体查询:
| 断点 | 最小宽度 | Tailwind 前缀 | 典型设备 |
|---|---|---|---|
| sm | 640px | sm: | 大手机 |
| md | 768px | md: | 平板 |
| lg | 1024px | lg: | 笔记本 |
| xl | 1280px | xl: | 桌面 |
| 2xl | 1536px | 2xl: | 大桌面 |
使用方式
在任意 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-fit 和 minmax,可以实现真正的”零媒体查询”响应式:
<!-- 不需要任何 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: none | hidden |
| 显示元素 | display: block | block |
| 响应式文字 | 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 |
总结
记住响应式设计的三个核心:
- viewport meta 是响应的第一步,没有它一切免谈
- 移动优先是推荐的策略,先做移动端,再用
min-width逐步增强 - Tailwind 前缀(
sm:md:lg:)让你不用写媒体查询,但你要理解底层原理
响应式不是为每个屏幕写一套 HTML,而是让同一个 HTML 在不同屏幕下展现不同的布局。这才是现代前端开发的正确姿势。