ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CSS Grid 核心概念与实战:从网格线到响应式布局一文讲透

CSS Grid 核心概念与实战:从网格线到响应式布局一文讲透 做前端这几年如果让我评一个“文档看过、真到用时就怂”的 CSS 模块CSS Grid 网格布局绝对排第一。不少人都在教程里见它炫技什么九宫格、双飞翼、瀑布流看起来无所不能可真到自己写页面手指头还是习惯性放到display: flex上。原因很简单Grid 的心智模型和 Flex 不一样不彻底理解它那套“画格子”的思路上手确实有点飘。这篇文章我不想当文档搬运工而是按我自己从入门到敢在真实项目里用 Grid 的顺序把核心概念、常用写法、实战案例和踩坑记录一次性讲透。内容覆盖grid-template-*、fr单位、repeat、minmax、网格线定位、区域命名、对齐方式、响应式布局以及十个新手必踩的坑。写完之后你会发现原来很多让 JavaScript 计算高度、靠浮动 hack 的布局用 Grid 一行声明就能解决。1. 先想清楚Grid 和 Flex 到底怎么分工1.1 一维与二维两种完全不同的心智模型很多人一开始用不好 Grid是因为老拿 Flex 的思路去套它结果越套越乱。这俩东西的底层模型根本不是一个维度。Flex 是一维布局本质上就是“在一根轴线上排项目”。主轴方向从左到右还是从上到下由flex-direction决定项目太多就换行换行之后依然是按顺序一根轴一根轴地排。它擅长的是“这一组按钮怎么水平分布”“这一列菜单怎么撑开”但你让它管“整个页面上有多少列、每列占多宽、某个区域同时跨几行几列”这种二维结构就很吃力往往要靠嵌套、固定高度、甚至 JS 来补。Grid 是二维布局它在你声明display: grid的那一刻就把整个容器划分成一个表格状的坐标系。你可以同时控制行和列可以让某个项目横跨两列、纵跨两行可以精确说出“这个区域从第 1 条竖线到第 3 条竖线从第 2 条横线到第 4 条横线”。用一个生活类比可能更好记Flex 是排队大家一个挨一个按顺序站宽度不够就换下一排Grid 是影厅座位你能精确指定谁坐第几排第几列还能让一个人横躺两个座位、或者一次占掉两个座位的位置。所以我自己的经验是不要问“Grid 和 Flex 谁更强”它们分工不同。页面级骨架、大面积分区、二维报表类布局优先 Grid组件内部的单行排列、按钮组、导航条这类“一条线”的问题用 Flex 更顺手。二者是配合关系不是替代关系。1.2 五个必懂基础概念容器、项目、网格线、单元格、区域要玩转 Grid先把这五个词刻进脑子里否则后面所有属性都会看得云里雾里。容器Grid Container设置了display: grid或display: inline-grid的元素。它就是那张无形的表格画布。项目Grid Item容器的直接子元素。注意只能是“直接子元素”孙子元素不算。项目自动进入网格不需要手动安排位置。网格线Grid Line把网格分开的那一条条线分横向和纵向。Grid 里网格线从 1 开始编号容器最左边是第 1 条纵向网格线最上边是第 1 条横向网格线。也可以从最后一个方向倒着数用负数表示比如-1永远指向最后一条线。单元格Grid Cell相邻两条横向网格线和相邻两条纵向网格线围起来的区域它是网格的最小单位。几条网格线就能围出几个格子比如 4 条纵向线和 3 条横向线就形成一个 3 列 2 行的网格共 6 个单元格。区域Grid Area由一个或多个单元格组成的矩形区域。后面要讲的grid-template-areas就是靠给区域起名字来做布局的让整个页面骨架像画平面图一样清晰。记住这五个词后续看任何 Grid 教程都不会再迷路。特别提醒一点很多人在容器上写了一大堆属性子元素却没变化多半是把定位属性写在容器而不是子项目上了区分好“管容器的属性”和“管项目的属性”是第一步。2. 搭建网格骨架columns、rows、fr 和 repeat2.1 从 display: grid 出发建立网格轨道Grid 的行列在规范里叫“轨道”Track通俗理解就是一列或一行的宽度/高度。建轨道用两个属性grid-template-columns定义每一列的宽度grid-template-rows定义每一行的高度。.container { display: grid; grid-template-columns: 100px 200px 100px; grid-template-rows: 80px 120px; }这段代码建立一个 3 列 2 行的网格三列宽度分别是 100px、200px、100px两行高度分别是 80px 和 120px。所有直接子元素会自动按顺序填入单元格中先从左到右一行满了自动换到下一行。这里有一个细节值得新手注意如果只定义了 2 行但子元素有 5 个第 5 个元素会跑到哪答案是它会触发 Grid 的“隐式轨道”机制自动生成第 3 行来承接这个项目。这个机制后面会单独讲这里先有个概念。上面用了像素值肯定有人会问那能不能用百分比可以比如grid-template-columns: 25% 25% 50%。但百分比在计算间距和折行时很容易产生意外的溢出因为百分比是基于容器内容宽度算的加上gap之后25% 25% 50% 再加间距总量就可能超过 100%。所以现代 Grid 更推荐用接下来这个单位。2.2 fr 单位把剩余空间变成可分配的份额fr是 fraction 的缩写意思是“份”。它解决的是弹性比例分配问题它的计算逻辑是这样的先看网格容器里由固定尺寸px、em、%等占用的空间把它扣掉剩余的空间作为“待分配池”再把所有fr值相加得到总份数每个fr轨道按自己的份数分到对应比例的剩余空间。用一个例子直接说明.container { display: grid; grid-template-columns: 200px 1fr 2fr; }这里第一列固定 200px剩下的空间分成 3 份第二列拿 1 份第三列拿 2 份。如果容器总共 800px 宽第一列 200px剩余 600px第二列就是 200px第三列是 400px。容器宽度变化时第一列永远是 200px后两列则按 1:2 自动缩放。这种写法的经典应用场景是“左侧固定侧边栏 右侧自适应内容区”。以前用 Flex 写这个需求通常要配合flex: 1和min-width: 0处理一堆边界情况用 Grid 就是一行grid-template-columns: 220px 1fr的事固定和弹性之间的分配逻辑一眼看清。fr和百分比最大的区别在于百分比基于容器总宽固定计算容易和间隙、固定列产生冲突fr是基于“扣完固定值后的剩余空间”分配天然避开了这类问题。所以我现在写 Grid只要是带弹性的列宽基本都用fr。2.3 repeat 简写、minmax 边界控制与隐式轨道手工写很多列的时候比如六宫格你要是写grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr手一抖就容易多打或少打一个。repeat()函数就是干这个的grid-template-columns: repeat(6, 1fr); /* 等价于 1fr 1fr 1fr 1fr 1fr 1fr */repeat()第一个参数是重复次数第二个则是重复的轨道模式。模式可以是多个值比如repeat(2, 100px 1fr)等价于100px 1fr 100px 1fr相当于把“100px 固定列 1fr 弹性列”这个组合重复了两次。实际做商品列表、卡片网格时这个简写非常管用。minmax()函数则用来定义轨道的尺寸范围格式是minmax(最小值, 最大值)。它最经典的应用就是响应式网格grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));这句的意思是每一列最小 240px最大占 1 份弹性空间只要容器宽度能塞得下更多列就自动多生成一列。整个网格不需要写任何媒体查询就能在小屏手机上一列、平板两列、桌面三四列地自动变化。这个组合是响应式卡片布局的黄金写法后面实战章节还会细讲。再补充一个重要概念隐式轨道。前面提到项目数量超过显式定义的轨道数量时Grid 会自动生成新的行或列这些自动生成的轨道就叫隐式轨道。隐式轨道的尺寸默认是auto如果你希望自动生成的行高是统一的可以用grid-auto-rows控制.container { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 160px; }这样哪怕有 100 个项目自动生成的每一行也都会是 160px 高做瀑布流、商品墙的时候特别方便。配合grid-auto-flow: dense还能让后面的项目往前回填空隙让整个网格看起来更紧凑但要注意它会改变项目在文档流中的视觉顺序涉及键盘操作或阅读顺序的内容要慎重使用。2.4 gap间距的问题别再用 margin 硬挤了在 Grid 之前给多个块级元素之间加间距最痛苦的方案就是设置 margin 后还要处理“最后一个不能有外边距”“第一列不能有左边距”等边角情况。Grid 里有了专门的间距属性gap它可以直接在轨道之间插入间距而且不会参与项目自身的尺寸计算也不会像 margin 一样产生意外塌陷对Grid 子项之间不存在 Flex 里那种 margin 折叠问题。.container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; /* 行列间距都是 16px */ row-gap: 20px; /* 单独覆盖行间距 */ column-gap: 12px; /* 单独覆盖列间距 */ }老版本浏览器的写法是grid-gap现在已经完全可以用gap替代放心写就行。这个属性对后台管理系统、卡片网格这类间距要求整齐划一的场景极其友好能省掉大量“改间距改到怀疑人生”的时间。3. 把项目放到指定位置网格线、span 与区域命名3.1 网格线定位精确控制起点和终点Grid 排布项目时默认情况是按顺序自动填充但真正的威力在于手动指定位置。定位的核心就是利用之前讲的网格线编号。每个项目都可以设置四个属性grid-row-start项目从第几条横向网格线开始grid-row-end项目到第几条横向网格线结束grid-column-start项目从第几条纵向网格线开始grid-column-end项目到第几条纵向网格线结束简写形式更常用.item { grid-column: 1 / 3; /* 从第 1 条纵向线到第 3 条纵向线即占 2 列 */ grid-row: 1 / 2; /* 从第 1 条横向线到第 2 条横向线即占 1 行 */ }这种写法的好处是你能精确指定任何一个项目在网格里的位置完全不按照 DOM 顺序。比如一个项目在 HTML 里排第三你也可以让它出现在第一行第一列这种能力在改版、重组页面、或者做跨区域海报布局时非常有用。如果不想记精确的结束线可以用span关键字含义是“跨多少个轨道”.item { grid-column: 2 / span 3; /* 从第 2 条线开始跨 3 列相当于 2 / 5 */ }注意一个坑span写在斜杠左边和右边语义上是不同的。2 / span 3是“从第 2 条线开始跨 3 列”span 2 / 4是“跨 2 列从第 2 条线左侧出发让结束线落到第 4 条线”本质都是指定起止区间。这两个写法很容易被搞混我建议新手统一用开始线 / span 数量这种最直观的组合省得算错。负数编号也常用grid-row: 1 / -1表示从第 1 条线到最后一条线等价于“占满所有行”。这种写法在实现“内容占满整个网格高度”的场景非常实用不用纠结一共定义了几行。3.2 区域命名让布局像平面图一样可读网格线定位虽然精确但属性写多了代码可读性会直线下降。尤其是页面级骨架比如“上边 header、左边侧边栏、中间主体、下边 footer”用一堆数字编号很容易把自己绕晕。这时候grid-template-areas就是救星。你可以在容器上画一个“字符版平面图”.page { display: grid; grid-template-columns: 220px 1fr; grid-template-rows: 60px 1fr 60px; grid-template-areas: header header sidebar content footer footer; }然后每个子元素通过grid-area属性指定自己属于哪个区域即可.header { grid-area: header; } .sidebar { grid-area: sidebar; } .content { grid-area: content; } .footer { grid-area: footer; }这样布局长什么样光看grid-template-areas那几行字符串就能一目了然第一行两个格子都叫 header所以 header 横跨整行第二行左边是 sidebar右边是 content第三行 footer 横跨整行。页面改版时调整字符画的位置就能改变整体布局不需要动 DOM 顺序。grid-template-areas有几个硬性规则必须遵守所有行必须具有相同数量的列也就是说字符画必须是矩形不能有缺角每个区域名必须形成矩形不能用名字围出一个 L 形空单元格用句点.表示。如果违反这些规则整个grid-template-areas声明会直接无效布局立刻崩掉。我第一次用时就在非矩形区域上卡了半天后来养成习惯先在草稿纸上画格子再数一遍每行字符数再写代码再也不出这种问题了。3.3 auto-fill 与 auto-fit少写一堆媒体查询的关键repeat()的第一个参数除了能写具体数字还能写auto-fill或auto-fit。它们都是“让浏览器自动决定列数”但行为有细微区别这个区别坑过很多人。两者的共同前提是配合minmax()使用比如grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));auto-fill的逻辑是在容器宽度内尽可能多地生成满足最小宽度要求的轨道。即使项目数量不足生成的多余空轨道也会保留下来。因此当只有 3 个项目、但容器能塞下 5 列时右侧会出现空列后面的项目不会自动拉宽填补。auto-fit的逻辑是同样尽量生成轨道但空轨道会被折叠为 0。换句话说项目数量不足时剩余空间会平均分给已有的项目让它们自动铺满整行。实操感受是展示类卡片列表用auto-fit更美观因为卡片会自动拉伸视觉上没有大片空白如果你需要固定卡片宽度、不让他们拉伸就选auto-fill。过去做响应式靠的是写三四个媒体查询断点切换grid-template-columns现在一句repeat(auto-fit, minmax(240px, 1fr))全搞定是我最常用的响应式方案。3.4 组合技巧同时使用网格线和区域命名在大型布局里网格线定位和区域命名可以混用。你可以给网格线也起名字比如.container { display: grid; grid-template-columns: [sidebar-start] 220px [content-start] 1fr [content-end]; }然后项目里写.sidebar { grid-column: sidebar-start / content-start; }这种写法比纯数字好维护但又比区域名字更灵活适合那种“区域数量很多、或者区域会重叠”的复杂 dashboard。不过新手不建议一上来就混用先把两种方式分别吃透再考虑组合不然排错时容易分不清问题出在名字还是编号上。4. 对齐与间距Grid 里最容易绕晕的一组属性4.1 两组对齐属性先搞清楚对象是谁Grid 里有六个对齐属性我见过大部分新手第一次接触时都会卡在这里。卡壳的根本原因是Flex 里也有justify-content和align-items但 Grid 里这些属性控制的对象和语义完全不同。第一组是“项目在单元格内部怎么摆”属性控制方向可选值作用对象justify-items水平方向start / end / center / stretch所有项目在其单元格内的水平对齐align-items垂直方向start / end / center / stretch所有项目在其单元格内的垂直对齐justify-self水平方向start / end / center / stretch单个项目的水平对齐覆盖容器设置align-self垂直方向start / end / center / stretch单个项目的垂直对齐覆盖容器设置第二组是“所有轨道作为一个整体在容器里怎么摆”属性控制方向可选值作用对象justify-content水平方向start / end / center / space-between / space-around / space-evenly所有列轨道在容器内的水平分布align-content垂直方向start / end / center / space-between / space-around / space-evenly所有行轨道在容器内的垂直分布这两组之间的区别我常用一个例子说明容器宽度 600px三列分别 100px。此时三列总宽度只有 300px容器里还剩 300px 空白。justify-content: center会让三列作为一个整体居中整体之间相对位置不变而justify-items管的是每一列里那个项目自身的位置比如列宽 100px、项目实际尺寸 60pxjustify-items: center让它在这个 100px 里居中。默认值stretch是最容易被忽略的。项目默认会拉伸填满整个单元格所以很多时候你不加任何对齐属性项目就已经铺满了。这也是为什么有人设置了justify-items却没反应——因为项目默认就是 stretch你先给它一个固定宽度再看这个属性才有效果。简写place-items可以同时设置垂直和水平place-items: center center; /* 等价于 align-items: center; justify-items: center; */如果只写一个值另一个也会使用同样的值place-items: center就是垂直水平都居中。这个简写在做“单元格内居中”时特别省事。4.2 margin: auto 在 Grid 里是个隐藏大招在 Grid 项目上设置margin: auto效果和 Flex 里完全不一样它会同时让项目在水平和垂直方向居中且不支持任何别的方式覆盖。什么意思以前要实现一个元素绝对居中可能要写定位加 transform或者 display: flex 加 align-items/justify-content。在 Grid 里只要项目本身占据了一个单元格你给它写.item { margin: auto; }它就会在这个单元格内居中。这个技巧在 Icon 按钮、数字角标、单格子内容居中时非常好用而且配合表格类布局甚至能实现“某个格子内容居中、其他格子内容左对齐”这种局部控制比 flex 的容器级对齐更精准。用的时候注意一个冲突点如果项目上同时使用了justify-self或align-selfmargin: auto的优先级会高过它们因为 auto margin 在实际渲染时会吸附所有可用空间。所以二者混用时要有个心理预期。4.3 gap 和 margin 的选择建议有些从 Flex 转过来的同学还是习惯用 margin 在 Grid 里做间距能跑但很痛苦。Grid 的gap属性会把间距直接算入轨道布局项目本身的尺寸不会因为间距而变化也不用额外处理“最后一个项目没有 margin”的边界。我的建议是Grid 里的行列间距一律优先gap如果遇到“某个项目需要额外缩进”这种个性需求再用 margin 做补充。两条准则一组合间距代码基本不会乱。5. 实战经典页面骨架与自动填充卡片网格5.1 实战一经典页面骨架用 grid-template-areas 一次成型后台管理系统的页面结构十有八九是顶栏、侧边栏、内容区、底栏。用 Grid 来做代码非常整洁div classlayout header classheader顶部导航/header aside classsidebar侧边菜单/aside main classmain主内容区/main footer classfooter版权信息/footer /div.layout { display: grid; grid-template-columns: 220px 1fr; grid-template-rows: 60px 1fr 50px; grid-template-areas: header header sidebar main footer footer; height: 100vh; gap: 0; } .header { grid-area: header; background: #2c3e50; color: #fff; } .sidebar { grid-area: sidebar; background: #34495e; } .main { grid-area: main; overflow: auto; padding: 20px; } .footer { grid-area: footer; background: #1a252f; color: #fff; }几个要点说一下给.layout设置height: 100vh再配grid-template-rows: 60px 1fr 50px可以让内容区自动撑满剩余高度这个“中间自适应、上下固定”的经典后台布局一行声明就完成了。如果要做移动端适配让侧边栏变到顶部或隐藏只需要在媒体查询里改grid-template-areas不需要改动 DOM。比如把sidebar main改成main main侧边栏区域直接没了。内容区最好加overflow: auto避免长内容把网格行高撑爆。这是我最推荐新手复刻的第一个 Grid 实战因为它能快速建立“区域命名布局”的信心成就感来得特别快。5.2 实战二自适应卡片网格一行响应式电商商品列表、博客文章卡片、图片墙这类“卡片数量不定屏幕宽度变化时列数跟着变”的需求过去要写媒体查询加 flex-wrap现在用 Grid 的自动填充一行解决.card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 20px; }配合一段简单的 HTMLdiv classcard-grid div classcard卡片1/div div classcard卡片2/div div classcard卡片3/div div classcard卡片4/div /div这个网格的行为是这样的当容器宽度小于 480px 时只放得下一列宽度在 480px 到 720px 之间时能放下两列继续变宽就自动三列、四列。每张卡片的最小宽度被限定在 240px不会缩得太小同时每列会尽量占用剩余空间。整个过程不需要任何媒体查询浏览器自动计算最合适的列数。如果想让卡片在项目较少时也能拉伸铺满整行把auto-fill换成auto-fit即可。这两个值的选择就是我 3.3 节讲的那个区别在真实场景中的体现。5.3 实战三产品展示墙网格线与 span 做跨行列做产品海报墙时经常需要让某些格子突出显示比如第一个卡片占两行两列其他卡片正常大小。用网格线定位加 span 可以很轻松地实现div classgallery div classfeature主打产品/div div普通产品/div div普通产品/div div普通产品/div div普通产品/div /div.gallery { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 120px; gap: 10px; } .feature { grid-row: span 2; grid-column: span 2; }这里的feature项目通过grid-row: span 2和grid-column: span 2跨了两行两列其他项目则自动填充剩余位置。配合grid-auto-rows设好的固定行高整个展示墙的格子高度就统一了而当项目数量超出显式轨道时自动生成的行也会沿用这个高度。这种布局放在以前要用绝对定位或一整段 JS 去算位置现在只要两个属性。另一个常见需求是“自适应高度下的卡片墙”。这时可以把固定行高去掉改用grid-auto-rows: minmax(100px, auto)让卡片高度根据内容伸缩同时保证最小高度一致。5.4 组合思想页面骨架用 Grid组件内部用 Flex实战做多了你会慢慢形成肌肉记忆Grid 管大局Flex 管细节。一个典型的例子是卡片组件本身。整个卡片阵列用 Grid 排布但卡片内部的按钮区、标签区、标题和描述的对齐用 Flex 来处理更自然div classcard-grid div classcard h3标题/h3 p描述文字/p div classactions button查看/button button删除/button /div /div /div.card { display: flex; flex-direction: column; justify-content: space-between; } .card .actions { display: flex; gap: 8px; justify-content: flex-end; }外层网格负责卡片排列内层 Flex 负责按钮分布。这套组合拳打下来几乎能应付我遇到的所有常见业务布局而且代码结构非常清晰看一个文件就能快速定位问题出在“大布局”还是“小组件”。6. 常见问题排查与调试实录6.1 踩坑速查表十个高频问题与处理方法Grid 上手期最容易出的问题我整理成了一张速查表。每一个都是我或身边同事实际踩过的对照排查能省很多时间。现象根本原因解决方案子元素没进网格直接叠在一起或乱跑把display: grid写在了子元素上容器没有触发确认display: grid写在父容器上设置了grid-column没反应定位属性写错对象写在容器而非项目上定位属性必须写在直接子项目上1fr 的列被内容撑爆宽度超出预期Grid 项目默认min-width: auto内容撑开轨道给项目加min-width: 0或overflow: hiddenrepeat(auto-fill)右侧出现多余空白auto-fill会保留空轨道改成repeat(auto-fit, ...)grid-template-areas整个失效区域不是矩形或各行字符数不一致检查字符画是否规则空位补.justify-items设置后没变化项目默认 stretch属性看不出效果先给项目设置固定宽度再观察gap 没有生效浏览器版本过老或还写着grid-gap新版浏览器直接写gap老项目改grid-gap行高被内容撑得忽大忽小只设置了固定grid-template-rows但个别项目内容过长给行用minmax(100px, auto)做自适应项目顺序和 DOM 顺序不一致手动指定了网格线位置或使用了dense属性确认是预期行为注意可访问性子元素包含图片时网格高度变形项目内图片超出容器宽度撑破最小尺寸给图片设置max-width: 100%项目加min-width: 0其中“min-width: 0解决内容撑破”这条我想多说两句因为它是fr和auto轨道最容易踩的隐性坑。Grid 项目的min-width默认是auto意味着项目内容的最小宽度会参与轨道尺寸计算。当项目里有一段超长文字或一张宽图时即使你写的是1fr这个轨道也可能被内容撑得超出预期宽度。解决办法是给项目设置min-width: 0让轨道能够正常压缩。这个问题在 Flex 里同样存在所以熟悉min-width: 0这个修复是 CSS 布局的重要基本功。6.2 调试工具用 Chrome DevTools 的 Grid Inspector 看网格写 Grid 布局时我最推荐的调试工具是 Chrome DevTools 内置的 Grid Inspector。操作方法很简单在 Elements 面板选中设置了display: grid的元素在样式面板里点击grid字样旁边的小徽标像网格图标页面上会直接显示网格线、轨道尺寸和编号。这个工具能显示每条网格线的序号1、2、3…、轨道宽度、以及项目跨线的范围。我第一次用的时候把grid-row: 2 / 4写错成2 / 5当时怎么都对不上最后打开 Grid Inspector 一看编号清清楚楚一眼定位到问题。Firefox 的开发者工具也有类似功能而且在检查grid-template-areas时更直观会直接显示区域名称。调试建议遇到布局对不上时先别急着改代码打开网格高亮数一遍网格线编号再对照你写的 start/end 值。很多时候问题出在“对编号的理解偏差”而不是属性写错。6.3 排错思路先小步验证再整体重构在 Grid 上看到奇怪布局时我习惯从小处验证。比如你先写一个只有一个项目的最小网格测试grid-column的定位逻辑再逐步添加项目观察自动排列的影响。这种“小步验证”能帮你快速隔离问题到底来自容器定义、项目定位还是内容本身。如果确认代码逻辑没毛病但布局依然不对百分之八十的情况出在某个默认值上项目默认 stretch 导致尺寸超预期或默认min-width: auto把轨道撑开了。先处理这两个默认值相关的因素很多问题会迎刃而解。说实话Grid 刚出来那年我也没放在心上真正用顺手是在一个后台项目里。当时几十个页面全是“左侧固定侧栏 顶部栏 内容区”的骨架用 Flex 做了两周各种对齐和间距处理到想放弃。改成 Grid 之后每个页面大概就是几行grid-template-areas的事后来再也没有回头。如果让我给一个学习路径上的建议学 Grid 别一上来就背属性先在纸上把页面画成格子想清楚哪些格子合并、哪些区域自适应、哪些列要固定再去翻属性表。你会发现很多曾经要靠 JS 计算、靠清浮动 hack 的布局现在只是 Grid 的一行声明。等你把这种“先画格、再布局”的思维方式刻进习惯里CSS Grid 就不再是文档里的炫技功能而是日常开发里最顺手的那把刀。
返回列表