通俗重制系列--Grid布局
Grid布局
flex布局
是 一维布局
,一般用于单行或者单列的布局,如果要实现多行多列的布局,推荐使用 gird网格布局
。
示例demo 看看多么方便
<div class="wrapper"> <div class="one item">One</div> <div class="two item">Two</div> <div class="three item">Three</div> <div class="four item">Four</div> <div class="five item">Five</div> <div class="six item">Six</div> </div>
.wrapper { margin: 60px; /* 声明一个容器 */ display: grid; /* 声明列的宽度 */ grid-template-columns: repeat(3, 200px); /* 声明行间距和列间距 */ grid-gap: 20px; /* 声明行的高度 */ grid-template-rows: 100px 200px; } .one { background: #19CAAD; } .two { background: #8CC7B5; } .three { background: #D1BA74; } .four { background: #BEE7E9; } .five { background: #E6CEAC; } .six { background: #ECAD9E; } .item { text-align: center; font-size: 200%; color: #fff; }
容器属性
- grid - 生成块级网格
- inline-grid - 生成内联级网格
.container{ display: grid | inline-grid; }
注意,设为网格布局以后,容器子元素(项目)的float
、display: inline-block
、display: table-cell
、vertical-align
和column-*
等设置都将失效
grid-template-columns,grid-template-rows
grid-template-columns
属性定义每一列的列宽, grid-template-rows
属性定义每一行的行高
grid-template-columns<rows>: length | percent | auto | fr 复制代码
可以使用绝对单位,也可以使用百分比。(1)repeat()
有时候,重复写同样的值非常麻烦,尤其网格很多时。这时,可以使用repeat()
函数,简化重复的值。上面的代码用repeat()
改写如下。
.container { display: grid; grid-template-columns: repeat(3, 33.33%); grid-template-rows: repeat(3, 33.33%); }
举例repeat()
重复某种模式也是可以的。
grid-template-columns: repeat(2, 100px 20px 80px);
上面代码定义了6列,第一列和第四列的宽度为100px
,第二列和第五列为20px
,第三列和第六列为80px
。
(2)auto-fill 关键字
有时,单元格的大小是固定的,但是容器的大小不确定。如果希望每一行(或每一列)容纳尽可能多的单元格,这时可以使用auto-fill
关键字表示自动填充。
.container { display: grid; grid-template-columns: repeat(auto-fill, 100px); }
(3)fr 关键字
为了方便表示比例关系,网格布局提供了fr
关键字(fraction 的缩写,意为"片段")。如果两列的宽度分别为1fr
和2fr
,就表示后者是前者的两倍。(4)minmax()
minmax()
函数产生一个长度范围,表示长度就在这个范围之中。它接受两个参数,分别为最小值和最大值。
grid-template-columns: 1fr 1fr minmax(100px, 1fr);
上面代码中,minmax(100px, 1fr)
表示列宽不小于100px
,不大于1fr
。
(5)auto 关键字
auto
关键字表示由浏览器自己决定长度。
grid-template-columns: 100px auto 100px;
上面代码中,第二列的宽度,基本上等于该列单元格的最大宽度,除非单元格内容设置了min-width
,且这个值大于最大宽度。
(6)每条线可以取名字
结果:
grid-template-areas
网格布局允许指定"区域"(area),一个区域由单个或多个单元格组成。 grid-template-areas
属性用于定义区域
.main { display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; grid-template-areas: 'a b c' 'd e f' 'g h i'; }
可以将多个单元格合并成一个区域,其中 grid-area
后面会介绍,这里先不作深究
.main { display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; grid-template-areas: 'a a b' 'a a b' 'c c c'; } .main div:nth-child(1) { grid-area: a; background: skyblue; }
.main { display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; grid-template-areas: 'a a b' 'a a b' 'c c c'; } .main div:nth-child(1) { grid-area: a; } .main div:nth-child(2) { grid-area: b; } .main div:nth-child(3) { grid-area: c; }
如果某些区域不需要利用,则使用"点"(.
)表示。
grid-template
grid-template
属性是 grid-template-columns
、 grid-template-rows
和 grid-template-areas
这三个属性的合并简写形式。但是不建议合并在一起写,所以这里就不作案例展示,毕竟这些属性本身比较难记。可以看MDN上关于 grid-template 相关的介绍
grid-row-gap,grid-column-gap
grid-row-gap
属性设置行与行的间隔(行间距), grid-column-gap
属性设置列与列的间隔(列间距)。需要注意的是,CSS Grid Layout 起初是用 grid-row-gap
属性来定义的,目前逐渐被 row-gap
替代。因为其他布局方式也可以使用gap属性,例如 flex弹性布局
。但是,为了兼容那些不支持 row-gap
属性的浏览器,你需要像上面的例子一样使用带有前缀的属性。详情看MDN关于row-gap的介绍
grid-row<column>-gap: length
.main { display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; row-gap: 20px; column-gap: 20px; }
可以看到行与列之间多了20px的间距
grid-gap
grid-gap
属性是 grid-column-gap
和 grid-row-gap
的合并简写形式,现在已经逐渐被gap替代
justify-items,align-items
justify-items
属性设置单元格内容的水平位置, align-items
属性设置单元格内容的垂直位置,默认值都是 stretch
justify-items<align-items>: start | end | center | stretch;
首先我们先定义一个3行3列的网格
.main { display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; } .main div { background: pink; }
为什么在没有给定子项宽高的情况下,仍然可以铺满整个父容器?原因是因为水平与垂直都是默认拉升的( stretch
),也就是:
.main div { justify-items: stretch; align-items: stretch;}
如果我们给子项设置宽高:
.main div { width: 50px; height: 50px; }
虽然子项的宽高发生了变化,但是实际上网格的大小仍然没有变,用调试工具就可以看出来:
这个情况下,可以使用 justify-items
, align-items
来对齐子项的位置
行与列设置居中对齐
.main { display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; justify-items: center; align-items: center; } .main div { width: 50px; height: 50px; background: pink; }
行与列设置尾部对齐
.main { justify-items: end; align-items: end; } 复制代码
place-items
place-items
属性是 align-items
属性和 justify-items
属性的合并简写形式,注意的是,垂直对齐是在前,水平对齐是在后。如果只写一个,则默认垂直与水平是一致。
place-items: <align-items><justify-items>; 复制代码
.main { display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; place-items: center; } .main div { width: 50px; height: 50px; background: pink; }
justify-content , align-content
justify-content
属性是整个内容区域在容器里面的水平位置, align-content
属性是整个内容区域的垂直位置。默认都是 start
justify-content<align-content>: start | end | center | stretch | space-around | space-between | space-evenly;
首先定义一个3行3列的网格布局
.main { width: 500px; height: 500px; display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; } .main div { background: pink; }
向结束位置对齐
.main { justify-content: end; align-content: end; }
居中对齐
.main { justify-content: center; align-content: center; }
两端对齐
.main{ justify-content: space-between; align-content: space-between;}
子项与子项之间间隔相等
.main { justify-content: space-around; align-content: space-around; }
子项与子项之间间隔相等,子项与容器边框之间间隔相等
.main { justify-content: space-evenly; align-content: space-evenly; }
其他情况不在此继续展示,可自行尝试
place-content
place-content
属性是 align-content
属性和 justify-content
属性的合并简写形式。和 place-items
一样,垂直在前,水平在后。如果只写一个,则默认垂直与水平是一致。
place-content: <align-content><justify-content>
.main { place-content: center; }
justify-items,align-items 与 justify-content,align-content 的注意点
这两对属性和 flex弹性布局
很相似,所以经常搞混,这里特别要说明的是,与 flex布局
不一样的地方是,这两对属性都是作用在父容器上,而 flex布局
的 justify-content
, align-items
属性是作用在父容器上的,但是没有 justify-items
, align-content
这两个属性。一般在 Grid布局
中, justify-items
, align-items
是一起使用, justify-content
, align-content
是一起使用
那么什么时候使用 justify-items
, align-items
,什么时候使用 justify-content
, align-content
呢?
可以记住一个技巧:
(1)当子项的大小低于单元格的大小的时候,使用 justify-items
, align-items
还记得前面说的吗,子项的大小是可能会比单元格小的,例如单元格大小是 100*100
,而子项大小只有 50*50
。这种情况使用 justify-items
, align-items
。
(2)当容器大小大于单元格大小时,使用 justify-content
, align-content
显示网格与隐式网格
正常情况下,我们定义了 例如三行三列的网格,总共有 9
个元素,那这 9
个元素正好布满整个容器,这 9
个子项都是 显示网格
.main { display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; } .main div { background: pink; } 复制代码
如果有超过 9
个子项呢?比如,数字 10
,数字 11
,数字 12
.....??这些多出来的网格就是 隐式网格
,这些隐式网格默认都是按照 rows
的方向进行排列,高度会自动 拉伸
铺满容器
grid-auto-flow
明白了什么是 显示网格
和 隐式网格
,就可以看一下 grid-auto-flow
。划分网格以后,容器的子元素会按照顺序,自动放置在每一个网格。默认的放置顺序是"先行后列",即先填满第一行,再开始放入第二行。这就解释了,上面的 隐式网格
为什么会在 789
的下面,明明父容器右侧还有空白位置,为什么无法铺满,这是因为默认设置了"先行后列",即 grid-auto-flow: rows
,这个属性会决定网格的排列顺序
grid-auto-flow: rows | column | ros dense | column dense;
将顺序设置为先列后行,即 grid-auto-flow: column
.main { width: 500px; height: 500px; display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; grid-auto-flow: column; } .main div { background: pink; }
如果将网格 1
和网格 2
各占据两个单元格,然后在默认 grid-auto-flow: row
情况下,会产生下面这样的布局
上图中,网格 1
和网格 2
后面的位置都空了出来,因为网格 3
的排序是默认跟着网格 2
的,设置 grid-auto-flow: row dense
,可以将空出的位置铺满
.main { width: 300px; height: 400px; display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; grid-auto-flow: row dense; }
如果是"先列后行"的情况
.main { width: 500px; height: 300px; display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; grid-auto-flow: column }
grid-auto-rows,grid-auto-columns
如果是先行后列的顺序, 隐式网格
的列宽默认和 显示网格
一样,行高则是拉伸铺满,如果是先列后行的顺序, 隐式网格
的行高默认和 显示网格
一样。难道 隐式网格
的高度或者宽度只能拉升吗?当然不是,可以使用 grid-auto-rows
, grid-auto-columns
控制 隐式网格
的行高和列宽
先行后列的顺序下,设置 隐式网格
行高为 50px
.main { width: 500px; height: 300px; display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; grid-auto-flow: rows; grid-auto-rows: 50px; }
先列后行的顺序下,设置 隐式网格
列高为 50px
.main { width: 500px; height: 300px; display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; grid-auto-flow: column; grid-auto-columns: 50px; }
将 隐式网格
的行高也设置成 100px
,这样就和 显示网格
展示的大小一样了
.main { width: 500px; height: 400px; background: skyblue; display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; grid-auto-rows: 100px; }
repeat()方法与auto-fill关键字
我们在定义网格的时候,写 grid-template-columns
和 grid-template-rows
都是写多个重复值,比如 grid-template-columns: 100px 100px 100px
,简单的网格可以这样定义,但是如果网格很多的时候,难道要这样写吗? grid-template-columns: 100px 100px 100px 100px 100px ......
,这样很麻烦,可以使用 repeat()
去简化重复的值
repeat(number, length | percent | fr)
定义一个5行4列的网格
.main { display: grid; grid-template-columns: repeat(5, 100px); grid-template-rows: repeat(4, 100px); }
也可以具体的数值和 repeat()函数
一起使用
.main { display: grid; grid-template-columns: 200px repeat(2, 100px); grid-template-rows: 200px repeat(2, 100px); }
还有一种情况,容器的宽度有时候可以容纳更多的网格,但是由于定义了列数量或者行的数量比较少时
.main { width: 500px; background: skyblue; display: grid; grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(3, 100px); }
明明 网格4
是可以继续在 网格3
的后面继续排列的,为什么需要换行呢,仅仅是因为使用了 repeat(3, 100px)
定义三列,有什么办法,在单元格的大小是固定的,但是容器的大小不确定的情况下,使得每一行(或每一列)容纳尽可能多的单元格,这时可以使用 auto-fill
关键字表示自动填充
.main { width: 500px; background: skyblue; display: grid; grid-template-columns: repeat(auto-fill, 100px); grid-template-rows: repeat(3, 100px); }
minmax()方法
minmax()
函数产生一个长度范围,表示长度就在这个范围之中。它接受两个参数,分别为最小值和最大值。
minmax(min, max)
定义一个列宽和行高不小于 100px
,不大于 200px
的网格
.main { display: grid; grid-template-columns: minmax(100px, 200px) minmax(100px, 200px) minmax(100px, 200px); grid-template-rows: minmax(100px, 200px) minmax(100px, 200px) minmax(100px, 200px); }
minmax()方法可以和repeat()方法一起使用
.main { display: grid; grid-template-columns: repeat(3, minmax(100px, 150px)); grid-template-rows: 100px 100px 100px; }
项目属性
grid-area
首先定义一个三行三列的网格
默认情况下,网格数字都是按顺序排列的,有什么办法可以指定位置摆放呢? grid-area
属性就可以指定项目放在哪一个区域,但前提是需要先用 grid-template-areas
属性指定了区域
将 网格1
放到 区域e
.main { display: grid; grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(3, 100px); grid-template-areas: 'a b c' 'd e f' 'g h i'; } .main div:nth-child(1) { grid-area: e; background: chartreuse; }
grid-column-start , grid-column-end 和 grid-row-start , grid-row-end 与span关键字
这两对属性表示grid子项占据的区域的起始和终止位置,具体方法就是指定项目的四个边框,分别定位在哪根网格线
grid-column-start
属性:左边框所在的垂直网格线grid-column-end
属性:右边框所在的垂直网格线grid-row-start
属性:上边框所在的水平网格线grid-row-end
属性:下边框所在的水平网格线
如何查看所在的网格线?可以利用浏览器的调试工具,这样就可以展示网格线的序号了
grid-column-start
和 grid-column-end
.main { background: skyblue; display: grid; grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(3, 100px); } .main div { background: pink; grid-column-start: 1; grid-column-end: 3; }
grid-row-start
和 grid-row-end
.main { background: skyblue; display: grid; grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(3, 100px); } .main div { background: pink; grid-row-start: 2; grid-row-end: 3; }
两对属性一起使用
.main div { grid-column-start: 2; grid-column-end: 3; grid-row-start: 2; grid-row-end: 3; }
除了使用这种方式外,还可以直接命名网格线,效果也是一样的,使用调试工具可以查看网格线的命名
.main { background: skyblue; display: grid; grid-template-columns: [col1] 100px [col2] 100px [col3] 100px [col4]; grid-template-rows: [row1] 100px [row2] 100px [row3] 100px [row4]; } .main div { grid-column-start: col2; grid-column-end: col3; grid-row-start: row2; grid-row-end: row3; }
这两对属性还可以使用 span
关键字,表示"跨越",即左右边框(上下边框)之间跨越多少个网格
grid-column<row>-start: span number; 复制代码
.main div { grid-column-start: span 2; }
.main div { grid-column-start: 2; grid-column-end: span 2; }
grid-row,gird-column
grid-column
属性是 grid-column-start
和 grid-column-end
的合并简写形式, grid-row
属性是 grid-row-start
属性和 grid-row-end
的合并简写形式
grid-column: <start-line>/ <end-line>; grid-row: <start-line>/ <end-line>;
.item-1 { grid-column: 1 / 3; grid-row: 1 / 2; } /* 等同于 */ .item-1 { grid-column-start: 1; grid-column-end: 3; grid-row-start: 1; grid-row-end: 2; }
这两个属性之中,也可以使用 span
关键字,表示跨越多少个网格
.item-1 { grid-column: 1 / span 2; grid-row: 1 / span 2; } /* 等同于 */ .item-1 { grid-column: 1 / 3; grid-row: 1 / 3; }
斜杠以及后面的部分可以省略,默认跨越一个网格
.item-1 { grid-column: 1; grid-row: 1; }
用 grid-area
也可以实现同样的效果
grid-area: grid-row-start / grid-column-start / grid-row-end / grid-column-end;
.main { background: skyblue; display: grid; grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(3, 100px); } .main div { background: pink; grid-area: 2 / 2 / 3 / 3; }
justify-self,align-self
justify-self
属性设置单元格内容的水平位置(左中右),跟 justify-items
属性的用法完全一致,但只作用于单个项目
align-self
属性设置单元格内容的垂直位置(上中下),跟 align-items
属性的用法完全一致,也是只作用于单个项目
justify-self: start | end | center | stretch; align-self: start | end | center | stretch;
- start:对齐单元格的起始边缘
- end:对齐单元格的结束边缘
- center:单元格内部居中
- stretch:拉伸,占满单元格的整个宽度(默认值)
.main { background: skyblue; display: grid; grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(3, 100px); } .main div { width: 50px; height: 50px; background: pink; grid-area: 2 / 2 / 3 / 3; justify-self: end; align-self: end; }
place-self
place-self
属性是 align-self
属性和 justify-self
属性的合并简写形式。如果省略第二个值, place-self
属性会认为这两个值相等
place-self: <align-self><justify-self>;
.main { background: skyblue; display: grid; grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(3, 100px); } .main div { width: 50px; height: 50px; background: pink; grid-area: 2 / 2 / 3 / 3; place-self: center; }
布局案例
栅格布局
利用 grid布局
可以轻松实现 栅格布局
<div class="row"> <div class="col-6">1</div> <div class="col-3">2</div> <div class="col-4">3</div> <div class="col-5">4</div> </div>
.row { background: skyblue; display: grid; grid-template-columns: repeat(12, 1fr); grid-template-rows: 50px; grid-auto-rows: 50px; } .row div { background: pink; border: 1px black solid; } .row .col-1 { grid-area: auto/auto/auto/span 1; } .row .col-2 { grid-area: auto/auto/auto/span 2; } .row .col-3 { grid-area: auto/auto/auto/span 3; } .row .col-4 { grid-area: auto/auto/auto/span 4; } .row .col-5 { grid-area: auto/auto/auto/span 5; } .row .col-6 { grid-area: auto/auto/auto/span 6; } .row .col-7 { grid-area: auto/auto/auto/span 7; } .row .col-8 { grid-area: auto/auto/auto/span 8; } .row .col-9 { grid-area: auto/auto/auto/span 9; } .row .col-10 { grid-area: auto/auto/auto/span 10; } .row .col-11 { grid-area: auto/auto/auto/span 11; } .row .col-12 { grid-area: auto/auto/auto/span 12; }
不规则子项排列
如果要实现这样的效果,使用 grid布局
也是轻而易举实现的
<div class="main"> <div class="main-list"> <div class="theme1"></div> <div class="theme2"></div> <div class="theme1"></div> <div class="theme1"></div> <div class="theme1"></div> <div class="theme3"></div> <div class="theme3"></div> </div> </div>
.main { width: 308px; margin: 20px auto; } .main-list { height: 352px; margin: 0 14px; display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(4, 1fr); grid-template-areas: "a1 a3 a3" "a2 a3 a3" "a4 a4 a5" "a6 a7 a7"; gap: 8px; } .main-list div:nth-of-type(1) { grid-area: a1; } .main-list div:nth-of-type(2) { grid-area: a2; } .main-list div:nth-of-type(3) { grid-area: a3; } .main-list div:nth-of-type(4) { grid-area: a4; } .main-list div:nth-of-type(5) { grid-area: a5; } .main-list div:nth-of-type(6) { grid-area: a6; } .main-list div:nth-of-type(7) { grid-area: a7; } .main-list a { width: 100%; height: 100%; display: block; line-height: 30px; } .main-list h3 { text-align: right; margin-right: 4px; } .main-list p { text-align: center; } .theme1 { background: pink; } .theme2 { background: skyblue; } .theme3 { background: orange; }
更多布局案例
总结
grid布局
和 flex弹性布局
一样,都是当下最流行的CSS布局方案之一。它的优点是可以实现多行多列的布局,属于 二维布局
,基本可以满足任何的布局页面。
优点:
- 固定和灵活的轨道尺寸
- 可以使用行号、名称或通过定位网格区域将项目放置在网格上的精确位置
- 可以将多个项目放入网格单元格或区域中,它们可以彼此部分重叠
缺点:
- 浏览器兼容性较差
- 学习成本较高
grid布局
可以说是目前最强大的CSS布局方案,在实际开发过程中,往往 grid布局
和 flex布局
一起结合使用。