CSS布局(四)

519 阅读12分钟

前言

到目前为止,CSS布局系列的文章已经写了三篇了,前面的三篇主要为到CSS布局的基本概念,CSS的基本布局方式,以及flex布局。这一篇文章是该系列的最后一篇文章,主要讲grid布局和多列布局的相关内容。前文之路:

  • CSS布局(一)
  • CSS布局(二)
  • CSS布局(三) 这篇文章,我们从Flex布局和Grid布局的区别开始聊起,然后具体聊一聊Grid布局的相关概念和属性,最后再聊一聊web中的报纸期刊布局方式,多列布局。

Flex VS Grid

在上一篇文章中,总结了flexbox的相关内容,总结起来,可以得到如下的结论:flexbox定义了一种可调节子元素的显示大小的布局方式,用于实现一维布局时会有很好的灵活性。虽然,可以通过设置flex-wrap属性来实现多行排列,但是它本身并不是用来实现二维布局的,用起来不是很顺手。与之相对应的,Grid布局模型是一种基于二维网格布局的系统。那么问题来了,什么是一维布局,什么又是二维布局呢?我们来进行一个对比:

一维布局

一维布局始终只能沿着坐标系统的一个方向进行布局。就拿flexbox来说,flexbox中的子元素是只能按照一个方向来进行布局的,布局的方向通过flex-direction来进行控制。

  • 将 flex-direction 设置为 row,则flexbox的子元素会沿着x轴方向从左往右进行布局。其布局的方式如图所示: flexbox-row.png
  • 将 flex-direction 设置为 column,则flexbox的子元素会沿着y轴方向从上往下进行布局。其布局方式如图所示: flexbox-column.png

二维布局

对于二维布局而言,则没有主轴和侧轴之分,子元素的排列方式也不是沿着某一条坐标轴排列的。Grid布局就是一种典型的二维布局模型。在Grid模型之中,可以将父元素想象成一个一个的格子,然后子元素则是往格子里面填充。在这种布局方式中,没有主轴和侧轴之分,x轴和y轴的地位是平等的,他们两个坐标轴共同构成了一个网格。 因此,这种布局方式叫做网格(grid)布局。
这种布局有一个好处,就是只用一个gird容器可以放下各种奇奇怪怪的子元素大小组合。如图所示的这种布局方式,如果采用flexbox模型进行布局的话,需要将flex进行分区,flex容器里面再套一个flex容器,这样就显得比较麻烦。然而,如果采用grid布局的话,则只需要一个grid容器,然后将排列规则写好就可以了。 grid布局方式.png

需要注意的一点是,flex布局和grid布局这两种布局方式并没有什么好坏之分,只是他们适用的场合不一样而已。因此,比较好的一个观点就是flex布局和gird布局结合起来,把他们都分别用在合适的地方。这样可以帮助我们实现一个比较好的布局。

Grid 基本概念

在这一部分,我们来聊一聊Grid布局模型的一些基本的概念,这些概念分为以下几组:

  • 网格容器(grid container)/网格项目(grid item)
  • 网格线(grid lines)/网格轨道(grid tracks)
  • 网格单元格(grid cell)
  • 网格区域(grid area)/合并单元格 接下来,我们来看一看这些概念都是怎么形成的。和 flexbox 一样,要想触发 grid 布局方式,需要将父元素的diplay属性声明成grid。这样的声明方式就带来了grid的两个基本概念:网格容器(grid container)和网格项目(grid-item)。 顾名思义,这两个概念跟别代表着容纳该种排列方式的容器和在容器中排列的子元素。
    在触发了 grid 布局之后,接下来要考虑的是这种布局模型的规则问题。正如前面所提到的,grid布局是一种二维的布局,没有主轴和侧轴的概念,x轴和y轴的地位是平等的。这样就导致了,子元素不会单纯的按照哪个坐标轴排列,而是分布在由x轴和y轴构成的一个网格中grid概念-1.png
    如图所示,这些和坐标轴平行的虚拟的直线叫做网格线(grid line)。网格线是用来在水平方向和垂直方向分割网格布局区域的线。无论水平方向还是垂直方向,这些网格线的起点都是从容器的左上角,也就是坐标原点开始的。然后依次往右和往下排列。任意两条网格线之间的区域称为网格轨道(grid tracks)。由四条网格线构成的每个小格子是网格单元格(grid cell),网格单元格是grid布局的基本单位,每个网格项目(grid item)都要填充到单元格里面。

这就是网格布局的基本思路,把网格容器抽象成一个由平行于坐标轴的线分割成的一个一个的小格子,然后将子元素填充到每个小格子中去。
grid的最后两个概念是合并单元格和网格区域。合并单元格就是说将几个网格单元格合并成一个,最后多个单元格放到一起就形成了一个网格区域(grid area).网格区域的一种划分如下图所示: grid概念-2.png

Grid 属性

同flexbox一样,gridbox的属性也包括了作用到grid容器上的属性和作用到grid项目上的属性两个大类。但是由于flexbox和gridbox的排列规则不同,这些属性的具体内容会有很大的区别。在flexbox布局模型中,子元素的排列跟主轴方向有关,所以这些属性分为方向、尺寸、对齐三类;在gridbox布局模型中,子元素的排列跟网格的划分有关,所以这些属性分为网格划分、尺寸、对齐三类。

网格容器(grid container)

正如前面提到的,作用在网格容器上面的属性可以用来控制网格的划分、尺寸、对齐。

  • 网格划分:
    • grid-template -> grid-template-columns || grid-template-rows || grid-template-areas
    • grid -> grid-template-rows || grid-template-rows || grid-template-areas || grid-auto-rows || grid-auto-columns || grid-auto-flow
  • 对齐:
    • place-content -> align-content || justify-content
    • place-item -> align-items || justify-items
  • 尺寸:
    • grid-gap -> grid-row-gap || grid-column-gap

网格划分

对于Grid容器而言,和网格划分相关的属性需要实现的功能是父元素划分成多个 grid-cell 以及控制子元素在容器中的排列顺序。然后,再来看相关的属性:grid-template-rowsgrid-template-columns 是用来控制grid容器划分单元格的;grid-template-areas 是控制grid容器划分区域的,每个区域一般由一个火或者多个单元格组成;grid-auto-flow 是控制容器中子元素的放置顺序的;grid-auto-columnsgrid-auto-rows 是用来控制新增单元格的列宽和行宽的。

这些属性都有几个简写的属性,但是不建议合并属性

划分单元格

grid-template-rows属性定义了每一行的行宽,grid-template-columns属性定义了每一列的列宽。每一行或列的宽度都有对应位置的宽度表示,参数和参数之间用空格隔开,参数的个数代表了将容器划分的行数或者列数。下面的例子定义了一个三行三列的表格,每一个表格的行和列都是100px

#container{
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
}

显示效果如图所示:
grid-ex效果.png
接下来要探讨的一个话题是表示行宽和列高的单位:

  • 绝对单位:表示每个行或者列的绝对宽度
  • 百分比:表示行或者列占grid容器的百分比
  • repeat(): 接受两个参数,第一个参数表示重复的次数,第二个参数表示重复值。其中重复值可以是一个值,也可以是一种重复的模式,比如:“100px 200px 40px”
  • auto-fill: 该参数用在单元格大小是固定的,但是容器大小不固定,并且希望填充行或列的时候
  • fr关键字:是一个相对的单位,表示片段宽度。举个例子:“1fr 2fr”,这样的设置方式就表示将行或者列划分为两个,并且第二列或者第二行的宽度是第一列或者第一行的两倍。
  • minmax():这个函数产生一个长度的范围,表示尺寸在这个范围之中,接受两个参数:分别表示最小值和最大数值
  • auto:表示浏览器自己决定长度 最后,我们可以添加方括号来表示网格线的名字,例如:grid-template-rows: [r1] 100px [r2] 100px [r3] auto [r4];这段代码表示将网格容器划分为三行,其中,网格线的名字是方括号里面的值,网格轨道的宽度为两个放括号之间的值。

划分区域

在grid布局中,可以通过设置grid-template-areas属性来划分区域。该属性的使用方式为

grid-template-areas: 'a b c'
                     'd e f'
                     'g h i';

每个''中包含的元素表示一行,每一行由多个列,列于列之间用空格隔开。这种表达方式类似于矩阵。如果某些区域不需要使用,则需要用.来进行占位,表示该区域不适用。

元素放置顺序

用来控制元素排列顺序的是grid-auto-flow属性,该属性可以是指的参数值有三个:

  • column:元素先按照列排列,排不下了换下一列
  • row:元素先按照行排列,排不下了换下一行
  • dense:这个关键字是用来表示将空间尽可能占满的

新增行宽和列宽

在进行grid布局的时候很有可能遇到的一种情况是所有的空间都被占满了,但是还是没有把元素全部放下。这个时候就需要扩展容器的大小了。grid-auto-rowsgrid-auto-columns就是用来控制新增的行列的大小的。

对齐

关于grid布局方式的对齐问题,需要进行描述的有两种对齐:

  • 第一种是grid容器中的所有内容的对齐方式,用place-content来进行控制 这种方式适用的情况是容器很大,所有的元素所占用的空间很小。如图所示: 容器很大.png
  • 第二种是grid单元格中的对齐方式,用place-item来进行控制 这种方式适用的情况是容器中的元素大小参差不齐的时候,需要将元素进行一个对齐。如图所示: 元素大小不齐.png

至于具体的设置关键字,在flexbox那里已经有比较详细的描述,这里就不再赘述。

尺寸

对于grid布局的尺寸控制,和flexbox一样,专指元素和元素之间个gap。

网格项目(grid item)

对于网格项目而言,只有控制网格项目大小和控制对齐方式的属性。控制网格项目大小的属性通过网格项目占据的单元格大小来控制。其中包括利用网格线控制的和利用网格区域控制的两种方式。

  • 大小:
    • 网格线控制:
      • grid-column -> grid-column-start || grid-column-end
      • grid-row -> grid-row-start || grid-row-end
    • 网格区域控制:grid-area 其中,网格线控制的方式是通过指定起始和结束的网格线来进行元素布局的控制,而网格区域的控制则是和网格容器中定义的网格区域名称相关。举个例子:
.item-1 {
  background: #b03532;
  grid-column: 1 / 3;
  grid-row: 1 / 3; /* 除了网格线的数字,还可以用网格线的名称,以及span关键字来表示网格线的位置*/
}

上述代码表示,将.item-1垂直放到第1个网格线和第3个网格线之间,水平放到第1个网格线和第3个网格线之间。

  • 对齐:place-self -> align-self || justify-self 单个元素对齐相关的属性的使用方法和flexbox中的使用方法相同。

多列布局

多列布局是用来实现类似报纸排版的布局效果的布局方式,多列布局相关的属性包括:

  • columns:集成了column-width和column-count两个属性
  • column-width:定义每列列宽
  • column-count:定义分列列数
  • column-gap:定义列间间距
  • column-rule:定义列边框
  • column-span:定义多列布局子元素跨列效果
  • column-fill:控制每列列高效果

写在后面的话

关于CSS布局的系列文章在此就告一段落了。这一系列的文章讲述了目前为止的几种CSS布局方式,从文档流、浮动定位等基本布局方式,到一维的flex布局,再到最后这篇文章写的Grid和多列布局。这一系列文章算是对自己这一段时间学习的总结吧。各位路过的大佬,喜欢我的文章的,给我点个赞。如果文章有什么地方写的有问题的,还烦请各位能够指出。谢谢大家(^▽^)