写在前面:做前端这些年,布局问题几乎天天打交道。从最早的 float + 定位,到如今 Flexbox、Grid 成为主流,布局这件事其实已经变得简单了很多。这篇文章把我常用的布局技巧做一次系统梳理,代码都可直接复制使用,希望对你有帮助。
往期前端系列文章在我的主页可以找到。
一、水平垂直居中的 N 种姿势
居中大概是布局界的"第一道面试题",我把常用的几种按推荐度排个序。
方案一:Flexbox(首选,万金油)
.parent {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
}
方案二:Grid 一行搞定(现代浏览器直接用)
.parent {
display: grid;
place-items: center;
}
place-items 是 align-items 和 justify-items 的简写,比 Flex 还省事。
方案三:绝对定位 + transform(不知道子元素尺寸时用)
.parent { position: relative; }
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
方案四:绝对定位 + margin: auto(已知子元素尺寸)
.child {
position: absolute;
inset: 0; /* 等价于 top/right/bottom/left: 0 */
margin: auto;
width: 200px;
height: 100px;
}
日常开发记住前两种就够了,后两种在特定场景(弹窗遮罩等)会更灵活。
二、Flexbox 实战技巧
1. 左右固定、中间自适应(圣杯布局的现代解法)
曾经要用 float + 负 margin 折腾半天的"圣杯布局 / 双飞翼布局",Flex 三行解决:
.layout { display: flex; }
.left, .right { width: 200px; flex-shrink: 0; } /* 固定侧栏 */
.main { flex: 1; min-width: 0; } /* 自适应中间 */
注意 min-width: 0,后面踩坑部分细说。
2. Sticky Footer(footer 永远贴底)
内容不够长时 footer 也想待在页面底部:
body {
min-height: 100vh;
display: flex;
flex-direction: column;
}
.footer { margin-top: auto; } /* 自动吸底 */
3. 用 gap 替代 margin 兜底
以前做列表间距,不是给子项加 margin 就是给容器加负 margin,还容易出"最后一项多出一个间距"的问题。现在直接:
.list {
display: flex;
gap: 16px; /* 子项之间自动留缝,首尾干净 */
}
Flex 和 Grid 容器都支持 gap,无脑用。
4. 等分与等高
- 等分:子项都写
flex: 1; - 等高:不用设置,Flex 默认
align-items: stretch,子项自动等高
5. space-between / space-around / space-evenly 的区别
-
space-between:两端贴边,中间均分 -
space-around:每项两侧有相等的空隙,中间的空隙是两侧的两倍 -
space-evenly:所有空隙完全相等
导航栏分散对齐用 space-between 最常见。
三、Grid 布局技巧
如果说 Flex 是"一维布局之王",Grid 就是"二维布局之王",行列一起控制。
1. 响应式卡片列表(一行代码实现自适应列数)
不用媒体查询,屏幕变宽自动多放一列:
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 16px;
}
意思是:每列最少 240px,能塞下几列就塞几列,剩余空间平均分。做商品列表、博客卡片列表非常好用。
2. 命名区域布局(整页骨架首选)
.layout {
display: grid;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
grid-template-columns: 200px 1fr;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
页面结构一眼看穿,移动端改成单列也只需要换一下 grid-template-areas 的排布,非常直观。
3. place-items 居中 + fr 单位
-
fr:剩余空间的份数,grid-template-columns: 1fr 2fr表示 1:2 分 -
minmax(100px, 1fr):给列设上下限,配合响应式很灵活
四、响应式布局技巧
1. clamp():不写媒体查询也能流式缩放
h1 {
/* 最小 20px,理想 4vw,最大 40px */
font-size: clamp(20px, 4vw, 40px);
}
标题、内边距、间距都可以用它做"弹性但不失控"的缩放。
2. aspect-ratio:告别 padding-bottom 占位黑科技
以前保持图片 16:9 比例要用伪元素 + padding-bottom: 56.25%,现在:
.video-box { aspect-ratio: 16 / 9; }
加载前占位、封面图容器都好用。
3. 移动优先 + min-width 断点
/* 默认就是手机样式 */
.layout { display: block; }
@media (min-width: 768px) {
.layout { display: grid; }
}
从下往上加样式,比从上往下覆盖省很多代码。
4. 容器查询:组件级响应式(值得关注的新能力)
媒体查询只看视口宽度,容器查询看的是"组件自己的容器":
.card-wrap { container-type: inline-size; }
@container (min-width: 400px) {
.card { display: flex; } /* 容器够宽时卡片变横向 */
}
同一个组件放进侧边栏是竖版,放进主内容区是横版,真正实现"组件级自适应"。
五、那些年踩过的坑
1. margin 塌陷与 BFC
父子元素的 margin 会"合并"到一起,导致给子项加 margin-top 结果父元素整体往下掉。解法:
.parent {
display: flow-root; /* 推荐:触发 BFC,无副作用 */
}
比 overflow: hidden(会裁剪内容)干净得多。
2. flex 子项内容过长把布局撑爆
flex: 1 的子项里如果有长单词或长文本,默认不会被压缩,会把整个布局撑开。解法:
.main { flex: 1; min-width: 0; }
同理,纵向布局里对应 min-height: 0。
3. 多行文本省略
.desc {
display: -webkit-box;
-webkit-line-clamp: 3; /* 最多显示 3 行 */
-webkit-box-orient: vertical;
overflow: hidden;
}
看着像"黑科技",但它已经是事实标准,各大浏览器都支持。
4. position: sticky 不生效?
大概率是某个祖先元素设置了 overflow: hidden / auto / scroll,把它"锁死"了。排查思路:逐层检查父容器的 overflow 和 height 设置。
六、布局选型建议
| 场景 | 首选方案 |
|---|---|
| 整页骨架(头、侧栏、主区、脚) | Grid(grid-template-areas) |
| 一行内的对齐与分布 | Flex |
| 卡片/瀑布类列表 | Grid(auto-fill + minmax) |
| 表单、标签组等流式排列 | Flex + gap,或 inline 布局 |
| 需要随容器宽度变化的组件 | 容器查询 |
一句话总结:宏观用 Grid 搭骨架,微观用 Flex 做对齐,两者是互补不是替代。
写在最后
布局的 API 就这么多,真正的功夫在于遇到需求时能快速选对工具、少走弯路。建议把上面的代码块存成自己的 snippet 库,用两次就熟了。
如果这篇文章对你有帮助,点个喜欢就是对我最大的鼓励;想持续看前端干货,可以关注我。你还想看哪方面的总结(JS 基础、Vue/React 实战、工程化……),评论区告诉我。