一开始让我搞CSS Grid,我心里是犯嘀咕的——这玩意儿能比Flexbox好用?结果第一次上手做项目,硬是被fr单位搞懵了。后来才发现,Grid这东西,真的是为复杂布局量身定做的。不过嘛,踩坑是少不了的。今天我就把我和Grid“搏斗”的经历全倒出来,顺便说说哪些坑是真没必要再踩的。
先看基础:Grid到底能干啥?
Grid最牛的地方,就是能同时控制行和列。你想象一下,以前用浮动或者Flexbox做那种两列三行的布局,得写一堆嵌套的div,看着就烦。现在一个grid容器就搞定了。
“`css
/* 最简单的网格 */
.container {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
grid-template-rows: auto;
gap: 20px;
}
“`
这段代码的意思是:三列,比例1:2:1,行高自动,间距20px。那个fr单位,我一开始搞错了,以为和百分比差不多,后来发现它比百分比真的好用太多——不用算边框和间距,自动适配剩余空间。
对了,为什么要用fr?因为百分比在计算间距和边框时容易溢出,而fr会自动扣除gap和其他固定尺寸的空间,再分配剩余空间。这个设计,一开始我觉得反人类,后来仔细想想,它太人性化了。
第一个大坑:grid-gap vs gap
我刚开始用Grid的时候,照着网上的教程写`grid-gap`,结果浏览器给我报了个warning。当时我心想:完了,又得查文档。结果查了半天才发现,`grid-gap`已经被弃用了,现在直接用`gap`就行。这算是个小坑吧,但浪费了我半小时,真的不值。
“`css
/* 不要写这个(已弃用) */
.container {
grid-gap: 20px;
}
/* 正确写法 */
.container {
gap: 20px;
}
“`
`gap`是统一属性,同时控制行间距和列间距。如果想让行和列间距不同,用`gap: row-gap column-gap`。这个我试过,好使。
核心概念:grid-template-areas
这是Grid最爽的地方,没有之一。你想象一个典型的页面布局:头部、侧边栏、主内容、底部。以前要写一堆class和样式,现在一行搞定。
“`css
.layout {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
“header header”
“sidebar main”
“footer footer”;
min-height: 100vh;
gap: 1rem;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
“`
为什么这么写?因为grid-template-areas用ASCII艺术的方式定义了布局结构,一眼就能看出页面长啥样。头部占两列,侧边栏和主内容占第二行,底部又占两列。改布局只需要改这个字符串,不用动HTML结构。这玩意儿,真的好用。
另一个坑:自动换行与minmax
做响应式布局时,我踩过一个巨坑:想让卡片自适应列数,但不想写媒体查询。网上说用`auto-fill`和`minmax`,结果第一次写出来是这样的:
“`css
/* 错误示范 */
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1rem;
}
“`
这段代码看似正确,但实际效果是:列数会自适应,但每列宽度会撑满容器。原因在于`1fr`作为最大值时,minmax会忽略最小值,直接取最大值。
正确的写法应该是这样的:
“`css
/* 正确写法 */
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1rem;
}
“`
等一下,代码看起来一样?不,关键在于`auto-fill`和`auto-fit`的区别。`auto-fill`会尽量填充列,哪怕有些列是空的;而`auto-fit`会合并空列。通常我们想要的是`auto-fit`:
“`css
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
“`
这个组合拳的效果是:每列最少200px,如果容器宽了就自动增加列数,如果窄了就自动减少列数。不用任何媒体查询,真正的一行代码搞定响应式。我试过,效果贼好。
再说说对齐:place-items与place-content
刚开始我以为这两个是一样的,结果发现完全不是。`place-items`控制子元素在单元格内的对齐,而`place-content`控制整个网格容器的对齐。
“`css
.container {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-template-rows: repeat(3, 100px);
width: 500px;
height: 500px;
/* 子元素在各自单元格中居中 */
place-items: center;
/* 整个网格在容器中居中 */
place-content: center;
}
“`
这个设计,一开始我也觉得反人类。但仔细想想就明白了:`place-items`是微观对齐(单元格内的元素),`place-content`是宏观对齐(整个网格在容器中的位置)。记住这个区分就不会搞混了。
实战案例:文章列表卡片
来个实际的例子,做一个文章列表,左侧是缩略图,右侧是文字描述。
“`html
文章标题
文章摘要描述
2024-06-01
“`
“`css
.article-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1.5rem;
}
.article-card {
display: grid;
grid-template-columns: 120px 1fr;
gap: 1rem;
align-items: start;
padding: 1rem;
border: 1px solid #eee;
border-radius: 8px;
}
.card-thumb {
width: 100%;
height: auto;
border-radius: 4px;
}
“`
总结一下,CSS Grid这个东西,上手不难,但坑不少。不过只要把那些关键点记牢——比如fr单位、gap属性、grid-template-areas、auto-fit和minmax的组合——做复杂布局就轻松多了。我现在做项目,基本不用Flexbox了,Grid是真的香。