CSS: 手搓12列栅格
栅格系统(Grid System)是网页布局中非常经典的方案——把一行分为若干列(通常是 12 列),通过组合不同的列宽实现多样化布局。Bootstrap 等框架的核心就是栅格系统。
1. 为什么是 12 列?
12 的因数很多:1、2、3、4、6、12,所以它能灵活组合:
- 1 列:占全部 12 份
- 2 列:每列占 6 份
- 3 列:每列占 4 份
- 4 列:每列占 3 份
- 6 列:每列占 2 份
2. 用 Flexbox 实现栅格
(1) 基本结构
▶ 示例
HTML
📖 仅展示
<style>
/* 行容器 */
.row {
display: flex;
flex-wrap: wrap;
margin: 0 -10px; /* 抵消列的内边距 */
}
/* 通用列样式 */
[class*="col-"] {
padding: 0 10px; /* 列间距 */
box-sizing: border-box;
}
/* 为可视演示添加背景色 */
.col-demo {
background: #e3f2fd;
border: 1px solid #90caf9;
padding: 12px 0;
text-align: center;
margin-bottom: 8px;
border-radius: 4px;
}
/* 12 列栅格 */
.col-1 { width: 8.333333%; } /* 1/12 */
.col-2 { width: 16.666667%; } /* 2/12 */
.col-3 { width: 25%; } /* 3/12 */
.col-4 { width: 33.333333%; } /* 4/12 */
.col-5 { width: 41.666667%; } /* 5/12 */
.col-6 { width: 50%; } /* 6/12 */
.col-7 { width: 58.333333%; } /* 7/12 */
.col-8 { width: 66.666667%; } /* 8/12 */
.col-9 { width: 75%; } /* 9/12 */
.col-10 { width: 83.333333%; } /* 10/12 */
.col-11 { width: 91.666667%; } /* 11/12 */
.col-12 { width: 100%; } /* 12/12 */
</style>
<div class="row">
<div class="col-1"><div class="col-demo">1</div></div>
<div class="col-2"><div class="col-demo">2</div></div>
<div class="col-3"><div class="col-demo">3</div></div>
<div class="col-4"><div class="col-demo">4</div></div>
<div class="col-5"><div class="col-demo">5</div></div>
<div class="col-6"><div class="col-demo">6(一半)</div></div>
<div class="col-7"><div class="col-demo">7</div></div>
<div class="col-8"><div class="col-demo">8</div></div>
<div class="col-9"><div class="col-demo">9</div></div>
<div class="col-10"><div class="col-demo">10</div></div>
<div class="col-11"><div class="col-demo">11</div></div>
<div class="col-12"><div class="col-demo">12(全宽)</div></div>
</div>
(2) HTML 使用
HTML
<!-- 三栏等宽:每列占 4 份 -->
<div class="row">
<div class="col-4">占 4 列</div>
<div class="col-4">占 4 列</div>
<div class="col-4">占 4 列</div>
</div>
<!-- 两栏不对称:左 3 右 9 -->
<div class="row">
<div class="col-3">占 3 列</div>
<div class="col-9">占 9 列</div>
</div>
<!-- 四栏等宽:每列占 3 份 -->
<div class="row">
<div class="col-3">占 3 列</div>
<div class="col-3">占 3 列</div>
<div class="col-3">占 3 列</div>
<div class="col-3">占 3 列</div>
</div>
3. 添加响应式断点
让栅格在不同屏幕下有不同的列数:
▶ 示例
HTML
<style>
/* 手机:默认满宽 */
.col-sm-1 { width: 8.333333%; }
.col-sm-2 { width: 16.666667%; }
.col-sm-3 { width: 25%; }
.col-sm-4 { width: 33.333333%; }
.col-sm-6 { width: 50%; }
.col-sm-12 { width: 100%; }
/* 平板 */
@media (min-width: 768px) {
.col-md-1 { width: 8.333333%; }
.col-md-2 { width: 16.666667%; }
.col-md-3 { width: 25%; }
.col-md-4 { width: 33.333333%; }
.col-md-6 { width: 50%; }
.col-md-8 { width: 66.666667%; }
.col-md-12 { width: 100%; }
}
/* 桌面 */
@media (min-width: 1024px) {
.col-lg-1 { width: 8.333333%; }
.col-lg-2 { width: 16.666667%; }
.col-lg-3 { width: 25%; }
.col-lg-4 { width: 33.333333%; }
.col-lg-6 { width: 50%; }
.col-lg-8 { width: 66.666667%; }
.col-lg-12 { width: 100%; }
}
.media-demo { padding: 20px; background: #f0f0f0; border-radius: 8px; border: 1px solid #ddd; }
</style>
<div class="media-demo">Media demo</div>
(1) 响应式使用示例
HTML
<!-- 手机:堆叠显示;平板:两栏;桌面:四栏 -->
<div class="row">
<div class="col-sm-12 col-md-6 col-lg-3">Col sm 12 col md 6 col lg 3</div>
<div class="col-sm-12 col-md-6 col-lg-3">Col sm 12 col md 6 col lg 3</div>
<div class="col-sm-12 col-md-6 col-lg-3">Col sm 12 col md 6 col lg 3</div>
<div class="col-sm-12 col-md-6 col-lg-3">Col sm 12 col md 6 col lg 3</div>
</div>
4. 添加偏移类
有时候需要让列偏移,比如让内容居中:
▶ 示例
HTML
<style>
.col-offset-0 { margin-left: 0; }
.col-offset-1 { margin-left: 8.333333%; }
.col-offset-2 { margin-left: 16.666667%; }
.col-offset-3 { margin-left: 25%; }
.col-offset-4 { margin-left: 33.333333%; }
.col-offset-6 { margin-left: 50%; }
</style>
<div class="col-offset-0">无偏移列</div>
<div class="col-offset-1">偏移 1 列</div>
<div class="col-offset-2">偏移 2 列</div>
<div class="col-offset-3">偏移 3 列</div>
<div class="col-offset-4">偏移 4 列</div>
<div class="col-offset-6">偏移 6 列</div>
HTML
<!-- 让内容位于中间 -->
<div class="row">
<div class="col-6 col-offset-3">
这个内容占据中间6列,左右各偏移3列
</div>
</div>
5. 完整的栅格系统
▶ 示例
HTML
📖 仅展示
<style>
/* ===== 栅格系统 ===== */
.row {
display: flex;
flex-wrap: wrap;
margin: 0 -10px;
}
[class*="col-"] {
padding: 0 10px;
box-sizing: border-box;
}
/* 12 列 */
.col-1 { width: 8.333333%; }
.col-2 { width: 16.666667%; }
.col-3 { width: 25%; }
.col-4 { width: 33.333333%; }
.col-5 { width: 41.666667%; }
.col-6 { width: 50%; }
.col-7 { width: 58.333333%; }
.col-8 { width: 66.666667%; }
.col-9 { width: 75%; }
.col-10 { width: 83.333333%; }
.col-11 { width: 91.666667%; }
.col-12 { width: 100%; }
/* 偏移 */
.col-offset-1 { margin-left: 8.333333%; }
.col-offset-2 { margin-left: 16.666667%; }
.col-offset-3 { margin-left: 25%; }
.col-offset-4 { margin-left: 33.333333%; }
.col-offset-6 { margin-left: 50%; }
/* 响应式 */
@media (min-width: 768px) {
.col-md-1 { width: 8.333333%; }
.col-md-2 { width: 16.666667%; }
.col-md-3 { width: 25%; }
.col-md-4 { width: 33.333333%; }
.col-md-6 { width: 50%; }
.col-md-8 { width: 66.666667%; }
.col-md-12 { width: 100%; }
}
@media (min-width: 1024px) {
.col-lg-1 { width: 8.333333%; }
.col-lg-2 { width: 16.666667%; }
.col-lg-3 { width: 25%; }
.col-lg-4 { width: 33.333333%; }
.col-lg-6 { width: 50%; }
.col-lg-8 { width: 66.666667%; }
.col-lg-12 { width: 100%; }
}
.media-demo { padding: 20px; background: #f0f0f0; border-radius: 8px; border: 1px solid #ddd; }
</style>
<div class="media-demo">Media demo</div>
6. 用 CSS Grid 实现栅格
也可以使用 Grid 来实现,更简洁:
▶ 示例
HTML
<style>
.grid-12 {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 20px;
}
.g-col-3 { grid-column: span 3; }
.g-col-4 { grid-column: span 4; }
.g-col-6 { grid-column: span 6; }
.g-col-8 { grid-column: span 8; }
.g-col-12 { grid-column: span 12; }
.grid-12-item {
background: #e8f4f8;
border: 1px solid #3498db;
padding: 16px;
margin: 4px;
border-radius: 4px;
text-align: center;
}
</style>
<div class="grid-12">
<div class="grid-12-item">Grid 12 item</div>
<div class="grid-12-item">Grid 12 item</div>
<div class="grid-12-item">Grid 12 item</div>
</div>
❓ 常见问题
Q 为什么栅格系统都用 12 列?
A 12 能被 2、3、4、6 整除,组合最灵活。可以做出 1/2、1/3、1/4、1/6、2/3、3/4 等各种比例。Bootstrap 等主流框架都采用 12 列栅格,这已经成了事实标准。
Q 手写栅格和用 Bootstrap 的栅格有什么区别?
A 手写栅格能帮你理解原理,Bootstrap 的栅格是封装好的实现。实际项目直接用 Bootstrap 更高效,但理解原理后遇到框架不满足的场景,你也能自己写栅格系统。
Q Flex 版栅格和 Grid 版栅格哪个好?
A 各有利弊。Flex 版适合一维排列,但无法跨行对齐。Grid 版二维能力强,列与列之间可以对齐。如果只需要简单的行内列分配,Flex 版就够了;如果需要网格线对齐,用 Grid 版。
7. 常用布局模式
(1) 圣杯布局(Header + Sidebar + Main + Footer)
这是最常见的页面布局模式:
▶ 示例
HTML
<style>
.holy-grail {
display: grid;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
grid-template-columns: 200px 1fr 200px;
grid-template-rows: 60px 1fr 40px;
min-height: 100vh;
gap: 10px;
}
.holy-grail-header { grid-area: header; background: #2c3e50; color: white; }
.holy-grail-sidebar { grid-area: sidebar; background: #34495e; color: white; }
.holy-grail-main { grid-area: main; background: #ecf0f1; }
.holy-grail-aside { grid-area: aside; background: #34495e; color: white; }
.holy-grail-footer { grid-area: footer; background: #2c3e50; color: white; }
.holy-grail-item {
padding: 20px;
display: flex;
align-items: center;
justify-content: center;
}
</style>
<div class="holy-grail">
<header class="holy-grail-header holy-grail-item">Header</header>
<aside class="holy-grail-sidebar holy-grail-item">Sidebar</aside>
<main class="holy-grail-main holy-grail-item">Main Content</main>
<aside class="holy-grail-aside holy-grail-item">Aside</aside>
<footer class="holy-grail-footer holy-grail-item">Footer</footer>
</div>
(2) 瀑布流布局(Pinterest风格)
使用Grid实现简单的瀑布流效果:
▶ 示例
HTML
<style>
.masonry {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
padding: 15px;
}
.masonry-item {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 8px;
padding: 20px;
color: white;
break-inside: avoid;
}
.masonry-item:nth-child(2) { height: 150px; }
.masonry-item:nth-child(3) { height: 100px; }
.masonry-item:nth-child(5) { height: 180px; }
</style>
<div class="masonry">
<div class="masonry-item">项目 1</div>
<div class="masonry-item">项目 2</div>
<div class="masonry-item">项目 3</div>
<div class="masonry-item">项目 4</div>
<div class="masonry-item">项目 5</div>
<div class="masonry-item">项目 6</div>
</div>
(3) 仪表盘布局
使用Grid实现数据展示面板:
▶ 示例
HTML
📖 仅展示
<style>
.dashboard {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: auto;
gap: 15px;
padding: 15px;
background: #f5f5f5;
}
.dashboard-card {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.dashboard-card h3 {
margin: 0 0 10px 0;
font-size: 14px;
color: #666;
}
.dashboard-card .value {
font-size: 24px;
font-weight: bold;
color: #2c3e50;
}
.dashboard-card:nth-child(1) { border-left: 4px solid #3498db; }
.dashboard-card:nth-child(2) { border-left: 4px solid #2ecc71; }
.dashboard-card:nth-child(3) { border-left: 4px solid #e74c3c; }
.dashboard-card:nth-child(4) { border-left: 4px solid #f39c12; }
</style>
<div class="dashboard">
<div class="dashboard-card">
<h3>总用户数</h3>
<div class="value">12,345</div>
</div>
<div class="dashboard-card">
<h3>活跃用户</h3>
<div class="value">8,901</div>
</div>
<div class="dashboard-card">
<h3>转化率</h3>
<div class="value">23.5%</div>
</div>
<div class="dashboard-card">
<h3>收入</h3>
<div class="value">$45,678</div>
</div>
</div>
💡 布局要点: 圣杯布局用
grid-template-areas 定义区域,瀑布流用 repeat(3, 1fr) 均分列,仪表盘用固定列数展示数据卡片。
📖 小节
- 栅格系统是网页布局中久经考验的经典方案
- 用 Flexbox 手写一个 12 列栅格并不复杂——关键是理解
width: 百分比的计算和flex-wrap的配合 - 12 列的优势在于组合灵活,加上响应式断点就能适配各种屏幕
- 虽然现在很多项目会直接用 Bootstrap 或 Tailwind 的栅格系统,但自己动手实现一次,能让你真正理解背后的原理
📝 作业
- 实现上面的完整 12 列栅格系统,创建一个 HTML 页面展示不同列组合的效果(如 3-3-3-3、4-4-4、2-8-2 等)。
- 使用响应式栅格,让一个页面在手机上显示单列、平板上显示两列、桌面上显示四列。
- 使用
col-offset-3让一个内容块在页面中居中显示。 - 使用 Grid 版本重新实现上面的 12 列栅格,对比两个版本的代码差异。