细说 CSS grid 网格布局子元素相关属性

笔记哥 / 04-18 / 32点赞 / 0评论 / 704阅读
学习本文之前,建议先学习上一篇了解父元素的相关属性。 前文对 grid 网格布局中父元素容器相关的 CSS 属性做了详细介绍,本篇将继续学习子元素相关的 CSS 属性。 网格布局的一大波样式属性,父元素占据了大半江山,子元素嘛相对就少了一些~~ 本文中的中的示例基础代码: ```csharp
A
B
C
D
``` ## 子元素相关的 CSS 属性 `grid-column-start` 控制子元素列从哪根线开始。 `grid-column-end` 控制子元素列在哪条网格线结束。 `grid-column` 简写属性 grid-column-start 、 grid-column-end。 `grid-row-start` 控制子元素行从哪根线开始。 `grid-row-end` 控制子元素行在哪条网格线结束。 `grid-row` 简写属性 grid-row-start 、 grid-row-end。 `grid-area` 指定子元素属于哪个命名区域或简写位置。 `justify-self` 覆盖容器的 justify-items,控制单个子元素的行对齐。 `align-self` 覆盖容器的 align-items,控制单个子元素的列对齐。 `order` 调整子元素的显示顺序(类似 Flexbox)。 `z-index` 控制子元素的层叠顺序。 ### 设置子元素列的开始位置和结束位置 `grid-column-start` 用于设置子元素列的开始位置,从哪条网格线开始 `grid-column-end` 用于设置子元素列的结束位置,在哪条网格线结束 **以 grid-column-start 为例:** ```csharp grid-column-start: auto; /* 默认值,自动分配 */ grid-column-start: 4; /* 从第 4 根线开始 */ grid-column-start: span 2; /* 定义跨两列 */ grid-column-start: some-grid-area; /* 从命名区域 some-grid-area 开始 */ grid-column-start: span some-grid-area; /* 未知的渲染方式 */ grid-column-start: span some-grid-area 3; /* 未知的渲染方式 */ ``` 使用数字和关键字 span 示例: ```csharp .box { /* 设置网格五行五列 */ grid-template-columns: repeat(5, 1fr); grid-template-rows: repeat(5, 1fr); } .box .item:nth-child(1) { /* 第一个子元素从第 4 根线开始 */ grid-column-start: B; } .box .item:nth-child(2) { /* 第二个子元素跨两列 */ grid-column-start: span 2; } ``` 注意看右侧网格线,由于第二个子元素要占用两列,网格放不下了,所以从第二行开始。显示效果: ![](https://cdn.res.knowhub.vip/c/2504/19/2febd912.png?G1UAAETn9LyUQnDIvtMdbIlTE20GKtIIKvWs13vO2jfR94dAND%2bj9Rn7wy9an0HFL7iRQAoUKXCFs3F1eGIFAxCTvEYA) 使用命名区域设置子元素开始位置: ```csharp .box { grid-template-areas: "A1 A1 F2 G3 G3" "A1 A1 F2 B4 B4" "C5 C5 C5 C5 C5" "D6 D6 D6 D6 D6" "E7 E7 E7 E7 E7"; } .box .item:nth-child(1) { grid-column-start: F2; /* 从 F2 开始 */ } .box .item:nth-child(2) { grid-column-start: span G3; /* 无效 */ } .box .item:nth-child(3) { grid-column-start: span D6 4; /* 无效 */ } ``` **重点:**不知道是我姿势不对,还是 MDN 文档有问题, `grid-column-start: span G3;` 和 `grid-column-start: span D6 4;` 两种写法浏览器解析了,没报无效值,但是实际没啥效果~~头大.... ![](https://cdn.res.knowhub.vip/c/2504/19/f60ea333.png?G1UAAMTsdJxIknqk26hD2jvFHc1ARRpBpZ71es9Z%2byb6flfWFJ%2fR%2bvT94RetTydYZiukrOCEEKSySdGawUFgyBdQEddw) 不过 MDN 上找到这么一个例子: ```csharp .box { grid-template-columns: repeat(6, [col1-start] 1fr [col2-start] 3fr); } .item:nth-child(1) { grid-column: col1-start / col2-start 2; } .item:nth-child(2) { grid-row: 2; grid-column: col1-start 2 / span 2 col1-start; } ``` 实际使用是正常可以显示的,那么 `grid-column-start: span D6 4;` 这种写法应该是用于重复的命名行线,而不是命名区域。 **同时设置列起始和结束位置:** grid-column-end 与 grid-column-start 写法一样。 使用数字比较好理解: ```csharp .box { /* 设置网格五行五列 */ grid-template-columns: repeat(5, 1fr); grid-template-rows: repeat(5, 1fr); } .box .item:nth-child(1) { /* 从第 2 根线开始,结束在第 4 根线结束 */ grid-column-start: 2; grid-column-end: 4; } .box .item:nth-child(2) { /* 从第 2 根线开始,横跨四列 */ grid-column-start: 2; grid-column-end: span 4; } ``` 显示效果: ![](https://cdn.res.knowhub.vip/c/2504/19/be643873.png?G1UAAMTsdJzIixDpNuqQ9k5xp81ARRpBpZ71ev5%2fn4vo%2fZzBEu%2fZx%2fLz4Rd9LKdiFabE4AJBCKnBkmZpWUMyrWgmQNzTAQ%3d%3d) 使用命名区域设置时候又出幺蛾子了,感觉命名区域设置就不能带上 `span` 关键字~~ ```csharp .box { grid-template-areas: "A1 A1 F2 G3 G4" "A1 A1 F2 B4 B4" "C5 C5 C5 C5 C5" "D6 D6 D6 D6 D6" "E7 E7 E7 E7 E7"; } .box .item:nth-child(1) { /* 从 F2 开始,在 G3 结束 */ grid-column-start: F2; grid-column-end: G3; } .box .item:nth-child(2) { /* 嘿~不好意思,无效,span 只能跟数字,其他值都无效,还会导致网格多一列 */ grid-column-start: F2; grid-column-end: span G3; } .box .item:nth-child(3) { /* 也不是说此方法无效,它在表格后面多绘制了 10 列,无语了.... */ grid-column-start: F2; grid-column-end: span G3 10; } ``` 看效果: ![](https://cdn.res.knowhub.vip/c/2504/19/07b7488b.png?G1QAAOQ5d14KIEj0nXZQm6mbNgMSVQSVetbrPWftG%2bD7g5ElP6P1GfvDH1qfAeoV3YCRFQXJ04VOJqguidRKMaaS1wg%3d) `grid-column-end: span G3 10;` 这种写法你说他无效吧,它在网格后面多绘制了 10 列,你说有效吧,又没办法理解浏览器的绘制方式。 按照 MDN 的说法,还支持 `grid-column-end: 10 G3 span;` 这种写法,实际效果与上面一样,还是给网格多绘制了 10 列。 但如果使用 `grid-template-columns: repeat(5, 1fr);` 控制了网格列数,那么就不会多绘制那么多列了,但也无法理解他的绘制方式。 **可能跟上面一样,用于重复的命名行线,而不是命名区域。** ### 设置子元素行的开始位置和结束位置 `grid-row-start` 用于设置子元素行的开始位置,从哪条网格线开始 `grid-row-end` 用于设置子元素行的结束位置,在哪条网格线结束 设置行的两个属性与设置列的属性一样,使用 `命名区域` 有 span 关键字时设置行起始和结束位置还是会出幺蛾子,就不再一一演示。 看能理解的示例: ```csharp .box { grid-template-areas: "A1 A1 F2 G3 G4" "A1 A1 F2 B4 B4" "C5 C5 C5 C5 C5" "D6 D6 D6 D6 D6" "E7 E7 E7 E7 E7"; } .box .item:nth-child(1) { grid-column-start: 1; grid-column-end: 3; grid-row-start: 1; grid-row-end: 3; } .box .item:nth-child(2) { grid-column-start: 2; grid-column-end: span 2; grid-row-start: 2; grid-row-end: span 2; } .box .item:nth-child(3) { grid-column-start: F2; grid-column-end: G3; grid-row-start: G3; grid-row-end: B4; } ``` 显示效果: ![](https://cdn.res.knowhub.vip/c/2504/19/dffcca23.png?G1QAAGQ9PS%2faVov6Tju6JYaEZkCiiqBSz3q99%2b7TAL7fGVniM%2ftYfj78oY%2floJbRCjCyoiB4qmhUxIrUoMSUUmaMezo%3d) ### 行列的简写属性 使用 `grid-column` 和 `grid-row` 可简写列和行的开始结束位置。毕竟一次写四个属性太麻烦了,只写两个就省了一半。 ```csharp .box { grid-template-areas: "A1 A1 F2 G3 G4" "A1 A1 F2 B4 B4" "C5 C5 C5 C5 C5" "D6 D6 D6 D6 D6" "E7 E7 E7 E7 E7"; } .box .item:nth-child(1) { grid-column: 1 / 3; grid-row: 1 / 3; } .box .item:nth-child(2) { grid-column: 2 / span 2; grid-row: 3 / span 2; } .box .item:nth-child(3) { grid-column: span 3 / 2; /* 表示此单元格跨 3 列,在第二根网格线结束 */ grid-row: 3 / span 2; /* 表示此单元格行从第三根网格线开始,跨 2 行 */ } .box .item:nth-child(4) { grid-column: F2 / G3; grid-row: G3 / B4; } ``` 显示效果: ![](https://cdn.res.knowhub.vip/c/2504/19/e1be5901.png?G1UAAMTW3DgpQH5I22gDdWfqnTUDFWkElXrW6%2fn%2ftS%2bi9wtlLfkerc%2fYH37R%2bgyCn%2bxGygouSEEquxjM4UkMgJR61LxGAA%3d%3d) 设置位置时,可使用负数,表示倒数,比如:`grid-column: -1 / span 2;` 表示从倒数第一根网格线开始,跨 2 列。 ### 使用命名行线 虽然个人觉得这种用法有点难理解,但浏览器是支持这种写法的,可以不用,但不能不会,对不~ ```csharp .box { grid-template: [header-left] "head head" 30px [header-right] [main-left] "nav main" 1fr [main-right] [footer-left] "nav foot" 30px [footer-right] / 120px 1fr; } .box .item:nth-child(1) { grid-row: header-left / footer-left; } ``` 显示效果: ![](https://cdn.res.knowhub.vip/c/2504/19/f77d3122.png?G1UAAGSd87ygE2n9TjyqCQIJNAMVaQSVetbrPWftG%2bD7g5E1P6P1GfvDL1qfAcUv9AqMXFCRAhk6GQqqJnKpQk5meY0A) ### 使用 grid-area 插旗 前文介绍过 `grid-template-areas` 用于划分地盘,子元素就使用 `grid-area` 来插旗,指定子元素在哪块地盘。 看看经典的管理系统结构: ```csharp .box { grid-template-areas: "header header header" "left main right" "footer footer footer"; grid-template-columns: 10% 1fr 10%; grid-template-rows: 30px 1fr 40px; } .box .item:nth-child(1) { grid-area: header; } .box .item:nth-child(2) { grid-area: left; } .box .item:nth-child(3) { grid-area: main; } .box .item:nth-child(4) { grid-area: right; } .box .item:nth-child(5) { grid-area: footer; } ``` 显示效果: ![](https://cdn.res.knowhub.vip/c/2504/19/6ebab4dc.png?G1UAAMT0bJzoqaJsox%2f6n3gkNAMVaQSVetbrvXefRvT9xmDxz%2bxj2fnwiz6WUaoZtRCDEwQuBEUNChUtLsScIdAIv6cB) ### 覆盖父元素的对齐方式 `justify-self` 和 `align-self` 可用于覆盖父元素设置的对齐方式(justify-items / align-items)。某个子元素想要特立独行的时候,就可以派上用场了。 ```csharp .box { grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(4, 1fr); align-items: center; justify-items: center; } .box .item { width: 40px; height: 40px; } .box .item:nth-child(2) { align-self: flex-start; } .box .item:nth-child(3) { justify-self: flex-end; } ``` 显示效果: ![](https://cdn.res.knowhub.vip/c/2504/19/9016ebdd.png?G1UAAOQ8bZy4l8M26nBtokhoBirSCCr1rNd77z4N4PudkTU%2bs4%2fl58Mv%2blgOqWasBoycUBECFaxUSCTnQGxKxmQS93Q%3d) ### 调整子元素顺序 接上例中的代码,直接添加 `order` 属性可调整子元素顺序。 排序规则:越小值则越靠前,默认值为 0。 ```csharp .box .item:nth-child(1) { order: 3; /* 第一个子元素排第三位 */ } .box .item:nth-child(2) { order: 2; /* 第二个子元素排第二位 */ } .box .item:nth-child(3) { order: 1; /* 第三个子元素排第一位 */ } .box .item:nth-child(4) { order: 4; /* 第四个子元素排第四位 */ } .box .item:nth-child(5) { order: 5; /* 第五个子元素排第五位 */ } ``` 显示效果: ![](https://cdn.res.knowhub.vip/c/2504/19/1e8689ad.png?G1UAAOQ5d14KICT0nXZQm6mbNgMVaQSVetbrPWftG%2bD7g5ElP6P1GfvDL1qfAeoXegVGVhSkQIZORiasiczFa0GTvEYA) ### 控制子元素的层叠顺序 当网格布局中两个子元素叠在一起显示时候,这会可拿出 `z-index` 属性控制子元素层叠顺序,想谁在上面谁就在上面。 规则:谁的 z-index 值大谁就在上面。 ```csharp .box .item:nth-child(1) { grid-column: 1 / span 2; grid-row: 1 / span 2; background-color: red; } .box .item:nth-child(2) { grid-column: 2 / span 2; grid-row: 1 / span 2; background-color: yellow; } /* 控制第二个 box 中的第一个子元素在上面 */ .box:nth-child(2) .item:nth-child(1) { z-index: 2; } ``` 以上代码由于 grid-row 值相同,所以两个子元素会叠在一起,然后使用 z-index 控制了第二个盒子的第一个子元素。 显示效果: ![](https://cdn.res.knowhub.vip/c/2504/19/3a98e169.png?G1QAAMT0bJzoqUJtox%2f6n3gkNAMSVQSVetbrvXefRvT9xmDxz%2bxj2fnwhz6WUdIMLcTgBIHzoUJDZRGFi0E4l5jg9zQ%3d) ## 总结 网格布局这一壶终于喝完了,它包含的内容太多太广了,要熟练使用还需要多加练习才行,后续文章还会更新弹性盒子与网格布局的对比,以及它俩的应用场景,敬请期待。 2023 版本的 CSS 规范还提出了子网格 `Subgrid` 概念,如需了解更多请参阅后文中的参考资料链接。 参考资料: https://developer.mozilla.org/en-US/docs/Web/CSS/grid https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout/Subgrid