【CSS】 Grid 栅格布局
2018年作为Grid布局的元年,Grid给开发者带来了强大的布局体验,它能帮助我们在页面上创建响应式布局。目前已有77%+的浏览器支持这个特性,比例还在逐步增加。
要点:
- Grid
Grid Container
使用display:grid
或display:inline-grid
即可创建一个栅格容器,这个容器下的所有直接子节点都会成为栅格项(Grid Item)。
<div class="container"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> <div class="item">4</div> </div>
//base css .item {padding: 10px;border:1px solid #fff;text-align: center;color:#fff;background-color: #d426ff;} // grid css .container { display:grid;//如图1 } // or .container { display:inline-grid;//如图2 }
图1
图2
Explicit Grid
我们可以通过设置grid-template-columns
和grid-template-rows
来显示地设置栅格的列和行的值。
.container { grid-template-rows: 50px 100px; }
即:为每行指定一个高度值。单位可以是 px,%,em等
,例如上面中,第一行和第二行的固定高度为50px 和 100px。而其余行的高度将有该行自身包含的内容来确定。如下图:
类似的,grid-template-columns
能确定每列的宽度值。
.container { grid-template-rows: 50px 100px; grid-template-columns: 90px 50px 120px 30px; }
如下图:设置每列的宽度分别为90px 50px 120px 30px
:
当然,你还可以设置基础响应单位:fraction(fr)
:fr
允许你将容器拆分为多个块:
.container { grid-template-columns: 1fr 1fr 1fr 1fr;//四等分,每列占据一等分 }
.container { grid-template-columns: 3rem 25% 1fr 1fr;//3rem和25%设置第1列和第2列,fr 则基于剩余空间计算:1fr = ((width of grid)-(3rem)-(25% of width of grid))/3 }
Minimum and Maximum Grid Track Sizes
可以使用minmax()
函数定义栅格项的最小/最大尺寸。
- minmax(param1,param2):param1表示最小尺寸;param2表示最大尺寸。除了设置具体单位值,也可以设置为
auto
,这时,会基于栅格项的内容来定义栅格项的尺寸。
.container { grid-template-rows: minmax(100px,auto); grid-template-columns: minmax(auto,50%) 1fr 1fr 3em; }
上面代码表示:栅格项行的最小高度为100px,最大高度为auto,即允许根据内容大小增加尺寸
,
另一方面,栅格项列的最小宽度为auto
,但最大宽度为50%,即不能超过容器宽度的50%
。
Repeating Grid Tracks
使用repeat()
方法能定义重复的栅格项。对于具有相同尺寸的栅格项很有用。
- repeat(param1,param2):
param1
表示定义多少个栅格项重复;param2
表示对栅格项宽/高的定义。
.container { grid-template-rows: repeat(4,100px);//定义每行4个栅格项,高度均为100px grid-template-columns: repeat(4,1fr);//定义每列4个栅格项,宽度均为1fr }
同时,repeat()
也可以单独对某列使用:
.container { grid-template-columns: 30px repeat(2,1fr) 30px;//其中2、3列重复 }
Grid Gaps(Gutters)
每个栅格项之间可能需要间隔(水槽),类似设置了margin
,grid-column-gap
和grid-row-gap
就可以用来定义水槽的尺寸。但是,需要注意的是,不同于margin
,水槽仅能在列和行之间创建,不能沿栅格容器的边缘创建。水槽的大小可以是任意非负值(px,%,em等)。
.container { grid-template-rows: repeat(4,100px); grid-template-columns: 30px repeat(2,1fr) 30px; grid-row-gap: 20px; grid-column-gap: 5rem; } //or: 简写 .container { grid-gap: 20px 5rem; //第一个表示grid-row-gap,第二个表示grid-column-gap,若只有一个值,表示grid-row-gap和grid-column-gap是相等的设置 }
Positioning Items by Grid Line Numbers
当我们定义Grid时,实际定义的是栅格轨道,而不是栅格线。我们可以给栅格创建编号,用以定位每一个栅格元素。栅格线本质上表示的是列和行的开始、结束或行列之间的线。从栅格项的起点开始并沿着栅格方向从1开始递增编号。例如:下面3列2行的栅格中,拥有4条纵向的栅格线。
<div class="container"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> <div class="item">4</div> <div class="item">5</div> <div class="item">6</div> </div> .container { grid-template-rows: repeat(3,100px); grid-template-columns:repeat(3,1fr); }
那么怎样定位栅格元素:使用栅格线定位。
.item:first-of-type { grid-column-start:1; grid-column-end: 4; grid-row-start:1; grid-row-end: 3; }
上面代码中,从左至右,第一个栅格元素从列线1
开始,延伸至列线4
。同时,从行线1
延伸至行线3
。这样,3列3行的栅格产生了4列线,4行线
。
同时,你还可以使用简写:
grid-row:2;//grid-row是grid-row-start和grid-row-end的简写 grid-column: 3/4;//grid-column是grid-column-start和grid-column-end的简写
如果只提供一个值,则表示grid-row-start
或grid-column-start
如果只提供两个值,则第一个值表示grid-row-start
或grid-column-start
,第二个值表示grid-row-end
或grid-column-end
,并且两个值要用正斜杠/
分隔。
grid-area: 2/2/3/3;
grid-area
是grid-row-start
、grid-column-start
、grid-row-end
、grid-column-end
的简写,且grid-area
的值按这个顺序对应。
Spanning Items Across Rows and Columns(跨行、跨列)
通常情况下,栅格项是不跨列和不跨行的。但是跨行和跨列又是在布局中常见的操作。同样,可以使用grid-column-start
和grid-column-end
来设置。
<div class="container"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> <div class="item">4</div> </div> .container { display:grid; } .item:first-of-type {//跨列,从1-4列跨越 grid-column-start:1; grid-column-end:4; } //or 简写:两个值之间用正斜杠/分隔 .irem:first-of-type { grid-column: 1/4; }
于是,我们可以看到:
<div class="container"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> <div class="item">4</div> <div class="item">5</div> <div class="item">6</div> <div class="item">7</div> </div> .container { display: grid; grid-template-columns: 1fr 1fr 1fr; } .item:first-of-type {//跨行,从1-4行跨越 grid-row-start:1; grid-row-end:4; } //or 简写:两个值之间用正斜杠/分隔 .item:first-of-type { grid-row: 1/4; }
也可以使用span
关键字,该关键字后面跟要跨越的列数或行数:
.item:first-of-type { grid-column: span 2; //跨域2列 grid-row: 2/ span 2; //跨域2行 }
Naming Grid Lines (命名网格线)
在使用grid-template-rows
和grid-template-columns
属性定义网格时,可以命名网格线。然后可以引用线名称来定位网格项。
.container { display:grid; grid-template-rows: [row-1-start] 1fr [row-2-start] 1fr [row-2-end]; grid-template-columns: [col-1-start] 1fr [col-2-start] 1fr [col-3-start] 1fr [col-3-end]; }
使用grid-template-rows
和grid-template-columns
属性定义网格时,为网格线指定名称。分配的行名称必须用方括号括起来[name-of-line]
并相对于网格轨道放置。例如:
[row-1-start]
即使网格线名称,对应第1行的网格线的开始。
再如:
.container { display:grid; grid-template-rows: [row-start row-1-start] 1fr [row-1-end row-2-start] 1fr [row-2-end row-end]; grid-template-columns: [col-start] 1fr [col-2-start] 1fr [col-3-start] 1fr [col-end]; }
通过在方括号内添加名称并用空格分隔每个名称,可以将多个名称分配给网格线。
然后,当按行名称定位网格项时,可以引用每个行名称。
那么,我们可以试试,使用行名称定位Grid Item:
使用行名称定位Grid Item
使用命名网格线,可以按行名称和数字定位Grid Item。
.container { display:grid; grid-template-rows: [row-start row-1-start] 1fr [row-1-end row-2-start] 1fr [row-2-end row-end]; grid-template-columns: [col-start] 1fr [col-2-start] 1fr [col-3-start] 1fr [col-end]; } .item:first-of-type { grid-row-start: row-2-start; grid-row-end: row-end; grid-column-start: col-2-start; grid-column-end: col-end; } // or: 简写 .item:first-of-type { grid-row: row-2-start / row-end; grid-column: col-2-start / col-end; }
可以看到,我们把Item 1
定位到了这个位置:
为了方面,Grid 布局还提供了repeat()
函数为行/列指定相同的名称:
.container { display:flex; grid-template-rows: repeat(3,[row-start] 1fr [row-end]); grid-template-columns: repeat(3,[col-strat] 1fr [col-end]); }
然后,我们可以进行定位:
.item:first-of-type { grid-row: row-start 2 / row-end 2; grid-column: col-start 1 / col-start 3; }
要按名称相同的行定位,使用行的名称和位置/名称的出现次数
(名称和数字之间用空格分隔),例如:下面例子中,Item 1 的行位置从row-start
的第2个网格线开始,并在名为row-end
的第2个网格线处结束。它的列位置从命名的col-start
第一个网格线开始,并在名为col-start
的第2个网格线处结束。
按网格区域命名和定位网格项
与网格线名称一样,网格区域也可以使用
grid-template-areas
属性命名。然后可以引用名称来定位网格项。
.container { grid-template-areas: "header header" "content sidebar" "footer footer"; grid-template-rows: 150px 1fr 100px; grid-template-columns: 1fr 200px; }
- 名称用双引号或单引号括起来,每个名称用空格分隔。
- 每组名称都定义一行,其中的每个名称定义一列。
例如,上面代码中我们定义一个3行2列的名称组。
引用名称
网格区域名称可以用相同的属性值来定位网格项。例如:
.container { grid-template-areas: "header header" "content sidebar" "footer footer"; grid-template-rows: 150px 1fr 100px; grid-template-columns: 1fr 200px; } .container .grid-item {//居中内容 display: flex; display: -ms-flexbox; align-items: center; -ms-flex-align: center; -ms-flex-pack: center; justify-content: center; } .container .header { grid-row-start: header; grid-row-end: header; grid-column-start: header; grid-column-end: header; } //or 简写: .container .header { grid-row: header; grid-column: header; } //同时,grid-area属性也可以用来引用网格区域名称: .container aside { grid-area: sidebar; }