Gird

334 阅读8分钟

概述

最近有几个bug和需求,涉及到布局和样式,在尽量不大动老代码的情况下,flex布局显得有些力不从心,flex布局是一种一维布局,一次只能处理一个维度的元素布局,一行或者一列,而grid布局是二维布局,可以同时处理行和列的布局,grid布局远比flex布局强大的多,下面简单梳理下grid布局的一些前置知识。

前置知识

容器和项目

采用网格布局的区域,称为容器(container),容器内的顶级子容器,称为项目(item)

单元格和网格线

行列交叉为单元格,n行m列会产生n*m个单元格,划分网格的线称为网格线,n行有n+1根水平网格线,m列有m+1根垂直网格线,网格线概念与项目属性grid-row-startgrid-row-end grid-column-start grid-column-end关系密切。

grid.png

容器属性

display

  • display:grid(声明该容器是个块级元素)
  • display:inline-grid(声明该容器是行内元素)

注意,设为网格布局以后,容器子元素(项目)的float、display: inline-block、display: table-cell、vertical-align和column-*等设置都将失效

grid-template-rows、grid-template-columns和grid-auto-rows、grid-auto-columns

这两组四个属性放一块梳理,第一组显式行列(grid-template-rows、grid-template-columns),第二组隐式行列(grid-auto-rows、grid-auto-columns

现在有个2 * 3的布局,但该容器内不止6个项目,此时浏览器会自动创建多余的网格,这种情况下,2 * 3为显示网格,多余的项目为隐式网格,通过grid-template-rows、grid-template-columns可设置显示网格的行宽,列宽,通过grid-auto-rows、grid-auto-columns可设置隐式网格的行宽、列宽

.container {
    display: grid;
    /* 声明了三列,宽度分别为 100px 100px 100px */
    grid-template-columns: 100px 100px 100px;
    /* 声明了两行,宽度分别为 100px 100px */
    grid-template-rows: 100px 100px;
    /* 设置隐式网格行50px */
    grid-auto-rows: 50px;
}

image.png

在设置这四个属性时,有一些函数可简化操作

repeat(重复次数,重复值/重复模式)

.container {
  display: grid;
  grid-template-columns: repeat(3,100px);
  grid-template-rows: repeat(3,100px);
}

fr关键字

场景:构建n行2列且2列等分,列宽随着容器大小自适应,可用fr关键字,fr表示比例关系,两列宽度都为1fr,表示两列列宽相等,若为1fr,2fr,表示后者是前者的两倍,fr也可与绝对长度结合使用

用大白话讲,fr代表份,nfr表示在总长度中占n份

.container {
  display: grid;
  /* 声明三列,第一列占一份,第二、三列均占两份 */
  grid-template-columns: 1fr 2fr 2fr;
}

fr.gif

auto-fill关键字

auto-fill表示自动填充,让一行或者一列尽可能更多容纳更多的单元格,grid-template-columns: repeat(auto-fill, 100px) 表示列宽是 100 px,但每行列的数量随着容器宽度变化,只要容器容纳的下,就可以放置元素

.container {
    width: 50vw;
    display: grid;
    grid-template-columns: repeat(auto-fill, 100px);
    /* 声明了两行,宽度分别为 100px 100px */
    grid-template-rows: 100px 100px;
    /* 设置隐式网格行50px */
    grid-auto-rows: 50px;
}

auto-fill.gif

minmax(最小值,最大值)

minmax函数产生一个长度范围,表示网格元素长度在此范围内,grid-template-column:minmax(100px,300px) 1fr表示第一列列宽最小100px,最大300px

auto关键字

auto表示由浏览器自己决定长度,auto可轻松实现左右两列固定宽度,中间自适应布局,grid-template-columns: 100px auto 100px 表示第一第三列为 100px,中间由浏览器决定长度

auto.gif

row-gap、column-gap、gap

row-gap设置行间距,column-gap设置列间距

gap为合并简写形式,gap:<row-gap> <column-gap>

grid-template-areas

grid-template-areas用来定义区域,大白话讲就是给网格元素取名字,搭配项目属性grid-area一起使用的,grid-area 属性指定项目放在哪一个网格,这两个属性能轻松实现不同行不同个数项目的布局

image.png

<div class="container">
    <div class="item_1">1</div>
    <div class="item_2">2</div>
    <div class="item_3">3</div>
</div>

  .container {
    width: 50vw;
    display: grid;
    grid-template-columns: repeat(2, 100px);
    grid-auto-rows: 100px;
    grid-template-areas:
      "header header"
      "content_1 content_2";
  }
  .container div {
    display: grid;
    place-content: center;
  }
  .item_1 {
    background-color: aquamarine;
    grid-area: header;
  }
  .item_2 {
    background-color: brown;
    grid-area: content_1;
  }
  .item_3 {
    background-color: blueviolet;
    grid-area: content_2;
  }

grid-auto-flow

控制自动布局算法怎么运作,默认row(先行后列)

可取值:row(先行后列),row dense(先行后列,尽可能填满),column(先列后行),column dense(先列后行,尽可能填满)

.container {
    display: grid;
    grid-template-columns: repeat(3, 100px);
    grid-auto-rows: 100px;
    grid-auto-flow: row;
}

image.png 这种情况下出现空缺,使用grid-auto-flow: row dense尽可能填满

.container {
    display: grid;
    grid-template-columns: repeat(3, 100px);
    grid-auto-rows: 100px;
    grid-auto-flow: row dense;
}

image.png grid-auto-flow: column grid-auto-flow: column dense同理,就不过多赘述

justify-items、align-items、place-items和justify-content、align-content、place-content

也是两组属性,单元格位置(justify-items align-items place-items)和内容位置(justify-content align-content place-content

place-items为justify-items和align-items合并简写形式

place-items:<justify-items> <align-items>

place-content为justify-content和align-content合并简写形式

place-content:<justify-content> <align-content>

单元格位置

justify-items align-items可取值如下,以下图以justify-item属性为例进行讲解,align-items属性同理,只是方向为垂直方向

  • start:对齐单元格的起始边缘

image.png

  • end:对齐单元格的结束边缘

image.png

  • center:单元格内部居中

image.png

  • stretch:拉伸,占满单元格的整个宽度(默认值)

image.png

内容位置

justify-content align-content可取值如下,以下图以justify-content属性为例进行讲解,align-content属性同理,只是方向为垂直方向

  • start:对齐容器的起始边框

image.png

  • end - 对齐容器的结束边框

image.png

  • center - 容器内部居中

image.png

  • stretch - 项目大小没有指定时,拉伸占据整个网格容器
  • space-around - 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与容器边框的间隔大一倍

image.png

  • space-between - 项目与项目的间隔相等,项目与容器边框之间没有间隔

image.png

  • space-evenly - 项目与项目的间隔相等,项目与容器边框之间也是同样长度的间隔

image.png

项目属性

grid-column-start、grid-column-end、grid-row-start、grid-row-end

这四个属性指定项目的边框定位在哪根网格线

  • grid-column-start:左边框所在的垂直网格线
  • grid-column-end:右边框所在的垂直网格线
  • grid-row-start:上边框所在的水平网格线
  • grid-row-end:下边框所在的水平网格线

grid-column、grid-row

grid-column是grid-column-start和grid-column-end的合并简写形式

grid-column: <start-line> / <end-line>;

grid-row是grid-row-start和grid-row-end的合并简写形式

grid-row: <start-line> / <end-line>; image.png 上图布局观察到,1号项目左侧网格线定位在第一根网格线,右侧网格线定位在第四根网格线

  .item_1 {
    grid-column: 1/4;
  }

可以使用span关键字,表示"跨越",即左右边框(上下边框)之间跨越多少个网格,上述代码等价于

  .item_1 {
    grid-column: span 3;
  }

grid-area

指定项目放在哪个区域,具体使用看上述grid-template-areas描述

还可用作grid-row-start、grid-column-start、grid-row-end、grid-column-end的合并简写形式,直接指定项目的位置,如grid-area: 1 / 1 / 2 / 4,与上述grid-column: 1/4grid-column: span 3等价

  .item_1 {
    grid-area: 1/1/2/4;
  }

justify-self、align-self、place-self

justify-self属性设置单元格内容的水平位置(左中右),跟justify-items属性的用法完全一致,但只作用于单个项目。

align-self属性设置单元格内容的垂直位置(上中下),跟align-items属性的用法完全一致,也是只作用于单个项目

常见问题

为啥设置了1fr,宽度会超出

在使用CSS Grid布局时,设置1fr表示将可用空间平均分配给每个单元格,但是如果单元格中包含有固定宽度的内容,比如图片、文本等,那么单元格的实际宽度就会超出1fr所分配的空间。

例如,如果一个单元格设置了1fr,但是其中包含了一个宽度为100px的图片,那么该单元格的实际宽度就会是100px加上1fr分配的空间,这样就会导致单元格的宽度超出预期。

为了避免这种情况,可以考虑通过设置单元格的最大宽度来限制单元格的宽度,例如使用max-width属性或者minmax函数:

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

在上述代码中,使用minmax函数设置单元格的最小宽度为200px,最大宽度为1fr,这样可以平衡单元格宽度和内容宽度之间的关系,避免单元格宽度超出预期。

结语

这是我目前所了解的grid布局,当然也有可能存在一定的误区。

希望对大家有帮助,不喜勿喷