乐趣区

记一次grid布局实战应用分享会

记一次 grid 布局实战应用分享会

记录了组内技术分享会, 有同样需求的同学可以参考一下
分享全程下来时间大约 45 分钟
最终画图如下:↓

一. 到底能不能用在工程??(兼容性)

老生长谈的问题了, 但也是决定性的问题, 如下图:

对于不用兼容 ie 浏览器的工程可以玩起来了, grid 也不算新技术了, 技术的发展需要 coder 的推动, 有时候问问自己不用 grid 的原罪是不是 ’ 懒得学 ’ 哈哈哈哈, 我查了一下 chrome 57 版本是 2017.3 月发布的 .
ie 使用 display: -ms-grid 的写法也可以有效, 但是网上看到很多同学遇到了未知错误, 所以如果真的必须兼容 ie 的话还是不要使用 grid.

二. 技能定位(flex 的好战友)

grid 不会代替 flex, 相反他两位是非常棒的搭档, 配合使用简直开始螺旋人生, grid 布局可以打破 dom 位置的限制, 使用不好的话容易造成语义混乱, 导致鲁棒性下降, 这次我们就一起来探究一下 grid 布局的实战场景.

三. 从上下左右居中 ’ 新方法 ’ 引导兴趣

烂大街的一个面试题, 居中的方法.
你可以秀出 grid 了, 那么分数一定多加一分到两分.. 此处我介绍 ’ 四种 ’ 之后的内容会解释为什么会这样, 而且还有很多 qiyinqiaoji… 可以说学会了 grid 布局那么你的居中技巧就多出了 6 种以上!

整体 dom 结构如下
<div class="wrap">
     <div class="box"></div>
  </div>
固定的样式
.box{
      width: 100px;
      height: 100px;
      border: 1px solid red;
    }

实现方法: 有点玩赖, 就是两个属性的随意组合, 突出一个 ’ 秀 ’
注意这里的属性不是 flex 的, 他在 grid 布局模式下就是属于 grid.

.wrap{
      // 当然了开启布局的方式也与 flex 一样
      display: inline-grid | grid;
      width: 300px;
      height: 300px;
      // 第一种
      align-items: center;
      justify-items: center;
      // 第二种
      align-items: center;
      justify-content: center;
      // 第三种
      align-content: center;
      justify-items: center;
      // 第四种
      align-content: center;
      justify-content: center;
    }

四. 横排的排列

开启布局时, 我们打开调试模式鼠标悬停在 dom 上会出现网格
与 flex 不一样, 单纯的开启布局并不会影响元素的布局, 不会压缩抻拉宽高.
  <style>
    /* 只是开启 grid 布局不会有变化, 不像 flex 布局默认把内部的元素排成一排 */
     .wrap{
       display: grid;
       height: 100px;
       width: 300px;
       border: 1px solid;
     }
     .box{
       height: 50px;
       width: 50px;
       border: 1px solid red;
     }
  </style>
</head>
<body>
   <div class="wrap">
     <div class="box">1</div>
     <div class="box">2</div>
     <div class="box">3</div>
   </div>
</body>

grid-template-columns 定义把 dom 横排分成几份, 每份宽度是多少.

这里就是把 dom 分为 4 段, 每段 100px 宽, 然后我们就可以往里面放内容了.
grid-template-columns: 100px 100px 100px 100px;

横排排列
<style>
     .wrap{
       display: grid;
       height: 100px;
       width: 300px;
       border: 1px solid;
       /* 1: 成为一行, 开启这个 */
       /* 总共 3 列, 每列 100px */
       grid-template-columns: 100px 100px 100px;
     }
     .box{
       height: 50px;
       /* 子组件不设置宽度就会自动填充单元格 */
       /* 与上面的 3 个 100px 相对应 */
       border: 1px solid red;

     }
  </style>
</head>
<body>
   <div class="wrap">
     <div class="box">1</div>
     <div class="box">2</div>
     <div class="box">3</div>
   </div>
</body>

repeat 定义重复的部分

比如我们要把横排分成 10 份, 那我们写 10 个 100px 显然很笨拙, 可以使用如下的方式:
grid-template-columns: repeat(10, 100px);

我们想实现如下效果:

grid-template-columns: 100px 100px 100px 100px 100px 100px 200px 100px 100px 100px 100px;
可以这样写:
grid-template-columns: repeat(6, 100px) 200px repeat(4, 100px);

重复的类型也可以多样

grid-template-columns: 100px 200px 100px 200px 100px 200px 100px 200px 100px 200px 100px 200px
可以如下的方式书写:(要注意这里只有一个 ’ 逗号 ’)
grid-template-columns: repeat(6, 100px 200px);

auto-fill 属性 根据设定的宽度, 自动填充

比如我 dom 的宽度是 400px 那么下面的代码就会生成 10 个 40px 宽的格子, 当然如果 dom 宽是 390px, 它只会生成 9 个;
grid-template-columns: repeat(auto-fill, 40px);

技巧跳列
比如我们把横排分为 3 个格子每个 100px, 但是我只放入两个元素, 分别在第 1 个与第 3 个格子, 那么我们可以使用一个技巧, 就是中间放一个空元素, 而这个空元素应尽可能小的消耗内存, 那么可以尝试放一个 br 标签, 当然这种方式不推荐, 布局上会给其他同学造成一些困扰, 代码如下:
 <style>
     .wrap{
       display: grid;
       height: 100px;
       width: 300px;
       border: 1px solid;
       grid-template-columns: 100px 100px 100px 100px;
     }
     .box{
       height: 50px;
       border: 1px solid red;
     }
  </style>
</head>
<body>
   <div class="wrap">
     <div class="box">1</div>
     <br>
     <div class="box">3</div>
   </div>
</body>

五. [fr, auto] 单位与关键字

fr

我们知道在 flex 布局里面, 比如我写 flex:1, 他代表着在 flex 布局里面占总份数里面的一份, grid 里面也有类似的属性, 而且更加的定制化语义化, 他就是 fr.

下面这段代码的意思就是把 dom 分成 5 份, 每份就是占一份的宽.

grid-template-columns: repeat(5,1fr);

大家瓜分剩余空间

grid-template-columns: 120px 1fr 2fr 3fr 1fr;

auto

auto 关键字, 单独存在时功能与 1fr 差不多,但是语义化更明显
grid-template-columns: 20px 20px auto 20px 20px;

auto 与 1fr 的区别,他不参与 fr 的计算规则,所以与 fr 同时使用会被挤成自身宽度
grid-template-columns: 20px 2fr auto 1fr 20px;
下图里面的 3 就是靠自身撑起的宽度

六. minmax限定范围

下面设置最小宽与最大宽

<style>
     .wrap{
       display: grid;
       border: 1px solid;
       width: 300px;
       height: 100px;
       /* 最小值,最大值,比如被压缩的时候要留一个基本宽度 */
       /* 里面可以填写 fr 为单位的数字,这就是好处 */
       grid-template-columns: 1fr 1fr minmax(300px,1fr);
     }
     .box{border: 1px solid red;}
  </style>
</head>
<body>
   <div class="wrap">
     <div class="box">1</div>
     <div class="box">2</div>
     <div class="box">3</div>
   </div>
当父级 320px 宽

当父级 200px 宽

七. 纵列格子

我们已经把横向弄忘了, 就像学会了九阳神功的张无忌学乾坤大挪移.
grid-template-rows 属性就是定义列的
当然, 在行可以用的技巧, 在列上都可以使用

  <style>
     .wrap{
       display: grid;
       border: 1px solid;
       height: 200px;
       width: 500px;
       grid-template-columns: 1fr 1fr 100px;
       grid-template-rows: 30px 60px 1fr;
     }
     .box{border: 1px solid red;}
  </style>
</head>
<body>
   <div class="wrap">
     <div class="box">1</div>
     <div class="box">2</div>
     <div class="box">3</div>
     <div class="box">4</div>
     <div class="box">5</div>
     <div class="box">6</div>
     <div class="box">7</div>
     <div class="box">8</div>
     <div class="box">9</div>
   </div>
</body>

八. 元素间隔

距离产生美,这么多格子当然需要点距离啦。

固定代码
<style>
     .wrap{
       display: grid;
       border: 1px solid;
       height: 300px;
       width: 300px;
       grid-template-columns: 1fr 1fr 1fr;
       grid-template-rows:  1fr 1fr 1fr;
     }
     .box{border: 1px solid red;}
  </style>
</head>
<body>
   <div class="wrap">
     <div class="box">1</div>
     <div class="box">2</div>
     <div class="box">3</div>
     <div class="box">4</div>
     <div class="box">5</div>
     <div class="box">6</div>
     <div class="box">7</div>
     <div class="box">8</div>
     <div class="box">9</div>
   </div>
</body>
添加: grid-row-gap: 10px;

添加:grid-column-gap: 10px;

当然了,这两个属性可以简写为 grid-gap:10px;或者grid-gap:10px 10px;


给父级一个 padding:10px

注意:暂时不支持这样写 grid-row-gap: 10px 20px; 也就是说不固定的间距需要想别的办法了。

我们可以在画格子的时候,把间距也当格子画。

九. 颠倒

grid-auto-flow: column; 格子的定位从横向变为了纵向

  <style>
     .wrap{
       display: grid;
       border: 1px solid;
       height: 300px;
       width: 300px;
       grid-template-columns: 1fr 1fr 1fr;
       grid-template-rows:  1fr 1fr 1fr;
       padding: 10px;
       grid-gap:10px;
       /* 定义排列的顺序, 类似方块旋转了 */
       /* 比如说竖排的布局,类似对联的效果就简单实现了 */
       grid-auto-flow: column; 
     }
     .box{border: 1px solid red;}
  </style>
</head>
<body>
   <div class="wrap">
     <div class="box">1</div>
     <div class="box">2</div>
     <div class="box">3</div>
     <div class="box">4</div>
     <div class="box">5</div>
     <div class="box">6</div>
     <div class="box">7</div>
     <div class="box">8</div>
     <div class="box">9</div>
   </div>
</body>

十. 居中对齐方式的解析

这里我们就可以解释一下最开始说的对齐方式的原理。

第一部分:网格的位置

  <style>
     .wrap{
       display: grid;
       border: 1px solid;
       height: 330px;
       width: 330px;
       /* 当单元格小于容器时效果显著 */
       grid-template-columns: 80px 80px 80px;
       grid-template-rows:  80px 80px 80px;
       grid-gap:10px;

     }
     .box{border: 1px solid red;}
  </style>
</head>
<body>
   <div class="wrap">
     <div class="box">1</div>
     <div class="box">2</div>
     <div class="box">3</div>
     <div class="box">4</div>
     <div class="box">5</div>
     <div class="box">6</div>
     <div class="box">7</div>
     <div class="box">8</div>
     <div class="box">9</div>
   </div>
</body>
居中
 justify-content: center; 
 align-content: center;

居右
 justify-content: end; 
 align-content: center;

居右下
 justify-content: end; 
 align-content: end;

简洁写法,直接定义两个属性

place-content:center

奇怪的取值范围(重点!)

justify-content: 取值范围:left right flex-end flex-start end start

align-content: 取值范围:flex-end flex-start end start

奇怪的点 1:align-content 不可以用 left right
奇怪的点 2:flex-end 这种属性居然有效
奇怪的点 3:可以用 left right 但是不可以用 top bottom

真是奇奇怪怪没有脑袋。。。。我建议采用 center end start 这样专属 grid 的意义更加明确。

第二部分:单元格的对齐

每个小网格就像是 excel 的一个单元格,那么这些单元格的排布方式也很有趣,第一种就整体的排布,第二种是自身的排布。

<style>
     .wrap{
       display: grid;
       border: 1px solid;
       height: 300px;
       width: 300px;
       grid-template-columns: 1fr 1fr 1fr;
       grid-template-rows:  1fr 1fr 1fr;
       grid-gap:10px;
       justify-items: center;
       align-items: center;
     }
     .box{
       height: 50px;
       width: 50px;
       border: 1px solid red;
     }
     .box4{
       justify-self:end;
       align-self: end;
     }
     .box5{
       justify-self:start;
       align-self: start;
     }
     .box6{
       justify-self:stretch;
       align-self: stretch;
       border: 1px solid red;
     }
     .box7{border: 1px solid red;}
  </style>
</head>
<body>
   <div class="wrap">
     <div class="box">1</div>
     <div class="box">2</div>
     <div class="box">3</div>
     <div class="box box4">4</div>
     <div class="box box5">5</div>
     <div class="box6">6</div>
     <div class="box7">7</div>
   </div>
</body>

  1. 前 3 个收到父级的 justify-items:` align-items:` 影响所以上下左右居中。
  2. 第 4 个自身布局优先级最高,出现在右下角
  3. 6 与 7 是因为未设置宽高的情况下,设置了 stretch 属性导致自身是否被拉伸。

stretch 填满单元格的宽度(默认值)

通过这里的学习,我们就能明白最开是的居中方式了,面试的时候你可以大展身手了。

十一. dom 排位 grid-row-start

定义格子从哪里开始, 到哪里结束, 这样可以不用 br 这种站位标签了.
<style>
    /* 只是开启 grid 布局不会有变化, 不像 flex 布局默认把内部的元素排成一排 */
     .wrap{
       display: grid;
       border: 1px solid;
       height: 500px;
       width: 500px;
       grid-template-columns: 1fr 1fr 1fr;
       grid-template-rows:  1fr 1fr 1fr;
       grid-gap:10px;
     }
     .box{
       /* height: 50px;
       width: 50px; */
       border: 1px solid red;
     }
     .box1 {
       /* 1:我可以自由选择我从网格的哪里开始,哪里结束 */
       /* 也就是说打破了自由排列的起始值 */
       grid-column-start: 2;

       /* 2:结束就是这个元素占据的’宽度‘*/
       /* 注意:无法作到跨行的延续 */
       grid-column-end: 4;

       /* 3: 列当然也可以这么玩 */
       /* 他到了下面去, 而不占用空间, 就是说他并不会把全体都往下弄一行 */
       grid-row-start: 2;
       grid-row-end: 4;


       /* 4: 简洁写法, 斜杠挺假的 */
       /* 讨论一下, 为啥要用 斜杠??? 而不是空格 */
       /* 不写就是默认跨越一个 */
       grid-column: 1 / 3;
       grid-row: 1 / 3;
     }
  </style>
</head>
<body>
   <div class="wrap">
     <div class="box box1">1:第一格开始,第三格结束 </div>
     <div class="box">2</div>
     <div class="box">3</div>
     <div class="box">4</div>
   </div>
</body>


这种写法突然出现 ‘/’ 斜线, 我感觉挺不舒服的, 不知道为啥这么设计.

 grid-column: 1 / 3;
 grid-row: 1 / 3;
要注意, 这种布局方式会有计算量的, 我个人不太建议这样玩 ….

十二. 古怪的居中方式(脑洞)

中规中矩的思维没法走的更快,让我来抛砖引如一下。

  <style>
     .wrap{
       display: grid;
       border: 1px solid;
       height: 300px;
       width: 300px;
       grid-template-columns: 1fr 1fr 1fr;
       grid-template-rows:  1fr 1fr 1fr;
       /* 1: 把单元格内的项目居中 */
       justify-items: center;
       align-items: center;
     }
     .box{
       /* 可以满足大于单元格的物体居中 */
       height: 250px;
       width: 250px;
       border: 1px solid red;
       /* 2: 设置了 9 个单元格, 把他放到中间的单元格就 ok 了 */
       grid-row-start: 2;
       grid-column-start:2 ;
     }
     /* 四个角, 位置被完全混淆了, 不要这样用 */
     .box1{
      grid-column-start: 1;
      grid-column-end: 2;
     }
     .box2{
       grid-column-start: 3;
      grid-column-end: 4;
     }
     .box3{
       /* 涉及到了网格错位的知识, 不建议这么用, 当然你会算别人不一定会算~~~ */
      grid-column-start: 1;
      grid-column-end: 2;
      grid-row-start: 3;
     }
     .box4{
      grid-column-start: 3;
      grid-column-end: 4;
      grid-row-start: 3;
     }
  </style>
</head>
<body>
   <div class="wrap">
     <div class="box1"> 角 </div>
     <div class="box2"> 角 </div>
     <div class="box">***** 这样居中的好处是, 可以在四个角做一些文章, 这是一种思维游戏 </div>
     <div class="box3"> 角 </div>
     <div class="box4"> 角 </div>
   </div>
</body>


坑点: 这四个角有点错乱, 你计算好了, 但是其他同学不一定计算的对, 需要把他封装起来.
扩展: 这四个角我们可以放一点花样, 应该挺好看的 …

十三. span 关键字

grid-column-start: span 2;不用写结尾了, 表明站几个就好了, 当然也有 row 属性可以设置.

也就是说 span 3 意思就是当前位置 往后 3 个格子都是我的了

十四. 映射布局(精髓)

有的时候就要直接一点, 这个知识点才是 grid 的灵魂.

grid-template-areas:

我们照常使用 grid-template-columns 为 dom 画格子, 然后为每个单元格定义一个名字, 什么名字都可以, 如果用不上的单元格名字就定义为 ’.’, 举个例子如下:

 grid-template-areas: 
        "header header header header"
        "main   main   .      sidebar"
        "footer footer footer footer";
上面的代码我们可以给内部 dom 自身一个 grid-area: header; 属性, 那么 dom 就会占据最上面四个格子的位置, 简直太直接了, 相当于多了个缩略图.
只能写出 ’ 矩形 ’ 的方阵, 并且必须是一体的, 俩个 ’header’ 不连贯东一个西一个也不会生效.
  <style>
     .wrap{
       display: grid;
       border: 1px solid;
       height: 300px;
       width: 300px;
       grid-template-columns: repeat(4,1fr);
       grid-template-rows:   repeat(3,1fr);
       grid-gap:10px;
       justify-content: center;
       align-content: center;
       padding: 10px;

      /* 1: 可视化映射, 我的理解这个才是灵魂, 这个功能才是无法取代 */
      /* '.' 表示一个空的单元格 */
       grid-template-areas: 
        "header header header header"
        "main main . sidebar"
        "footer footer footer footer";

     }
     .box{border: 1px solid red;}
     .box1{grid-area: header;}
     .box2{grid-area: main;}
     .box3{grid-area: sidebar;}
     .box4{grid-area: footer;}
  </style>
</head>
<body>
  <p> 可以利用可视化做居中, 没人这样用, 但是如果是你不敢想那就...</p>
   <div class="wrap">
     <div class="box box1">1</div>
     <div class="box box2">2</div>
     <div class="box box3">3</div>
     <div class="box box4">4</div>
   </div>
</body>

别看它简单, 接下来可以做一些有意思的事情了.

十五. 位置挪移要当心

我画了一个简易的游戏, 把点击的部位变黑, 当时设想是做最强大脑里面的那个奇偶消融游戏, 但是 grid 布局有自身的局限后来放弃了, 相关的问题我通过图片展示一下.


当我变换小球位置的时候, 前面的小球会补充之前的位置, 导致位置信息不好算了, 当然我们可以把每个小球固定, 然后在上面覆盖一层, 但这样做也没必要用 grid 布局了.

十六. 画表情的一点启发(类似我的世界)

之前还画了个 ’ 大风车 ’ 和 ’ 八卦图 ’, 就不在这里展示了, 但是我画了个笑脸的代码还是分享给大家把:
<style>
    .wrap{
      display: grid;
      height: 600px;
      width: 600px;
      margin: 50px auto;
      /* 用 auto 的话会导致大小不一致, 因为 auto 算是自适应里面的宽高 */
      grid-template-columns: repeat(15,1fr);
      grid-template-rows: repeat(15,1fr);
      justify-items: stretch;
      align-items: stretch;    
      grid-template-areas: 
      ". . . . . a a a a a . . . . ."
      ". . . b b f1 f1 f1 f1 f1 c c . . ."
      ". . d g5 g5 f1 f1 f1 f1 f1 f2 f2 e . ."
      ". f g4 g4 g4 f1 f1 f1 f1 f1 f4 f4 f4 g ."
      ". f g4 g4 g4 f1 f1 f1 f1 f1 f4 f4 f4 g ."
      "h g3 g4 g4 g4 f1 f1 f1 f1 f1 f4 f4 f4 f3 i"
      "h g3 g2 q q f1 f1 f1 f1 f1 r r r f3 i"
      "h g3 g2 q q f1 f1 f1 f1 f1 f6 f6 f5 f3 i"
      "h g3 g2 f9 f9 f1 f1 f1 f1 f1 f6 f6 f5 f3 i"
      "h g3 g2 f9 f9 f1 f1 f1 f1 f1 f6 f6 f5 f3 i"
      ". j g2 f9 f9 g1 s s s f7 f6 f6 f5 p ."
      ". j g2 f9 f9 f8 f8 f8 f8 f7 f6 f6 f5 p ."
      ". . k f9 f9 f8 f8 f8 f8 f7 f6 f6 o . ."
      ". . . m m f8 f8 f8 f8 f7 n n . . ."
      ". . . . . l l l l l . . . . ."
      ;  
    }
    .box {background-color: black;}
    .box-a{grid-area: a;}
    .box-b{grid-area: b;}
    .box-c{grid-area: c;}
    .box-d{grid-area: d;}
    .box-e{grid-area: e;}
    .box-f{grid-area: f;}
    .box-g{grid-area: g;}
    .box-h{grid-area: h;}
    .box-i{grid-area: i;}
    .box-j{grid-area: j;}
    .box-k{grid-area: k;}
    .box-l{grid-area: l;}
    .box-m{grid-area: m;}
    .box-n{grid-area: n;}
    .box-o{grid-area: o;}
    .box-p{grid-area: p;}
    .box-q{
      grid-area: q;
      display: flex;
      justify-content: center;
      align-items: center;
      background-color: rgb(255, 206, 46);
    }
    .box-q::after{
      content: '';
      display: block;
      height: 70px;
      width: 70px;
      border-radius: 50%;
      background-color: red;
    }
    .box-r{grid-area: r;}
    .box-s{grid-area: s;}
    .box-t{grid-area: t;}
    .f{background-color: rgb(251, 209, 71);
    }
    .f1{grid-area: f1;}
    .f2{grid-area: f2;}
    .f3{grid-area: f3;}
    .f4{grid-area: f4;}
    .f5{grid-area: f5;}
    .f6{grid-area: f6;}
    .f7{grid-area: f7;}
    .f8{grid-area: f8;}
    .f9{grid-area: f9;}
    .g1{grid-area: g1;}
    .g2{grid-area: g2;}
    .g3{grid-area: g3;}
    .g4{grid-area: g4;}

    .g5{grid-area: g5;}
    .g6{grid-area: g6;}
  </style>
</head>
<body>
   <!-- 采用 3 个 dom 拼接, 或者采用拼图板, 拼图更能体现 grid 布局的又优势 -->
   <div class="wrap">
     <div class="box box-a"> v </div>
     <div class="box box-b"> v </div>
     <div class="box box-c"> v </div>
     <div class="box box-d"> v </div>
     <div class="box box-e"> v </div>
     <div class="box box-f"> v </div>
     <div class="box box-g"> v </div>
     <div class="box box-h"> v </div>
     <div class="box box-i"> v </div>
     <div class="box box-j"> v </div>
     <div class="box box-k"> v </div>
     <div class="box box-l"> v </div>
     <div class="box box-m"> v </div>
     <div class="box box-n"> v </div>
     <div class="box box-o"> v </div>
     <div class="box box-p"> v </div>
     <div class="box box-q">  </div>
     <div class="box box-r"> v </div>
     <div class="box box-s"> v </div>
     <!-- 肤色 -->
     <div class="f f1"></div>
     <div class="f f2"></div>
     <div class="f f3"></div>
     <div class="f f4"></div>
     <div class="f f5"></div>
     <div class="f f6"></div>
     <div class="f f7"></div>
     <div class="f f8"></div>
     <div class="f f9"></div>
     <div class="f g1"></div>
     <div class="f g2"></div>
     <div class="f g3"></div>
     <div class="f g4"></div>
     <div class="f g5"></div>
     <div class="f g6"></div>
   </div>
</body>
也就是开局那张图, 使用 grid 的来画这张图简直舒服!!

end

本次的分享会就到这里, 如果有收获的话点在赞在走喽 ….
希望和你一起进步.

end.

退出移动版