ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
原文 https://mp.weixin.qq.com/s/aHyWCzUYwcnkwt5MWhGfFw 相信很多前端同志对弹性盒(Flex)布局很熟悉,但是对于网格(Grid)布局很陌生,甚至在项目中从来没有用到过。今天就带大家学习一下网格布局是如何玩的。 > 如果你懒的动手写代码,或者本地创建项目,博主贴心的为你准备了代码预览地址,你可以一边调试一边预览效果。 ## 1\. 什么是网格布局 网格是由一系列水平及垂直的线构成的一种布局模式。根据网格,我们能够将设计元素进行排列,帮助我们设计一系列具有固定位置以及宽度的元素的页面,使我们的网站页面更加统一。 一个网格通常具有许多的**列(column)与行(row)**,以及行与行、列与列之间的间隙,这个间隙一般被称为**沟槽(gutter)**。 也就是下面这张图: ![图片](https://mmbiz.qpic.cn/sz_mmbiz_png/Kgb3xohibzibIuz1Cbna4jpmGGCibntFBuoqmaVb4vE10n9bYYwHKSTKEc4R945X29bsNBLHSETOLibicGojgRiaX9Lg/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1) 我们一般会根据我们的设计图来决定网格的布局长什么样子。 接下来我们从一个基础的网格系统开始学起来。 ## 2\. 自定义网格布局 布局如下: ~~~ <h1>Simple grid example</h1> <div class="container">   <div>One</div>   <div>Two</div>   <div>Three</div>   <div>Four</div>   <div>Five</div>   <div>Six</div>   <div>Seven</div> </div> ~~~ ### 2.1. Gird 首先,你要设置网格布局,必须把display设置为`grid`。 ~~~ .container {   display: grid; } ~~~ ### 2.2. grid-template-columns 此时的布局并没有任何变化,我们需要通过`grid-template-columns`设置列的宽度,给个三列,每列200px吧。 ~~~ .container {   display: grid;   grid-template-columns: 200px 200px 200px; } ~~~ 此时,页面效果如下: ![图片](https://mmbiz.qpic.cn/sz_mmbiz_png/Kgb3xohibzibIuz1Cbna4jpmGGCibntFBuoyZL5iajp0JJJtOU4mkTq7Nia0OK52s5XuAPMoUXkvjT8kDibMztq5ZUNQ/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1) ### 2.3. gap 使用 grid-column-gap(en-US) 属性来定义列间隙;使用 grid-row-gap(en-US) 来定义行间隙;使用 grid-gap(en-US) 可以同时设定两者。 修改代码: ~~~ .container {   display: grid;   grid-template-columns: 200px 200px 200px;   grid-gap: 20px;   gap: 20px; } ~~~ **备注:**gap属性曾经有一个grid-前缀,不过后来的标准进行了修改,目的是让他们能够在不同的布局方法中都能起作用。尽管现在这个前缀不会影响语义,但为了代码的健壮性,你可以把两个属性都写上。 此时,页面效果如下: ![图片](https://mmbiz.qpic.cn/sz_mmbiz_png/Kgb3xohibzibIuz1Cbna4jpmGGCibntFBuo5QC1oSgbyLKXibVErRiaMnVHxWicRe99XpuJodEBfqrypGAc7qQSEOLIQ/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1) ### 2.4. fr 这里除了使用px意外,我们也可以用 fr 这个单位来灵活地定义网格的行与列的大小。这个单位代表网格容器中可用空间的一份。也就是把列等分以后,每列占据的份数是多少,fr值越法,占据的空间就越大。 修改代码: ~~~ .container {   display: grid;   grid-template-columns: 1fr 1fr 1fr; } ~~~ 这个意思是,把列三等分,每列占据1份空间。 此时,页面效果如下: ![图片](https://mmbiz.qpic.cn/sz_mmbiz_gif/Kgb3xohibzibIuz1Cbna4jpmGGCibntFBuoeeBqTJhNwXxHVbyWg9EibicbkX3k4Czv4FWbPqEmibt4Zx5maw2W5DYXA/640?wx_fmt=gif&wxfrom=5&wx_lazy=1&wx_co=1) ### 2.5. repeat 你可以使用repeat来重复构建具有某些宽度配置的某些列。举个例子,如果要创建多个等宽轨道,可以用下面的方法。 ~~~ .container {   display: grid;   grid-template-columns: repeat(3, 1fr);   grid-gap: 20px; } ~~~ 这个效果跟上面的代码是一致的。第一个传入 repeat 函数的值(3)表明了后续列宽的配置要重复多少次,而第二个值(1fr)表示需要重复的构建配置,这个配置可以具有多个长度设定。例如repeat(2, 2fr 1fr),如果你仍然不明白,可以实际测试一下效果,这相当于填入了 2fr 1fr 2fr 1fr。 ### 2.6. grid-template-rows 通过`grid-template-rows`可以设置行的高度,我们给每行设置个100px吧。 ~~~ .container {   display: grid;   grid-gap: 20px;   grid-template-columns: 1fr 1fr 1fr;   grid-template-rows: 100px 100px 100px; } ~~~ 此时,页面效果如下: ![图片](https://mmbiz.qpic.cn/sz_mmbiz_png/Kgb3xohibzibIuz1Cbna4jpmGGCibntFBuoU7YjSpJrmdIjL6aDvIicFlDXW4OOl7yH1971YnP052zic25vDQPqvBGA/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1) ### 2.7. minmax() 函数 100 像素高的轨道有时可能会不够用,因为时常会有比 100 像素高的内容加进去。所以,我们可以将其设定为至少 100 像素,并且能够跟随内容来自动拓展尺寸,从而保证能容纳所有内容。显而易见,你很难知道网页上某个元素的尺寸在不同情况下会变成多少,一些额外的内容或者更大的字号就会导致许多能做到像素级精准的设计出现问题。所以有了minmax()函数。 minmax()函数为一个行/列的尺寸设置了取值范围。比如设定为 minmax(100px, auto),那么尺寸就至少为 100 像素,并且如果内容尺寸大于 100 像素则会根据内容自动调整。在这里试一下把 grid-auto-rows 属性设置为minmax函数。 ~~~ .container {   display: grid;   grid-gap: 20px;   grid-template-columns: 1fr 1fr 1fr;   grid-template-rows: minmax(100px, auto) 100px 100px; } ~~~ 此时,页面效果如下: ![图片](https://mmbiz.qpic.cn/sz_mmbiz_png/Kgb3xohibzibIuz1Cbna4jpmGGCibntFBuomyicWQtZJ0ibX5b5Zia87qcV0Yrue1VMGzLVCrfSEn9waSjxyk1JvTTGA/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1) 可以看到,我们设置了minmax(100px, auto)以后,此时内容高度会自动撑高。 ### 2.8. auto-fill 在上面的布局中,每次都是把行和列的属性重复写三次才能都生效。有没有更简便的方法呢?有,那就是repeat中的一个参数:auto-fill。 ~~~ .container {   display: grid;   grid-gap: 20px;   grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));   grid-auto-rows: minmax(100px, auto); } ~~~ 此时,页面效果如下: ![图片](https://mmbiz.qpic.cn/sz_mmbiz_png/Kgb3xohibzibIuz1Cbna4jpmGGCibntFBuoxONlwicRLzMqFW8J2BCFp6oD9xK5b1omOmiawsmv3Fibq1JiaUvxINOtkw/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1) 以上代码参考地址:https://stackblitz.com/edit/web-platform-vabj4w?file=styles.css ## 3\. 基于线的元素放置 既然是一个网格,那么它就有线,我们可以根据这些线所处的位置来放置我们的元素。如下图所示: ![图片](https://mmbiz.qpic.cn/sz_mmbiz_png/Kgb3xohibzibIuz1Cbna4jpmGGCibntFBuoE2AxX2icfkxWRNeDPx38AwaJVBmrtHjJmMXPdjiauYQUaQw5Kl5raGibA/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1) 在英文中,第一条列分隔线(即网格边缘线)在网格的最左边而第一条行分隔线在网格的最上面。而对于阿拉伯语,第一条列分隔线在网格的最右边,因为阿拉伯文是从右往左书写的。 ### 3.1. grid-column和grid-row 我们根据这些分隔线来放置元素,通过以下属性来指定从那条线开始到哪条线结束。 * grid-column-start * grid-column-end * grid-row-start * grid-row-end 这些属性的值均为分隔线序号,你也可以用以下缩写形式来同时指定开始与结束的线。 * grid-column * grid-row 注意开始与结束的线的序号要使用/符号分开。 上面的概念听起来是不是没听懂?没关系,我们接下来做个博客系统的布局,你就懂了: ![图片](https://mmbiz.qpic.cn/sz_mmbiz_png/Kgb3xohibzibIuz1Cbna4jpmGGCibntFBuoFlsdqjNJnyLtibBMEOnW56DLMRosuy7t8EFbRdoQwdb6cic1mBVmNjqA/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1) 页面布局如下: ~~~ <div class="container">   <header>This is my lovely blog</header>   <aside>     <h2>Other things</h2>     <p>       Nam vulputate diam nec tempor bibendum. Donec luctus augue eget       malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut,       facilisis sed est.     </p>   </aside>   <article>     <h1>My article</h1>     <p>       Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras       porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed       auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet       orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac       ornare ex malesuada et. In vitae convallis lacus. Aliquam erat       volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin       eros pharetra congue. Duis ornare egestas augue ut luctus. Proin       blandit quam nec lacus varius commodo et a urna. Ut id ornare felis,       eget fermentum sapien.     </p>     <p>       Nam vulputate diam nec tempor bibendum. Donec luctus augue eget       malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut,       facilisis sed est. Nam id risus quis ante semper consectetur eget       aliquam lorem. Vivamus tristique elit dolor, sed pretium metus       suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu       urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt       eget purus in interdum. Cum sociis natoque penatibus et magnis dis       parturient montes, nascetur ridiculus mus.     </p>   </article>   <footer>Contact me@mysite.com</footer> </div> ~~~ 添加css样式 ~~~ body {   width: 90%;   max-width: 900px;   margin: 2em auto;   font: 0.9em/1.2 Arial, Helvetica, sans-serif; } header, footer {   border-radius: 5px;   padding: 10px;   background-color: rgb(207, 232, 220);   border: 2px solid rgb(79, 185, 227); } aside {   border-right: 1px solid #999; } .container {   display: grid;   grid-template-columns: 1fr 3fr;   gap: 20px; } header {   grid-column: 1 / 3;   grid-row: 1; } article {   grid-column: 2;   grid-row: 2; } aside {   grid-column: 1;   grid-row: 2; } footer {   grid-column: 1 / 3;   grid-row: 3; } ~~~ 我们再来看看这个页面布局的网格线: ![图片](https://mmbiz.qpic.cn/sz_mmbiz_png/Kgb3xohibzibIuz1Cbna4jpmGGCibntFBuofSQQN1TeuaeFdMafXCe9Yz6NMEA1X8YzVhXJVyHNsmVQia2fppRStNw/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1) 拿header来说,grid-column: 1 / 3,意思就是说从列的位置从分隔线序号1开始,从分隔线序号3结束,是不是跟上面图中的网格线一致?其他元素的布局也是类似的,你可以一一的对照去看。 以上代码参考地址:https://stackblitz.com/edit/web-platform-tmtmba?file=styles.css ### 3.2. grid-template-areas 当然,上面的布局实现方式可以用另一种往网格放元素的方式:grid-template-areas,并且你要命名一些元素并在属性中使用这些名字作为一个区域。 将之前基于线的元素放置代码删除(或者重新下载一份新的文件),然后加入以下 CSS 规则: ~~~ .container {   display: grid;   grid-template-areas:     "header header"     "sidebar content"     "footer footer";   grid-template-columns: 1fr 3fr;   gap: 20px; } header {   grid-area: header; } article {   grid-area: content; } aside {   grid-area: sidebar; } footer {   grid-area: footer; } ~~~ 同样的也能实现上面博客的布局效果。 ## 4\. 网格排版框架 网格排版框架一般由 12 到 16 列的网格构成,下面我们实现一个12列网格的排版框架。页面布局还是以上面博客的为例,参考代码:https://stackblitz.com/edit/web-platform-pfi7ju?file=styles.css 我们可以用基于线的元素放置模式来将我们的内容放到这个 12 列的网格中。 ~~~ .container {   display: grid;   grid-template-columns: repeat(12, minmax(0, 1fr)); /** 关键代码 **/   gap: 20px; } header {   grid-column: 1 / 13;   grid-row: 1; } article {   grid-column: 4 / 13;   grid-row: 2; } aside {   grid-column: 1 / 4;   grid-row: 2; } footer {   grid-column: 1 / 13;   grid-row: 3; } ~~~ 在Google浏览器中使用开发者工具查看它的网格线,你应该能看到这 12 列的网格是如何工作的了。 ![图片](https://mmbiz.qpic.cn/sz_mmbiz_png/Kgb3xohibzibIuz1Cbna4jpmGGCibntFBuoqUsmxJtZp82N9fbNN97eeseFe5ibwyxDF823EJsfjVPKeeqz1tKMfiaA/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1) > 总结:我们在这篇文章中接触了 CSS 网格版面的主要特性,你现在应该可以在你自己的设计中使用了。 最后,看完了别忘了给博主三连。请转发给你的朋友,让他们也学会网格布局的使用技巧吧,非常感谢!