什么是栅格

现在很多的 UI 组件库都提供了栅格系统,在响应式方面非常的方面,今天我们来谈的是 CSS 原生的栅格系统。

栅格系统是一个二维系统,他可以同时处理行和列

image-20220630172312476

栅格系统很强大,但是兼容性并不是特别好(我感觉其实已经可以了),截至目前(2022.6.30)grid 的兼容性如下

image-20220630182930776

绘制栅格

使用 display: grid; 声明一个 grid 容器。

绘制行列需要使用grid-template-rows 声明行的高度,grid-template-columns 声明列的宽度

<style>
  .grid {
    width: 200px;
    height: 200px;
    border: 1px solid silver;
    display: grid;
    grid-template-rows: 100px 100px;
    grid-template-columns: 100px 100px;
  }

  .grid div {
    background-color: pink;
    background-clip: content-box;
    padding: 10px;
    border: 1px solid pink;
    box-sizing: border-box;
  }
</style>

<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>

上面的示例中声明了一个 2*2 的 grid,并且固定量宽度和高度

image-20220630184400166

除了使用固定宽高,还可以使用百分比

<style>
  .grid {
    width: 200px;
    height: 200px;
    border: 1px solid silver;
    display: grid;
    grid-template-rows: 30% 70%;
    grid-template-columns: 50% 50%;
  }

  .grid div {
    background-color: pink;
    background-clip: content-box;
    padding: 10px;
    border: 1px solid pink;
    box-sizing: border-box;
  }
</style>
<!-- <div class="triangle"></div> -->
<!-- <div id="circle-rect"></div> -->
<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>

百分比的计算是相对于 grid 容器来计算的,上面的代码表示第一行高度为 30%,第二行高度为 70%,每一列的宽度都为 50%

image-20220630184715328

如果行列的百分比加起来不足 100%就会有空余区域,如果大于 100%就会超出容器范围

可以使用 repeat 函数来帮我们进行重复操作

.grid {
  width: 200px;
  height: 200px;
  border: 1px solid silver;
  display: grid;
  grid-template-rows: repeat(2, 50%); /*等价于 50% 50%*/
  grid-template-columns: repeat(4, 25%);/*等价于 25% 25% 25% 25%*/
}

image-20220630185156528

在使用 repeat 来进行重复操作时,可以传入多个数值,比如repeat(2, 100px 50px),等价于 100px 50px 100px 50px,是将第二个参数整体重复多次

除了 repeat 固定数值,还可以让 grid 自动填充

.grid {
  width: 200px;
  height: 200px;
  border: 1px solid silver;
  display: grid;
  grid-template-rows: repeat(auto-fill, 100px);
  grid-template-columns: repeat(auto-fill, 100px);
}

上面这段代码会让 div 按照每份 100px 的宽高进行自动分配,比如容器宽度不确定时,可以使用自动分配

和自动分配比较接近的是按比例划分,类似于 flex 布局中使用 flex 声明比例

.grid {
  width: 60%;
  height: 200px;
  border: 1px solid silver;
  display: grid;
  grid-template-rows: 1fr 2fr;
  grid-template-columns: 2fr 3fr;
}

第一行高度为 1/3 第二行高度为 2/3,第一列宽度为 2/5 第二列宽度为 3/5

image-20220630190048805

可以使用 minmax 控制尺寸的响应式波动

.grid {
  width: 60%;
  height: 50px;
  border: 1px solid silver;
  display: grid;
  grid-template-rows: repeat(2, minmax(30px, 50px));
  grid-template-columns: 2fr 3fr;
}

列按照比例等比划分,公有两行,每一行最小 30px, 最大 50px,如果容器范围小于所有行的最小范围,内容就会溢出

image-20220630190807601

间距控制

间距控制可以使用 margin,完全没问题,但是不够优雅,我们可以使用栅格提供的间距控制属性row-gap或、column-gap或者直接使用 gap

.grid {
  width: 60%;
  height: 100px;
  border: 1px solid silver;
  display: grid;
  grid-template-rows: repeat(2, minmax(30px, 50px));
  grid-template-columns: 2fr 3fr;
  gap: 20px 10px;
  /* 等价于
  row-gap: 20px;
  column-gap: 10px;
  */
}

image-20220630191424168

使用 gap 时如果只设置一个数值,则行间距和列间距同时应用这个数值

栅格线定位

栅格线可以使用命名与编号找到,方便控制指定栅格,或将内容添加到指定栅格中。

栅格命名有两种方式,主动命名和自动命名。

自动命名就是按照栅格线从一开始向正方向计数

<style>
  .grid {
    width: 200px;
    height: 200px;
    border: 1px solid silver;
    display: grid;
    grid-template-rows: repeat(3, 1fr);
    grid-template-columns: repeat(3, 1fr);

  }

  .grid div {
    background-color: pink;
    background-clip: content-box;
    padding: 10px;
    border: 1px solid pink;
    box-sizing: border-box;
  }

  .grid div:first-child {
    grid-row-start: 1;
    grid-column-start: 1;
    grid-row-end: 2;
    grid-column-end: 4;
  }
</style>
<div class="grid">
  <div>1</div>
</div>

控制 div 在第一条横线起始,第二条横线结束,也就是第一列;第一条竖线起始,第四条竖线结束,也就是第一、二、三列。

image-20220630194622832

主动命名就是在声明 grid 行列的时候手动为栅格线命名

<style>
  .grid {
    width: 300px;
    height: 300px;
    border: 1px solid silver;
    display: grid;
    grid-template-rows: [r1-start] 100px [r1-end r2-start] 100px [r2-end r3-start] 100px [r4-end];
    grid-template-columns: [c1-start] 100px [c1-end c2-start] 100px [c2-end c3-start] 100px [c4-end];

  }

  .grid div {
    background-color: pink;
    background-clip: content-box;
    padding: 10px;
    border: 1px solid pink;
    box-sizing: border-box;
  }

  .grid div:first-child {
    grid-row-start: r1-start;
    grid-column-start: c2-start;
    grid-row-end: r2-end;
    grid-column-end: c2-end;
  }
</style>
<div class="grid">
  <div>1</div>
</div>

通过主动命名来实现栅格内容的填充

image-20220630200526153

在手动命名栅格线的时候也可配合重复来简化操作

<style>
  .grid {
    width: 300px;
    height: 300px;
    border: 1px solid silver;
    display: grid;
    grid-template-rows: repeat(3, [r-start] 1fr [r-end]);
    grid-template-columns: repeat(3, [c-start] 1fr [c-end]);

  }

  .grid div {
    background-color: pink;
    background-clip: content-box;
    padding: 10px;
    border: 1px solid pink;
    box-sizing: border-box;
  }

  .grid div:first-child {
    grid-row-start: r-start 1;
    grid-column-start: c-start 2;
    grid-row-end: r-end 2;
    grid-column-end: c-end 1;
  }
</style>
<div class="grid">
  <div>1</div>
</div>

通过重复栅格+命名的方式我们实现了和上一个例子相同的效果

image-20220630200944691

可能会有人觉得这样多此一举,这样和自动命名编号没有区别。但是,注意如果重复栅格一组只有一个格效果和自动命名是一样的,但是如果重复栅格是多组的那么效果就不一样了

上面命名的示例都是通过栅格线定位的,还可以通过偏移量来定位

.grid div:first-child {
  grid-row-start: r-start 2;
  grid-column-start: c-start 2;
  grid-row-end: span 2;
  grid-column-end: span 1;
}

通过 span 来表示使用偏移量来定位

image-20220630201745626

行列定位可以使用组合模式

    .grid div:first-child {
      grid-row: r-start 2 / r-end 3;
      grid-column: c-start 2 / span 1;
      /* grid-row: 2 / 4;
      grid-column: 2 / span 1; */
    }

组合模式可以将多种方式混合使用,自动命名定位、手动命名定位、偏移量定位,/前面是start, 后面是 end

区域定位

除了使用栅格线定位还可以使用区域定位

.grid div:first-child {
  grid-area: 2 / 2 / 4 / 3;
}

我们使用区域定位实现了和上面示例相同的效果

image-20220630201745626

区域布局同样可以使用命名栅格线来定位,同时可以混合使用

.grid div:first-child {
  grid-area: r-start 2 / c-start 2 / span 2 / 3;
}

可以对每一个区域进行命名,使用grid-template-areas按照每行为一组进行命名

<style>
  .grid {
    width: 300px;
    height: 300px;
    border: 1px solid silver;
    display: grid;
    grid-template-rows: 60px 1fr 60px;
    grid-template-columns: 60px 1fr;
    grid-template-areas: 'header header''nav main''footer footer';

  }

  .grid div {
    background-color: pink;
    background-clip: content-box;
    padding: 10px;
    border: 1px solid pink;
    box-sizing: border-box;
  }

  .grid div:first-child {
    grid-area: header;
  }
  .grid div:nth-child(2) {
    grid-area: main;
  }
</style>
<div class="grid">
  <div>1</div>
  <div>2</div>
</div>

有相同命名的区域会被合并为一个区域

image-20220630204511481

css 会自动将我们的命名区域的起始行和起始列命名为 【命名-start】结束列命名为【命名-end】,例如上面的 header 的grid-area 的形式为 grid-area: header-start / header-start/ header-end/ header-end。

区域和行列声明可以使用简写模式

grid-template:
‘栅格名称 栅格名称 栅格名称 栅格名称’ 行高
‘栅格名称 栅格名称 栅格名称 栅格名称’ 行高
‘栅格名称 栅格名称 栅格名称 栅格名称’ 行高/列宽 列宽 列宽 列宽;

如果某个区域不需要命名可以使用.作为占位符,例如

.grid {
  grid-template-rows: 60px 1fr 60px;
  grid-template-columns: 60px 1fr;
  grid-template-areas: 'header .''nav main''. footer';
}

栅格流动

如果要去除栅格之的空格可以使用grid-auto-flow来控制栅格的流动,栅格布局默认 row 流动

选项 说明
column 按列排序
row 按行排列
dense 元素使用前面空余栅格

比如

<style>
  .grid {
    width: 300px;
    height: 300px;
    border: 1px solid silver;
    display: grid;
    grid-template-rows: repeat(3, 100px);
    grid-template-columns: repeat(3, 100px);
  }

  .grid div {
    background-color: pink;
    background-clip: content-box;
    padding: 10px;
    border: 1px solid pink;
    box-sizing: border-box;
  }

  .grid div:first-child {
    grid-column: 1/span 2;
  }

  .grid div:nth-child(2) {
    grid-column: 2 / span 1;
  }
</style>
<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
</div>

这个布局下的排列方式如下

image-20220630210858307

将排列方式更换为 column 之后

image-20220630210930709

设置为 row dense 之后

image-20220630211041153

对齐方式

对齐方式是我们经常需要用到的属性,在很多时候我们都需要使用对齐来调整样式

选项 说明 对象
justify-content 所有栅格在容器中的水平对齐方式,容器有额外空间时 栅格容器
align-content 所有栅格在容器中的垂直对齐方式,容器有额外空间时 栅格容器
align-items 栅格内所有元素的垂直排列方式 栅格容器
justify-items 栅格内所有元素的横向排列方式 栅格容器
align-self 元素在栅格中垂直对齐方式 栅格元素
justify-self 元素在栅格中水平对齐方式 栅格元素

justify-content 属性的值如下

说明
start 容器左边
end 容器右边
center 容器中间
stretch 撑满容器
space-between 第一个栅格靠左边,最后一个栅格靠右边,余下元素平均分配空间
space-around 每个元素两侧的间隔相等。所以,栅格之间的间隔比栅格与容器边距的间隔大一倍
space-evenly 栅格间距离完全平均分配

align-content 属性的值如下

说明
start 容器顶边
end 容器底边
center 容器垂直中间
stretch 撑满容器
space-between 第一个栅格靠左边,最后一个栅格靠右边,余下元素平均分配空间
space-around 每个元素两侧的间隔相等。所以,栅格之间的间隔比栅格与容器边距的间隔大一倍
space-evenly 栅格间距离完全平均分配

justify-items 用于控制元素的水平对齐方式,可用的属性值如下

说明
start 元素对齐栅格的左边
end 元素对齐栅格的右边
center 元素对齐栅格的中间
stretch 水平撑满栅格

align-items 用于控制元素的垂直对齐方式,可用的属性值如下

说明
start 元素对齐栅格的顶边
end 元素对齐栅格的底边
center 元素对齐栅格的垂直中间
stretch 垂直撑满栅格

justify-self 与 align-self 控制单个栅格内元素的对齐方式,属性值与 justify-items 和 align-items 是一致的。

place-content 用于控制栅格的对齐方式,语法如下:

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

place-items 控制所有元素的对齐方式,语法如下:

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

place-self 控制单个元素的对齐方式,语法如下:

place-self: <align-self> <justify-self>


前端小白