对于CSS的grid布局也了解过一些,但一直没怎么用,多少有些生疏,借着仿去哪网的城市列表页,对这些技术进行一个综合的学习
注:
本文主要参考MDN的网格布局,在目录上可能会有极大的相似,内容上相对MDN更加通俗易懂,案例围绕下方图的效果进行进行设计参考https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout
如需转载,请注明出处
效果如下
进入正题
通过在元素上声明display:grid
来创建一个网格容器,这个元素的所有直系子元素都会自动成为网格元素
通过grid-template-columns
和grid-template-rows
属性可以在网格容器中定义网格的行和列,任意两条线之间的空间就是一个网格轨道,例如下方图中红色框中为一个行轨道,蓝色框中为一个列轨道
通过grid-template-columns
可以定义列轨道的大小,即列的宽度
下方代码将.wrapper
设置为网格容器,其直系子元素就变成了网格元素,通过grid-template-columns
设置了三个相等的值将一行分为三列,每一列138px
,这样网格中每一行中就有了三个网格元素
HTML
<div class="wrapper"> <div>北京</div> <div>上海</div> <div>三亚</div> <div>香港</div> <div>杭州</div> <div>广州</div> <div>成都</div> <div>深圳</div> <div>苏州</div> <div>桂林</div> <div>西安</div> <div>厦门</div> </div>
CSS
.wrapper{ display: grid; grid-template-columns: 138px 138px 138px; }
注:对于案例中其他样式的CSS代码如下,仅列出一次
.wrapper{ width: 414px; background-color: #f5f5f5; font-size: 12px; margin: 0 auto; border: 1px solid #00bcd4; } .wrapper > div{ box-sizing: border-box; line-height: 44px; border: 1px solid #00bcd4; border-radius: 10px; }
效果
在网格布局中,还为我们提供了一个新的单位fr
,这是一个相对的单位,上面的138px
是我们写死的长度,如果网格容器的宽度是变化的,我们就不能保证每行的3个元素刚好可以占满容器
将CSS代码改为
.wrapper{ display: grid; grid-template-columns: 1fr 1fr 1fr; }
这样表示在网格容器中有三列,每一列各占一份
效果还是不变的
将CSS代码改为
.wrapper{ display: grid; grid-template-columns: 1fr 2fr 1fr; }
这样表示中间那一列的网格元素占两份,左右两边的网格元素占一份
效果为
通过fr
单位,我们可以很容易做到按照一定的比例去设置每一列
网格系统还提供给我们一个更加方便的函数
它到底有什么用,先写代码来看看
.wrapper{ display: grid; grid-template-columns: repeat(3,1fr); }
第一个参数表示重复的次数,第二个就是份数,这个跟上面写的grid-template-columns: 1fr 2fr 1fr;
是相同的效果,这样如果我们有更加复杂的需要重复的布局需求,repeat就可以很好的帮我们解决这种问题
当然repeat()
并不是只能单独使用
.wrapper{ display: grid; grid-template-columns: 1fr repeat(2,2fr) 1fr; }
我们还可以将repeat跟正常的fr
单位混这写,当然如果用px
做单位也是可以的
repeat的第二个参数并不是只能写一个,它也是支持写多个份数的
.wrapper{ display: grid; grid-template-columns: repeat(2,1fr 2fr); }
效果
我们在上面并没有定义grid-template-rows
但是我们发现我们的网格中也出现了好几行,这些行就是网格为我们隐式创建的行
在grid-template-columns
和grid-template-rows
明确定义出来的列和行就是显式的网格,如果网格元素的数量多于我们显式声明的行和列划分出来的元素数量,那个网格系统就会为我们创建隐式的网格
可以在grid-auto-rows
属性中使用minmax()
函数对行的高度进行更好的设置
在需求中如果有一个最小行高的需求,例:如果内容少,行高为44px,如果内容多,行高要跟随响应的内容变大,minmax可以写为minmax(44px, auto)
,auto就意味着行高将会根据内容自动调整,但是最小也是44px
HTML
<div class="wrapper"> <div>北京<p>首都</p></div> <div>上海</div> <div>三亚</div> <div>香港</div> <div>杭州</div> <div>广州</div> <div>成都</div> <div>深圳</div> <div>苏州</div> <div>桂林</div> <div>西安</div> <div>厦门</div> </div>
CSS
.wrapper{ display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: minmax(44px, auto); }
效果
对应列也有grid-auto-columns
属性来进行相关设置
在定义网格时,我们定义而定是网格轨道,不是网格线,grid会为我们创建网格线并赋予编号,网格线如下所示
通过网格线我们可以轻松定位想要的网格元素,网格线的顺序取决于书写模式,从左到右的书写语言中最左边为1号,从右到左书写的语言中最右边是1号。
在网格线的基础上,我们可以通过网格线去跨轨道放置网格元素
我们可以在网格元素
的CSS属性中使用grid-column-start
和grid-column-end
来设置网格元素占据的列数
通过grid-row-start
和grid-row-end
来设置网格元素占据的行数
HTML
<div class="wrapper"> <div class="title">热门城市</div> <div class="capital">北京 <div>首都</div> </div> <div>上海</div> <div>三亚</div> <div>香港</div> <div>杭州</div> <div>广州</div> <div>成都</div> <div>深圳</div> <div>苏州</div> <div>桂林</div> <div>西安</div> <div>厦门</div> </div>
CSS
.wrapper{ display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: minmax(44px, auto); } .title{ grid-column-start: 1; grid-column-end: 4; } .capital{ grid-row-start: 2; grid-row-end: 4; }
效果
我们设置热门城市
这个网格元素的列从第1根列
网格线开始,到第4根列
网格线结束
北京 首都
的行从第2根行
网格线开始,到第4根行
网格线结束,其余没有设置的就按照默认的方式放到网格中
当然,大家可以根据自己的喜好,按照上述方式去随意放置网格元素
一个网格单元是网格元素中最小的单位,类似于表格中的单元格
如上方的案例图中一个格子就是一个网格单元
网格区域是个矩形,如上述图中热门城市
这个网格元素,我们虽然对他进行了扩展,但是不管怎么扩展它都只能是一个矩形,不能扩展成L
形或其他形状
通过网格间距以及上面提到的一些东西,我们就可以完全实现要实现的内容了
网格间距定义在网格容器
的CSS中,有三个属性grid-column-gap
设置列之间的间距,grid-row-gap
设置行之间的间距,grid-gap
同时设置行和列之间的间距
HTML代码
<div class="wrapper"> <div class="title">热门城市</div> <div>北京</div> <div>上海</div> <div>三亚</div> <div>香港</div> <div>杭州</div> <div>广州</div> <div>成都</div> <div>深圳</div> <div>苏州</div> <div>桂林</div> <div>西安</div> <div>厦门</div> </div>
CSS代码
.wrapper{ display: grid; grid-template-columns: repeat(3, 1fr); grid-column-gap: 2px; grid-row-gap: 2px; /*grid-gap: 2px*/ /*这里或者这样写*/ }
其他的样式代码做了些调整,这里也再放出来吧
.wrapper{ width: 414px; background-color: #f5f5f5; font-size: 12px; margin: 0 auto; border: 1px solid #00bcd4; } .wrapper > div{ box-sizing: border-box; line-height: 44px; background-color: #fff; text-align: center; } .wrapper>.title{ grid-column-start: 1; grid-column-end: 4; background-color: #f5f5f5; text-align: left; text-indent: 10px; line-height: 36px; }
效果
这样便可以实现相应的效果
网格单元也可以作为网格容器,里面再实现一个小的网格布局
这里我在外层新建了一个网格容器
HTML代码
<div class="outWrapper"> 上述代码复制了6份 </div>
CSS代码
.outWrapper{ background-color: #00bcd4; display: grid; grid-template-columns: repeat(3, 1fr); grid-column-gap: 10px; grid-row-gap: 10px; grid-auto-columns: minmax(414px,auto) }
效果
在Level 1网格规范中有个子网格
的特性,即上述代码中我们将outWrapper内部的子网格的display不要设置为grid,而是设置为display:subgrid
注
规范中虽然有子网格特性,但是子网格还没有在
任何浏览器
中实现,并且可能随时被移除,了解就好
z-index
控制层级由于我们可以控制网格元素的位置,有可能就会产生覆盖现象
HTML
<div class="wrapper"> <div class="title">热门城市</div> <div class="capital">北京 <div>首都</div> </div> <div>上海</div> <div>三亚</div> <div>香港</div> <div>杭州</div> <div>广州</div> <div>成都</div> <div>深圳</div> <div>苏州</div> <div>桂林</div> <div>西安</div> <div>厦门</div> </div>
CSS
.wrapper{ display: grid; grid-template-columns: repeat(3, 1fr); grid-column-gap: 2px; grid-row-gap: 2px; } .wrapper>.title{ grid-column-start: 1; grid-column-end: 4; grid-row-start: 1; grid-row-end: 2; background-color: #f5f5f5; } .capital{ grid-column-start: 1; grid-column-end: 2; grid-row-start: 1; grid-row-end: 3; }
效果
此时北京 首都
网格元素覆盖了热门城市
的部分内容
如果我们想让热门城市覆盖北京,只需要给热门城市加上z-index
属性即可,值我这里设置的2,就可以覆盖了
效果