CSS——网格布局(display: grid)之上篇

CSS------网格布局(display: grid)

前面介绍了弹性布局,今天我们介绍一下网格布局。

什么是网格布局

CSS网格布局(CSS Grid Layout)是一种用于创建复杂网页布局的系统,它允许开发者以二维系统行和列 )来控制元素的布局。跟 Flexbox 类似,网格布局也是作用于两级的 DOM 结构。设置为 display: grid 的元素成为一个网格容器(grid container) 。它的子元素则变成网格元素(grid items)。除此之外,另外四个重要的概念如下图所示。

  • 网格线(grid line)------网格线构成了网格的框架。一条网格线可以水平或垂直,并且位于一行或一列的任意一侧。如果指定了 grid-gap 的话,它就位于网格线上。
  • 网格轨道(grid track)------一个网格轨道是两条相邻网格线之间的空间。网格有水平轨道(行)和垂直轨道(列)。
  • 网格单元(grid cell)------网格上的单个空间,水平和垂直的网格轨道交叉重叠的部分。
  • 网格区域(grid area)------网格上的矩形区域,由一个到多个网格单元组成。该区域位于两条垂直网格线和两条水平网格线之间。

如何进行网格布局

设置 display: grid 只是网格布局的第一步,下面我们从 grid-template-columnsgrid-template-rows 属性来逐步深入。

grid-template-columns 与 grid-template-rows 属性

  • grid-template-columns: 1fr 1fr 1fr:"fr"代表分数单位(fraction unit),我们这里可以简单的理解为"在被划分的空间中所占据的份数 ",所以,这个效果就是:创建三个等宽的列。当然,我们可以采取其他单位,如:%、px等。这些单位可以混搭使用,如:gird-template-columns: 300px 1fr 2fr,那么就会先创建300px宽的列,剩下的空间再分别分配1/3、2/3的空间给剩余的两列。不同单位的优先级如下:

    • 百分比(%):首先,浏览器会计算出可用空间的百分比部分。在这个例子中,第二列的宽度是容器宽度的90%。
    • 固定单位(px等):然后,浏览器会为以像素为单位的列分配固定的空间。在这个例子中,第四列的宽度是100px。
    • 分数(fr) :最后,浏览器会将剩余的空间按照分数单位的比例分配给使用 fr 的列。在这个例子中,第一列和第三列分别占据1份和2份。
      示例:
    html 复制代码
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <style>
        /*  
          创建了四个格子,父元素的背景色为黄色,
          其余的为了设置从#111 --> #eee的渐变,并设置了半透明
    	*/
        .main-container {
          width: 1000px;
          background-color: yellow;
        }
    
        .grid-item:nth-child(1) {
          width: 100px;
          padding: 10px;
          border: 1px solid;
          margin-right: 10px;
        }
    
        .grid-container {
          display: grid;
          grid-template-columns: 1fr 95% 100px 2fr;
          grid-template-rows: 1fr;
        }
    
        .grid-item {
          background-color: #999;
        }
    
        div {
          color: red;
          font-size: 1.5rem;
          font-weight: bold;
        }
      </style>
    </head>
    
    <body>
      <main class="main-container">
        <div class="grid-container">
          <div class="grid-item" style="background-color: rgba(17, 17, 17,.5);">项目1</div>
          <div class="grid-item" style="background-color: rgb(85, 85, 85,.5);">项目2</div>
          <div class="grid-item" style="background-color: rgb(153, 153, 153,.5);">项目3</div>
          <div class="grid-item" style="background-color: rgb(238, 238, 238,.5);">项目4</div>
        </div>
      </main>
    </body>
    
    </html>

可以自己复制代码进行尝试,我们在开发者工具中看到:项目1的宽度为100px,项目2的宽度为950px,项目3的宽度为100px,项目4的宽度为16px。

首先看到确实复合前面的规则,但是在明明在分配 fr单位的盒子的宽度之前,父元素的空间就已经占满了,那它们的宽度是如何来的呢?

这里就要解释了:在父元素宽度超出之后,浏览器也知道没有宽度了,所有就不按照 fr 比例进行分配了,而是按照元素的宽度包括内容、内边距,甚至是外边距 )进行分配,比如项目1 指定宽度为 100px,所有分配给他100px,至于项目4 没有指定宽度,其内容只有几个文字,而这些文字的字号是用户代理样式表 (浏览器默认加载的css文件,确保了在用户未设置样式时网页的可读性,其优先级低于作者样式表 ,即我们自己添加的css样式)中的字号 ------16px ,与以往不同的是,这里浏览器会尽量压缩宽度,使文字换行显示min-width,中文为一个汉字的宽度,英文为一个单词的宽度)。如果不做处理的话,这些内容会正常的超出显示(如上图所示)。

grid-template-rows的同理。

网格轨道的创建------repeat()函数

该函数可以用于 CSS Grid 属性 grid-template-columnsgrid-template-rows中。repeat() 函数表示轨道 列表的重复片段,允许以更紧凑的形式写入大量显示重复模式的列或行。如:grid-template-rows: repeat(3, 2fr 1fr):重复"2fr 1fr"这两个模式三次,总共创建6行。
repeat()函数有两个参数:

第一个参数可以是以下三种之一:

  • 数字(比如1,2,3)
  • auto-fit关键字
  • auto-fill关键字

第二个参数可选值包括:

  • 长度值,可使用单位包括fr、px、em、%和ch等等
  • min-content关键字
  • max-content关键字
  • auto关键字
  • minmax()函数,其可以嵌套min()或者max()函数
  • fit-content()函数
  • 命名线
参数取值
  1. <length>

    正整数数值

  2. <percentage>

    百分比长度。

    • 如果是行(rows),则相对于网格容器的宽度,如果是列(columns),则相对于网格容器的高度。
    • 如果网格容器的大小取决于网格元素,那么必须为关键字 auto
    • 如果网格元素的大小超过了网格容器的大小,那么浏览器会对网格元素的大小进行调整
  3. <flex>

    带有 fr 单位的非负尺寸指定轨道的弹性系数。任何被 <flex> 指定大小的轨道会根据其弹性系数按比例分配剩余空间。

  4. 关键字max-content

    首先介绍一下,min-content和max-content尺寸是根据内容来的,min-content是最小内容尺寸,中文的最小内容单位是一个汉字,英文的最小内容单位是单词,因此min-content最终宽度是所有这些最小内容单元最长的那个单元宽度;max-content是最大内容宽度,可以理解为文本内容不换行时候的宽度。不过,min-content和max-content在实际开发的时候是不会相对于字符进行尺寸设定的,而是相对于图片或者内联性质的容器元素,比方说容器宽度不确定同时一行最多显示一个容器(min-content),或者所有元素在一行显示(max-content)。

    css 复制代码
    container{
      grid-template-columns: repeat(3, min-content);
    }

    min-content 关键字可将轨道设置为与其最小内容一样宽或一样高。通常是单词间没有额外空间时的尺寸。如下图:

  5. 关键字min-content

    max-content 关键字的作用基本上与 min-content 相反:它根据网格单元格中最大的内容来确定轨道大小。如下图:

  6. 关键字auto

    auto 关键字的最大值为 max-content,最小值为 min-content(auto 只有在与其他值混合时才会出现上述行为。如果单独使用 repeat(3, auto),其行为就像我们设置 repeat(3, 1fr) 一样)。

    css 复制代码
    .container{
      grid-template-columns: repeat(3, auto 1fr);
    }

    在这里,我们将有六列,每一奇数列的宽度设置为 auto。在下面的演示中,我们可以看到,在有足够空间的情况下,带有"auto"文本的 div 将在max-content时达到最大宽度,而 1fr div 则共享剩余空间。当浏览器变窄时,"auto"列继续变窄,直到达到min-content阈值。

  7. 关键字auto-fill

    css 复制代码
    .container {
        grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
    }

    效果如下,默认宽度很宽的情况下,最后会有匿名的格子:

    随着尺寸变小,列数会跟着动态变化,同时宽度自动填充Grid容器(因为设置了1fr)。弹性变化效果如图:

    当我们使用auto-fill自动填充的时候,repeat()函数是不能和auto一起使用的,例如下面这种写法是无效的:

    css 复制代码
    .container {
        /* 无效 */
        grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)) auto;
    }

    但是可以和长度只和百分比值一起使用,例如:

    css 复制代码
    .container {
        /* 有效,最后一列的宽度始终为 20% */
        grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)) 20%;
    }
  8. 关键字auto-fit

    auto-fit 与 auto-fill 的行为是相似的,区别在于auto-fit 会把空的匿名格子进行折叠合并,而这个合并的 0px 大小格子可以认为具有单个格子轨道大小调整的功能,对了,其两侧的格子过道也会合并。在 auto-fill 自动填充的时候,如果 Grid容器的尺寸特别的宽,则最后会有一些空的格子占位:
    但是auto-fit自动适应的时候,如果Grid容器的尺寸特别的宽,则最后会有一些空的格子会合并成 1个,且宽度是 0。auto-fit 区别示意:

  9. maxmin()函数

    minmax() 函数本身需要两个参数--最小值和最大值,中间用逗号隔开。因此,通过 minmax(),我们可以在灵活的环境中为轨道设置一系列可能的尺寸。

    例如,我们可以将一列设置为 minmax(40px, 100px),这意味着其最小宽度为 40px,最大宽度为 100px。minmax() 的两个参数都可以使用长度值,如 fr、px、em、% 和 ch,以及 min-content、max-content 和 auto。不过,最好至少为一个参数使用长度值,因为关键字不应该同时作为两个参数工作 。

    下面代码设置了五列,每一列的最小宽度为60px,最大宽度为1fr:

    css 复制代码
    article {
      grid-template-columns: repeat(5, minmax(60px, 1fr));
    }

    minmax() 函数的参数也可以是 min() 或 max() 函数。这两个函数都接收两个参数。min()函数应用两个值中较小的值,而 max() 函数应用较大的值。这在响应式环境中非常有用。

    比如说:

    css 复制代码
    article {
      grid-template-columns: repeat(5, minmax(min(60px, 8vw), 1fr));
    }

    上面的代码设置了五列。在宽屏幕浏览器上,五列的间距均为 1fr。在较窄的设备上,列会越来越窄。一旦达到 60px 和 8vw 之间的较低值,就会停止缩小。

  10. fit-content()函数

    只有一个参数,只能为长度或者百分值<length> | <percentage>。

    其底层原理不过多解释,效果可以描述为:"尺寸由内容决定,内容越多尺寸越大,最小为 min-content,最大不超过限定的尺寸"。

    css 复制代码
    .container {
        grid-template-columns: repeat(2, fit-content(100px) 40px) auto;
    }

网格元素的安放

三种语法:带编号的网格线命名的网格线以及命名的网格区域

带编号的网格线

网格线编号从左上角为 1 开始递增,负数则指向从右下角开始的位置,如下图:

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>网格布局</title>
  <style>
    .grid-container {
      display: grid;
      grid-template-columns: repeat(2, 1fr);
      grid-template-rows: repeat(4, 1fr);
      grid-gap: 10px;
    }

    .header {
      grid-column: 1 / 3;
      grid-row: 1 / 2;
    }

    .nav {
      grid-column: 1 / 3;
      grid-row: 2 / 3;
    }

    .main {
      grid-column: 1 / 2;
      grid-row: 3 / 5;
    }

    .sidebar-top {
      grid-column: 2 / 3;
      grid-row: 3 / 4;
    }

    .sidebar-bottom {
      grid-column: 2 / 3;
      grid-row: 4 / 5;
    }

    .grid-container>div {
      background-color: #999;
    }
  </style>
</head>

<body>
  <div class="grid-container">
    <div class="header">Header</div>
    <div class="nav">Nav</div>
    <div class="main">Main</div>
    <div class="sidebar-top">Sidebar Top</div>
    <div class="sidebar-bottom">Sidebar Bottom</div>
  </div>
</body>

</html>

其中,grid-column 属性是 grid-column-startgrid-column-end 的简写,中间使用 "/" 分隔开。

效果如下:

span关键字

作为 grid-columngrid-row属性的值,后面跟正整数,表示在前面属性的方向上占据多少个轨道。由于没有指定是具体的哪几行和哪几列,会根据浏览器的布局算法进行布局(这里先不解释)。

以下表示占据两列一行:

css 复制代码
.item {
  grid-column: span 2;
  grid-row: span 1;
}
命名的网格线

与前面的带编号的命名方式相似,只不过是为那些编号起了名字(就好像学号和姓名一样,虽然有点"倒反天罡"了,但是大致是这样的意思),不过不必要给所有的网格线都起名字,就相当于并不是所有的人都是学生。结合下面的例子:

css 复制代码
 .container {
 display: grid;
 grid-template-columns: [left-start] 2fr
						[left-end right-start] 1fr
						[right-end];
 grid-template-rows: repeat(4, [row] auto);
 grid-gap: 1.5em;
 max-width: 1080px;
 margin: 0 auto;
} 
header,
nav {
 grid-column: left-start / right-end;
 grid-row: span 1;
} 
.main {
 grid-column: left;
 grid-row: row 3 / span 2;
} 
.sidebar-top {
 grid-column: right;
 grid-row: 3 / 4;
} 
.sidebar-bottom {
 grid-column: right;
 grid-row: 4 / 5;
}

我们把纵向的1、2、3号网格线分别命名为 left-start、left-end(right-start)、right-end,这样我们就可以使用 left-start、left-end(right-start)、right-end代替前面的数字,其语义化更好。

这里有个彩蛋:-start-end 后缀作为关键字,定义了两者之间的区域。如果给元素设置 grid-column: left,它就会跨越从 left-start 到 left-end 的区域

此外,我们还在 repeat()函数中使用了这种写法,由于repeat()函数是用来创建轨道的,我们这里 grid-template-rows: repeat(4, [row] auto)auto 的前面添加 [row]就是在为轨道的前面的网格线起名字,所以导致了最后一根网格线是没有名字的,只有编号 "5"。还注意到 grid-row: row 3 / span 2的操作,虽然我们设置了四条名字一样的网格线,但是我们可以通过"名字 第几条同名线"的组合来定位具体是哪根线。

命名网格区域

不用计算或者命名网格线,直接用命名的网格区域将元素定位到网格中。实现这一方法需要借助网格容器的 grid-template-areas 属性和网格元素的 grid-area 属性。

css 复制代码
.container { 
 display: grid; 
 grid-template-areas: "title title"
				      "nav nav" 
					  "main aside1" 
					  "main aside2"; 
 grid-template-columns: 2fr 1fr;
 grid-template-rows: repeat(4, auto);
 grid-gap: 1.5em; 
 max-width: 1080px; 
 margin: 0 auto; 
} 
header { 
 grid-area: title;
} 
nav { 
 grid-area: nav; 
} 
.main { 
 grid-area: main; 
} 
.sidebar-top { 
 grid-area: aside1; 
} 
.sidebar-bottom { 
 grid-area: aside2;
}

grid-template-areas 属性使用了一种 ASCII art 的语法,可以直接在 CSS 中画一个可视化的网格形象。该声明给出了一系列加引号字符串,每一个字符串代表网格的一行,字符串内用空格区分每一列。在这个例子中,第一行完全分配给了网格区域 title,第二行则分配给了 nav。接下来两行的左列分配给了 main,侧边栏的板块分别分配给了 aside1 和 aside2。用 grid-area 属性将每个网格元素放在这些命名区域中。
注意:每个命名的网格区域必须组成一个矩形。不能创造更复杂的形状,比如 L或者 U型。

还可以用句点(.)作为名称,这样便能空出一个网格单元 。比如,以下代码定义了四个网

格区域,中间围绕着一个空的网格单元。

css 复制代码
grid-template-areas: "top top right"
					 "left . right"
					 "left bottom bottom";

结语

这篇文章已经介绍完网格布局的最基础的部分,也请关注下一篇(实战篇)。感谢大家的支持,如有错误,恳请指出,希望与大家共同进步!

相关推荐
Myli_ing13 分钟前
HTML的自动定义倒计时,这个配色存一下
前端·javascript·html
dr李四维30 分钟前
iOS构建版本以及Hbuilder打iOS的ipa包全流程
前端·笔记·ios·产品运营·产品经理·xcode
雯0609~1 小时前
网页F12:缓存的使用(设值、取值、删除)
前端·缓存
℘团子এ1 小时前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
学习前端的小z1 小时前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
彭世瑜1 小时前
ts: TypeScript跳过检查/忽略类型检查
前端·javascript·typescript
FØund4041 小时前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
Backstroke fish1 小时前
Token刷新机制
前端·javascript·vue.js·typescript·vue
小五Five1 小时前
TypeScript项目中Axios的封装
开发语言·前端·javascript
小曲程序1 小时前
vue3 封装request请求
java·前端·typescript·vue