学习网格布局时,你可能会在网络上看到很多文章,内容不同,属性不同,真是让人摸不着头脑,到底哪个才是正确的?看了本篇文章,我想你会豁然开朗。
比如,一会儿用grid-rows,一会儿用grid-definition-rows,一会儿用grid-template-rows。
再比如,一开始说grid-row是grid-row-align和grid-row-span的标准缩写,grid-column是grid-column-align和grid-column-span的标准缩写。
后来说,grid-row是grid-before/after的缩写,grid-column是grid-start/end的缩写。
现在说,grid-row是grid-row-start和grid-row-end的标准缩写,grid-column是grid-column-start和grid-column-end的标准缩写。
总之一句话,这都是css module grid草案惹的祸!2010年,Microsoft提出了Grid布局,2017年还处于草稿阶段。他们那些所谓的标准在不断的修改,就像你写代码一样,需求变了,代码就得跟着变。昨天写的是a,今天可能换成了b,或许后天换成了c,在变化中求生存。代码都有价值,网友们的文章也都有价值,只是发挥作用的时间不同罢了,没有谁对谁错。
因此,我这篇文章也有可能会过期,但在标准正式建立之前,或许还有点用。如果grid正式标准和我这篇文章出入不大,我就在这篇基础上修修补补,如果差异太多,我会新写一篇关于grid的文章。至于当前这篇grid的文章,就让它随着时间的流逝被淘汰吧。
一、参考的链接
1、W3C规范
https://www.w3.org/TR/css3-grid-layout/
2、MDN
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout
3、一些例子
https://gridbyexample.com/examples/
4、大漠老师及其他网友的文章
http://www.w3cplus.com/blog/tags/355.html
http://chris.house/blog/a-complete-guide-css-grid-layout/
二、浏览器兼容性
每每用到新特性,一般少不了考虑浏览器兼容性,意思就是这个属性能不能在各大浏览器上起作用,而且是按照开发者期望的那样表现元素。
可以看到chrome,IE10+都已经支持grid了,我的chrome版本是61.0。看到有好多人说要在chrome浏览器开启CSS Grid Layout功能,具体操作如下。不过,我的这篇文章写得比较迟,浏览器已经逐步支持啦,不开启实验室,也能使用grid属性。
在浏览器地址栏输入网址:
chrome://flags#enable-experimental-web-platform-features
定位到需要的选项,点击“启用”(enable)按钮,如下图所示:
三、grid基本概念
为什么要学习grid?flexbox是一维布局,grid是二维布局,现在浏览器正在逐步实现网格布局,所以grid会成为明天网页布局的一种重要方式。
在正式介绍grid语法前,我分享一个问题,sublime3126的智能提示css插件还没有跟上W3C规范的脚步,它还在智能提示grid-rows,还不支持grid-template-rows。所以你如果用sublime3126写网格布局,还是纯手写样式吧,不要用什么快捷键了,除非哪天sublime的插件跟上节奏了,能够提示grid-template-rows时,你再用也不迟。所以,这时候就显现出手写代码不依赖工具的真功夫了。
1、显式网格
我们可以通过grid-template-rows、grid-template-columns、grid-template-areas几个属性定义固定的网格线名称和网格轨道。这种手动定义的网格我们称之为显式网格。
2、隐式网格
如果网格中有更多的网格项,或者网格项被放置在显式网格之外,网格容器就会通过向网格中添加网格线来自动生成网格轨道。显式网格和这些额外的隐式轨道和网格线构成了所谓的隐式网格。
3、网格容器(Grid Containers)
通过“display”属性给一个元素显式的设置了“grid”或者“inline-grid”属性值,这个元素将自动变成网格容器。
因为网格容器不是块容器,所以一些属性在网格布局中将会失效:
多栏布局模块中的所有“column-*”属性运用在网格容器上将失效; “::first-line”和“::first-letter”这样的伪元素不能应用在网格容器上。
4、网格项目(Grid Item)
因为网格容器不是块容器,所以一些属性在网格布局中将会失效:
“float”和“clear”使用在网格项目上将失效; “vertical-align”使用在网格项目上将失效。
5、网格线(Grid Line)
6、网格轨道(Grid Track)
两条相邻网格线之间的空间。
7、网格区域(Grid Area)
网格区域是一个逻辑空间,主要用来放置一个或多个网格项目。
8、网格项目顺序(order)
网格项目顺序可以像flexbox一样,通过order属性对网格项目重排顺序。
9、网格流
在一个被显式声明为网格的容器中,其所有子元素自动被认定为网格单元格,而这些网格单元格在没有被显式设置明确位置时,浏览器会自动为这些网格单元格分配位置,按照先后顺序从左向右,或从上到下排列。这就是CSS Grid Layout中的网格流。
四、grid容器属性
在讲述语法前,这里做个声明,如果是常量属性值,就直接写关键字,如果是变量,有多种情况,我会用<>把属性值包起来,这样可以有效区分关键字和变量值,以便更好的理解语法。另外,grid-template-columns和grid-template-rows属性取值和语法相同,就默认用grid-template-columns举例说明网格宽度的伸缩,至于grid-template-rows,参考grid-template-columns的讲解即可。
1、display: grid | inline-grid | subgrid;
.container{ display: grid | inline-grid | subgrid; }
2、grid-template-rows和grid-template-columns
这两个属性用于定义网格线名称和网格轨道大小。
.container{ display: grid; grid-template-columns: <line-name> <track-size>; grid-template-rows: <line-name> <track-size>; }
A、网格线名称
CSS Grid Layout的自定义网格线名称一般都放在()内。
.container{ display: grid; grid-template-columns: (col1-start) 100px (col1-end) 10px (col2-start) 100px (col2-end); grid-template-rows: (row1-start) auto (row1-end) 10px (row2-start) auto (row2-end); }
B、网格轨道大小取值
b.1、<length> 是一个非负的长度,比如50px,5rem。 b.2、<percentage> 是一个百分数,相对于网格容器,比如20%。 b.3、<flex> 是一个剩余空间的分数,比如1fr,属于自适应属性。 b.4、max-content 是一个关键字,直接写max-content,表示内容的最大宽度,属于自适应属性。 b.5、min-content 是一个关键字,直接写min-content,表示内容的最小宽度,属于自适应属性。 b.6、minmax(<min>, <max>) 是一个函数,属于自适应属性,但是会有一个范围限制伸缩。比如minmax(min-content, 200px)。参数min和max的取值可以是length值,percentage值,flex值,max-content,min-content,auto。 如果<min>比<max>大,<max>会被忽略,结果会以<min>为准。如果<min>比<max>小,内容会参考<min>和<max>来显示。 b.7、auto 是一个关键字,直接写auto,属于自适应属性。 b.8、fit-content(<length> | <percentage>) 是一个函数,属于自适应属性。比如fit-content(200px),如果内容宽度小于200px,就显示内容的实际宽度,如果内容宽度大于200px,就只显示200px宽度。 b.9、repeat( [ <positive-integer> | auto-fill | auto-fit ] , <track-list> ) 是一个函数,允许你定义一个模式重复n次,比如repeat(4, 10px [col-start] 30% [col-middle] 400px [col-end])。如果不想设置固定重复次数,可以使用auto-fill和auto-fit这样的关键词来替代固定的重复次数。
C、一些例子
grid-template-columns: 300px 1fr 3fr 20%; 上面的代码声明了4列,第1列的宽度是300px,最后1列的宽度是网格容器宽度的20%,第2列是容器剩余宽度的四分之一,第3列是容器剩余宽度的四分之三。 grid-template-columns: minmax(max-content, 300px) minmax(min-content, 1fr) 150px; 上面的代码声明了3列,第3列的宽度是150px,第1列会根据内容自适应,如果内容宽度大于300px,会按照内容实际宽度显示。如果内容宽度小于300px,则显示300px。第2列会随着第一列的宽度自适应,如果第1列的宽度太大了,第2列的最小内容宽度就是显示宽度,不能再退缩了。 grid-template-columns: fit-content(300px) fit-content(300px) 1fr; 假设第1列内容很少,不够300px宽;第2列内容比较多,大于300px;第3列内容多少随意。 上面的代码声明了3列,第1列会根据内容自适应宽度,第2列只显示300px宽,内容多了的话,自动换行。 grid-template-columns: repeat(2, 50px 1fr) 100px; 上面的代码声明了5列,第5列的宽度是100px,剩下的宽度平均分成两半,都有相同的网格项,都有两列。其中一列宽度是50px,另一列宽度是容器剩余宽度的1倍。 grid-template-columns: repeat(auto-fill, [col-start] minmax(100px, 1fr) [col-end]); 上面的代码显式声明了1列,容器中有多少个div,就会重复多少次该列,自动填充,最小内容宽度为100px。不会因为内容宽度自由伸缩,只会自动换行。多余的div,多余的内容都会自动换行。 grid-template-columns: repeat(auto-fill, 10px [col-start] 30% [col-middle] 400px [col-end]); 上面的代码显式声明了3列,然后重复此3列,每行3列。每列不会因为内容宽度自由伸缩,只会自动换行。多余的div,多余的内容都会自动换行。 grid-template-columns: repeat(auto-fit, 250px); 和自动填充相似,但auto-fit会尽可能创建更多网格,空网格轨道也会被自动匹配。 grid-template-columns: repeat(auto-fill, 1fr); 只会创建一个轨道,因为一个带有1fr宽度轨道已经填充了整个网格容器。
/* 会尽可能自动匹配整行空间 */ grid-template-columns: repeat(auto-fit,minmax(100px,1fr)); /* 只会自动填充100px */ grid-template-columns: repeat(auto-fill,minmax(100px,1fr));
3、grid-template-areas,定义网格区域
在CSS Grid Layout中,定义网格区域有两种方式,一种是通过网格线来定义(详见下文),另一种是通过grid-template-areas来定义。
通过grid-template-areas属性定义网格区域的名称,通过grid-area属性指定哪个元素放什么网格区域,重复区域可以使用同一个名称来实现跨区域。对于空的轨道区域,可以使用点号.代表,比如侧边栏与主内容之间的间距。
.container { display: grid; grid-template-columns: 220px 20px 220px 20px 220px; grid-template-rows: auto; grid-template-areas: "header header header header header" "sidebar . content content content" "footer footer footer footer footer" } .header { grid-area: header; } .content { grid-area: content; } .sidebar { grid-area: sidebar; } .footer { grid-area: footer; }
4、grid-column-gap和grid-row-gap,网格线的大小
行列间距,该属性设置的值针对于行列间,不会在边界起作用。
.container{ grid-column-gap: <line-size>; grid-row-gap: <line-size>; }
.container{ grid-template-columns: 100px 50px 100px; grid-template-rows: 80px auto 80px; grid-column-gap: 10px; grid-row-gap: 15px; }
5、grid-gap
.container { grid-gap: <grid-column-gap> <grid-row-gap>; }
.container { grid-template-columns: 100px 50px 100px; grid-template-rows: 80px auto 80px; grid-gap: 10px 15px; }
如果没有指定<grid-row-gap>,则默认和<grid-column-gap>值一致。
6、justify-items
沿列轴对齐网格项中的内容(相反于align-item属性定义的沿行轴对齐)。此值适用于容器内所有的网格项。
.container { justify-items: start | end | center | stretch; }
7、align-items
沿行轴对齐网格项中的内容(相反于justify-item属性定义的沿列轴对齐)。此值适用于容器内所有的网格项。
.container { align-items: start | end | center | stretch; }
8、justify-content
当你使用px这种非响应式的单位对你的网格项进行大小设置时,你的网格大小可能小于其网格容器的大小。在这种情况下,你就可以设置网格容器内网格的对齐方式。此属性会将网格沿列轴进行对齐(相反于align-content属性定义的沿行轴对齐)。
.container{ justify-content: start | end | center | stretch | space-around | space-between | space-evenly; }
9、align-content
当你使用px这种非响应式的单位对你的网格项进行大小设置时,你的网格大小可能小于其网格容器的大小。在这种情况下,你就可以设置网格容器内网格的对齐方式。此属性会将网格沿行轴进行对齐(相反于justify-content属性定义的沿列轴对齐)。
.container{ align-content: start | end | center | stretch | space-around | space-between | space-evenly; }
10、grid-auto-columns 和 grid-auto-rows
指定任何自动生成的网格轨道(隐式网格跟踪)的大小。当你(使用 grid-template-rows/grid-template-columns属性)定义了显式网格,并在网格项中引用不存在的网格线来定位网格项,宽度为0的隐式网格轨道就会被创建来填补空白,这就是隐式网格轨道的诞生背景。
.container{ grid-auto-columns: <track-size> ...; grid-auto-rows: <track-size> ...; }
/* 隐式网格轨道的诞生 */ .container { grid-template-columns: 60px 60px; grid-template-rows: 90px 90px } .item-a { grid-column: 1 / 2; grid-row: 2 / 3; } .item-b { grid-column: 5 / 6; grid-row: 2 / 3; }
.item b开始于列线5并结束于列线6,但是我们从来没有定义列线5或6,于是隐式网格轨道由此产生。
/* 设置隐式网格轨道 */ .container { grid-auto-columns: 60px; }
11、grid-auto-flow
如果你不显式的在网格中放置网格项,自动布局算法就会自动踢出此网格项,此属性用来控制自动布局算法的工作原理。
.container { grid-auto-flow: row | column | row dense | column dense; }
在CSS Grid Layout中盒模型大小计算变成:容器width = margin-left + margin-right + padding-left + padding-right + content width + border-left-width + border-right+width。
12、grid-template,网格模板
grid-template是grid-template-rows、grid-template-columns、grid-template-areas的简写。
.container{ grid-template: none | <grid-template-rows> / <grid-template-columns> / <grid-template-areas>; }
grid-template: 100px 1fr / 50px 1fr;
grid-template: auto 1fr / auto 1fr auto;
.container{ 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; }
13、grid
grid是设置显式网格(grid-template-rows,grid-template-columns,grid-template-areas),隐式网格(grid-auto-rows,grid-auto-columns,grid-auto-flow),以及网格间隔(grid-column-gap,grid-row-gap)的缩写。
.container{ grid: none | subgrid | <grid-template-rows> / <grid-template-columns>/<grid-template-areas> /<grid-column-gap>/<grid-row-gap>| <grid-auto-flow> [<grid-auto-rows> [/ <grid-auto-columns>]]; }
五、grid项目属性
1、grid-column-start、grid-column-end、grid-row-start、grid-row-end
使用特定的网格线确定网格项在网格内的位置。grid-column-start/grid-row-start 属性表示网格项的网格线的起始位置,grid-column-end/grid-row-end属性表示网格项的网格线的终止位置。
.item{ grid-column-start: <number> | <name> | span <number> | span <name> | auto grid-column-end: <number> | <name> | span <number> | span <name> | auto grid-row-start: <number> | <name> | span <number> | span <name> | auto grid-row-end: <number> | <name> | span <number> | span <name> | auto }
/* 上面属性的取值都有以下4种 */ <line>: 可以是一个数字来引用相应编号的网格线,或者使用名称引用相应命名的网格线; span <number>: 网格项包含指定数量的网格轨道; span <name>: 网格项包含指定名称网格项的网格线之前的网格轨道; auto: 表明自动定位,自动跨度或者默认跨度之一。
如果没有声明grid-column-end/grid-row-end属性,默认情况下网格项的跨度为1。
网格项可以互相重叠,使用z-index属性控制堆叠顺序。
2、grid-column、grid-row
这个主要用来定义网格项目显示在哪行和哪列。grid-row是grid-row-start和grid-row-end的标准缩写,grid-column是grid-column-start和grid-column-end的标准缩写。
.item{ grid-column: <start-line> / <end-line> | <start-line> / span <value>; grid-row: <start-line> / <end-line> | <start-line> / span <value>; }
基于网格线使用关键词span实现单元格合并。
.item{ grid-column: 3 / span 2; grid-row: third-line / 4; }
3、grid-area,给网格项命名
给网格项命名,方便grid-template-areas引用,也方便grid-column-start、grid-column-end、grid-row-start、grid-row-end引用。
.item{ grid-area: <name> | <row-start> / <column-start> / <row-end> / <column-end>; }
组成网格区域的网格线顺序是row-start/column-start/row-end/column-end,每个网格线之间用/来分隔,它们可以是数字或名称。
A、用名称对网格项命名
.item-a{ grid-area: header }
B、用网格线对网格项命名
.item-d{ grid-area: 1 / col4-start / last-line / 6 }
/* 一个例子*/ .container { display: grid; grid-template-columns: 220px 20px 220px 20px 220px; grid-template-rows: auto 20px auto 20px auto; } .header { grid-area: 1 / 1 / 2 / 6; } .content { grid-area: 3 / 3 / 4 / 6; } .sidebar { grid-area: 3 / 1 / 4 / 2; } .footer { grid-area: 5 / 1 / 6 / 6; }
4、justify-self
沿列轴对齐网格项中的内容(相反于align-self属性定义的沿行轴对齐)。此值适用于单一网格项中的内容。
.item { justify-self: start | end | center | stretch; }
5、align-self
沿行轴对齐网格项中的内容(相反于justify-self属性定义的沿列轴对齐)。此值适用于单一网格项中的内容。
.item { align-self: start | end | center | stretch; }
六、我的demo
https://codepen.io/cpid768/pen/JrrLpv
https://codepen.io/cpid768/pen/qPPKxR
https://codepen.io/cpid768/pen/eGGKNa
https://codepen.io/cpid768/pen/eGGVOa