MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

CSS Grid网格布局的核心概念与优势

2022-03-026.1k 阅读

CSS Grid 网格布局的核心概念

网格容器(Grid Container)

  1. 定义与创建 在 CSS Grid 布局中,首先要确定一个网格容器。这是通过将一个元素的 display 属性设置为 gridinline - grid 来实现的。例如:
.container {
    display: grid;
}

当设置为 grid 时,该元素将作为块级网格容器;设置为 inline - grid 时,该元素将作为内联网格容器。这类似于 display: blockdisplay: inline - block 的区别。块级网格容器会占据一整行,而内联网格容器则会根据其内容宽度自适应,并且可以与其他内联元素共处一行。 2. 网格容器的作用范围 网格容器为其所有直接子元素(网格项)提供了布局环境。这些子元素会自动成为网格布局的一部分,并根据网格容器所定义的规则进行排列。例如:

<div class="container">
    <div class="item1">Item 1</div>
    <div class="item2">Item 2</div>
</div>

这里的 .item1.item2 就是网格容器 .container 的直接子元素,会受到网格布局规则的约束。

网格项(Grid Item)

  1. 网格项的定义 网格项是网格容器的直接子元素。每个网格项都可以独立地在网格中定位和设置样式。比如在上面的例子中,.item1.item2 就是网格项。
  2. 网格项的默认特性
    • 网格项默认会自动填充网格容器所分配的空间。如果没有特别设置网格项的尺寸,它们会根据网格容器的大小和布局规则进行自适应。例如,如果网格容器有固定宽度,且设置了水平方向的网格轨道(稍后会介绍),网格项会均匀地分布在这些轨道上,自动调整自身宽度以适应布局。
    • 网格项在垂直方向上默认会伸展以填满网格容器的高度,除非设置了特定的高度或使用了对齐属性来改变这种默认行为。

网格轨道(Grid Track)

  1. 什么是网格轨道 网格轨道是在网格容器内定义的水平或垂直的空间划分。在水平方向上的网格轨道称为行轨道(row track),在垂直方向上的网格轨道称为列轨道(column track)。通过定义网格轨道,可以精确控制网格项在网格中的位置和大小。
  2. 定义网格轨道
    • 使用 grid - template - rowsgrid - template - columns 属性: 这两个属性分别用于定义行轨道和列轨道。例如,要创建一个包含三行和两列的网格,可以这样写:
.container {
    display: grid;
    grid - template - rows: 100px 200px 150px;
    grid - template - columns: 200px 300px;
}

这里 grid - template - rows 属性的值 100px 200px 150px 分别定义了三行的高度,第一行高度为 100 像素,第二行高度为 200 像素,第三行高度为 150 像素。grid - template - columns 属性的值 200px 300px 定义了两列的宽度,第一列宽度为 200 像素,第二列宽度为 300 像素。 - 使用 fr 单位fr 单位代表弹性分数(fraction),用于按比例分配剩余空间。例如:

.container {
    display: grid;
    grid - template - rows: 1fr 2fr;
    grid - template - columns: 1fr 3fr;
}

在这个例子中,行轨道的总高度会根据网格容器的高度进行分配,第一行占总高度的 1/3,第二行占总高度的 2/3。列轨道同理,第一列占总宽度的 1/4,第二列占总宽度的 3/4。这种方式在创建响应式布局时非常有用,因为它能根据容器大小自动调整网格项的尺寸。 - 重复轨道: 如果有多个相同尺寸的轨道,可以使用 repeat() 函数简化定义。例如,要创建一个包含五列且每列宽度为 150 像素的网格,可以这样写:

.container {
    display: grid;
    grid - template - columns: repeat(5, 150px);
}

repeat() 函数的第一个参数表示重复的次数,第二个参数表示轨道的尺寸。也可以使用多个值进行重复,例如:

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

这会创建一个包含六行的网格,每两行的高度分别为 100 像素和 50 像素。

网格线(Grid Line)

  1. 网格线的概念 网格线是划分网格轨道的边界线。在水平方向上,每一行轨道的上下边缘都有一条网格线;在垂直方向上,每一列轨道的左右边缘都有一条网格线。网格线用于定位网格项,通过指定网格项跨越的网格线,可以精确控制网格项在网格中的位置。
  2. 网格线的编号 网格线从 1 开始编号,在水平方向上,最上面的网格线编号为 1,依次向下递增;在垂直方向上,最左边的网格线编号为 1,依次向右递增。例如,在一个三行两列的网格中,水平方向有 4 条网格线(编号 1 - 4),垂直方向有 3 条网格线(编号 1 - 3)。
  3. 使用网格线定位网格项 可以通过 grid - row - startgrid - row - endgrid - column - startgrid - column - end 属性来指定网格项从哪条网格线开始,到哪条网格线结束。例如:
.item1 {
    grid - row - start: 1;
    grid - row - end: 3;
    grid - column - start: 1;
    grid - column - end: 2;
}

这表示 .item1 这个网格项从第一行网格线开始,到第三行网格线结束,从第一列网格线开始,到第二列网格线结束,即它会跨越两行一列的空间。

网格区域(Grid Area)

  1. 网格区域的定义 网格区域是由四条网格线围成的矩形区域,一个网格区域可以包含一个或多个网格项。网格区域可以通过 grid - template - areas 属性来定义,也可以直接在网格项上通过 grid - area 属性来指定。
  2. 使用 grid - template - areas 定义网格区域 首先在 CSS 中定义区域名称,然后在 grid - template - areas 属性中使用这些名称来布局。例如:
.container {
    display: grid;
    grid - template - rows: 100px 200px;
    grid - template - columns: 150px 250px;
    grid - template - areas:
        "header header"
        "sidebar content";
}
.header {
    grid - area: header;
}
.sidebar {
    grid - area: sidebar;
}
.content {
    grid - area: content;
}

在这个例子中,通过 grid - template - areas 属性定义了三个网格区域:headersidebarcontent。每个区域在定义中通过空格和换行来确定其在网格中的位置。header 区域跨越两列,sidebarcontent 区域分别占据一列。 3. 使用 grid - area 在网格项上指定区域 也可以直接在网格项上使用 grid - area 属性来指定其所在的网格区域。例如:

.item1 {
    grid - area: main - area;
}
.container {
    display: grid;
    grid - area: main - area / 1 / 1 / 3;
}

这里 .item1 被指定到名为 main - area 的网格区域,grid - area 属性的值还可以直接使用网格线编号来定义区域,格式为 区域名称 / 起始行网格线 / 起始列网格线 / 结束行网格线 / 结束列网格线

间隙(Gutters)

  1. 间隙的概念 间隙是指网格轨道之间的空间。在 CSS Grid 中,有两种类型的间隙:行间隙(row - gap)和列间隙(column - gap),也可以使用 gap 属性同时设置行间隙和列间隙。间隙可以使网格项之间产生一定的间隔,使布局更加美观和易读。
  2. 设置间隙
    • 使用 row - gapcolumn - gap 属性
.container {
    display: grid;
    grid - template - rows: repeat(3, 100px);
    grid - template - columns: repeat(3, 150px);
    row - gap: 20px;
    column - gap: 30px;
}

这里设置了行间隙为 20 像素,列间隙为 30 像素,使得每个网格项在水平和垂直方向上都有相应的间隔。 - 使用 gap 属性gap 属性是 row - gapcolumn - gap 的简写形式。例如:

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

如果只提供一个值,如 gap: 20px,则行间隙和列间隙都将设置为 20 像素。如果提供两个值,第一个值表示行间隙,第二个值表示列间隙。

CSS Grid 网格布局的优势

强大的布局控制能力

  1. 精确的定位与尺寸控制
    • 基于网格线和轨道的定位:CSS Grid 允许开发人员通过明确指定网格项跨越的网格线和轨道来精确控制其位置和大小。例如,在一个复杂的页面布局中,可能有一个导航栏需要固定在页面顶部特定的位置,通过网格布局可以轻松实现。假设我们有一个页面布局,包含导航栏(nav)、内容区域(content)和侧边栏(sidebar):
<div class="container">
    <nav class="nav">Navigation</nav>
    <div class="content">Content</div>
    <aside class="sidebar">Sidebar</aside>
</div>
.container {
    display: grid;
    grid - template - rows: 50px 1fr;
    grid - template - columns: 200px 1fr;
}
.nav {
    grid - row - start: 1;
    grid - row - end: 2;
    grid - column - start: 1;
    grid - column - end: 3;
}
.content {
    grid - row - start: 2;
    grid - row - end: 3;
    grid - column - start: 2;
    grid - column - end: 3;
}
.sidebar {
    grid - row - start: 2;
    grid - row - end: 3;
    grid - column - start: 1;
    grid - column - end: 2;
}

在这个例子中,导航栏跨越了第一行的两列,高度为 50 像素;内容区域占据第二行的右侧列,侧边栏占据第二行的左侧列。这种精确的定位在传统的布局方式(如浮动布局或定位布局)中实现起来相对复杂。 - 灵活的尺寸设置:通过 fr 单位和 repeat() 函数,能够轻松创建灵活且比例合理的布局。例如,创建一个响应式的博客页面布局,文章主体和侧边栏的宽度可以根据屏幕大小按比例调整:

.blog - container {
    display: grid;
    grid - template - columns: 3fr 1fr;
    gap: 20px;
}

这里文章主体部分占据三分之二的宽度,侧边栏占据三分之一的宽度,并且两者之间有 20 像素的间隙。当屏幕宽度发生变化时,它们会自动按比例缩放,保持布局的合理性。 2. 复杂布局的简化 - 多列布局:在传统的多列布局中,使用浮动或 display: inline - block 往往需要处理很多与清除浮动、对齐相关的问题。而在 CSS Grid 中,创建多列布局变得非常简单。例如,要创建一个四列布局:

.multi - column - container {
    display: grid;
    grid - template - columns: repeat(4, 1fr);
    gap: 15px;
}

这样就轻松创建了一个包含四列且每列宽度相等、列间距为 15 像素的布局。每个列中的内容可以独立设置样式,无需担心复杂的浮动清除等问题。 - 不规则布局:对于一些不规则的布局,如 Masonry 风格的布局,CSS Grid 也能很好地应对。通过结合网格区域和灵活的轨道定义,可以模拟出类似 Masonry 的布局效果。例如:

.masonry - container {
    display: grid;
    grid - template - columns: repeat(3, 1fr);
    grid - template - rows: auto - fit minmax(200px, auto);
    gap: 10px;
}

这里通过 grid - template - rows: auto - fit minmax(200px, auto) 使得行高度根据内容自动适应,并且最小高度为 200 像素,从而实现类似 Masonry 的布局效果,而不需要使用 JavaScript 来计算和调整元素位置。

响应式设计友好

  1. 自适应网格轨道
    • 基于 fr 单位的自适应:如前文所述,fr 单位能够根据容器大小自动分配空间。在响应式设计中,这一特性非常关键。例如,一个电商产品展示页面,在不同屏幕尺寸下,产品图片和描述区域的比例需要自适应调整:
.product - container {
    display: grid;
    grid - template - columns: 2fr 3fr;
    gap: 20px;
}
@media (max - width: 768px) {
    .product - container {
        grid - template - columns: 1fr;
    }
}

在大屏幕上,产品图片占据两列,描述区域占据三列;当屏幕宽度小于 768 像素时,通过媒体查询将布局调整为一列,图片和描述区域上下排列,这样可以在不同设备上都能提供良好的用户体验。 - 使用 minmax() 函数minmax() 函数可以结合 fr 单位使用,为网格轨道设置最小和最大尺寸。例如:

.layout - container {
    display: grid;
    grid - template - columns: minmax(200px, 3fr) 1fr;
}

这表示第一列的宽度最小为 200 像素,最大可以根据剩余空间按 3fr 的比例分配,使得布局在不同屏幕尺寸下既能保证一定的内容显示空间,又能灵活适应容器大小。 2. 灵活的网格项排列 - 网格项的重新排序:在响应式设计中,有时需要根据屏幕尺寸重新排列网格项的顺序。通过 CSS Grid,可以轻松实现这一点。例如,在一个页面布局中,有标题(header)、文章内容(content)和侧边栏(sidebar),在大屏幕上希望侧边栏在右侧,而在小屏幕上希望侧边栏在内容下方:

<div class="container">
    <header class="header">Header</header>
    <div class="content">Content</div>
    <aside class="sidebar">Sidebar</aside>
</div>
.container {
    display: grid;
    grid - template - rows: auto 1fr;
    grid - template - columns: 1fr 200px;
    gap: 15px;
}
.header {
    grid - row - start: 1;
    grid - row - end: 2;
    grid - column - start: 1;
    grid - column - end: 3;
}
.content {
    grid - row - start: 2;
    grid - row - end: 3;
    grid - column - start: 1;
    grid - column - end: 2;
}
.sidebar {
    grid - row - start: 2;
    grid - row - end: 3;
    grid - column - start: 2;
    grid - column - end: 3;
}
@media (max - width: 768px) {
    .container {
        grid - template - columns: 1fr;
        grid - template - rows: auto 1fr auto;
    }
    .sidebar {
        grid - row - start: 3;
        grid - row - end: 4;
        grid - column - start: 1;
        grid - column - end: 2;
    }
}

在大屏幕上,侧边栏在右侧;在小屏幕上,通过媒体查询改变网格模板,将侧边栏移动到内容下方,实现了响应式的布局调整。

与其他布局方式的兼容性

  1. 与 Flexbox 的结合使用
    • 优势互补:Flexbox 擅长在一维方向(水平或垂直)上对齐和分布元素,而 CSS Grid 则专注于二维布局。两者可以结合使用,发挥各自的优势。例如,在一个复杂的卡片式布局中,卡片内部的元素可以使用 Flexbox 进行对齐,而卡片之间的布局可以使用 CSS Grid。
<div class="grid - container">
    <div class="card">
        <img src="image1.jpg" alt="Image 1">
        <div class="card - content">
            <h3>Card Title</h3>
            <p>Card description here.</p>
        </div>
    </div>
    <div class="card">
        <img src="image2.jpg" alt="Image 2">
        <div class="card - content">
            <h3>Card Title</h3>
            <p>Card description here.</p>
        </div>
    </div>
</div>
.grid - container {
    display: grid;
    grid - template - columns: repeat(3, 1fr);
    gap: 20px;
}
.card {
    display: flex;
    flex - direction: column;
    justify - content: space - between;
}
.card img {
    width: 100%;
    height: auto;
}
.card - content {
    padding: 10px;
}

在这个例子中,grid - container 使用 CSS Grid 布局来排列卡片,而每个 card 内部使用 Flexbox 来垂直排列图片和内容,并使内容在垂直方向上均匀分布。 2. 与传统布局的共存 - 渐进增强:在一些需要兼容旧浏览器的项目中,可以先使用传统的布局方式(如浮动布局)构建基本布局,然后再使用 CSS Grid 进行渐进增强。例如:

<div class="wrapper">
    <div class="sidebar">Sidebar</div>
    <div class="main - content">Main Content</div>
</div>
.wrapper {
    overflow: hidden;
}
.sidebar {
    float: left;
    width: 200px;
}
.main - content {
    float: left;
    width: calc(100% - 200px);
}
@supports (display: grid) {
    .wrapper {
        display: grid;
        grid - template - columns: 200px 1fr;
        gap: 15px;
    }
    .sidebar,
   .main - content {
        float: none;
    }
}

在不支持 CSS Grid 的浏览器中,使用浮动布局来实现侧边栏和主内容区域的布局;在支持 CSS Grid 的浏览器中,通过 @supports 规则检测,然后使用 CSS Grid 进行更灵活和强大的布局,实现了渐进增强的效果。

提高代码的可维护性与可读性

  1. 清晰的布局结构
    • 基于网格区域的布局:使用 grid - template - areasgrid - area 属性,能够以一种直观的方式定义和管理布局。例如,在一个网页的整体布局中,定义页眉(header)、页脚(footer)、导航栏(nav)、主要内容(main)和侧边栏(sidebar):
body {
    display: grid;
    grid - template - rows: auto 1fr auto;
    grid - template - columns: 200px 1fr;
    grid - template - areas:
        "header header"
        "sidebar main"
        "footer footer";
}
header {
    grid - area: header;
}
nav {
    grid - area: nav;
}
main {
    grid - area: main;
}
sidebar {
    grid - area: sidebar;
}
footer {
    grid - area: footer;
}

通过这种方式,布局结构一目了然,开发人员可以很容易地理解和修改布局。如果需要调整某个区域的位置,只需要修改 grid - template - areas 中的定义即可,而不需要在多个元素的样式中查找和修改定位相关的属性。 2. 模块化的布局方式 - 网格容器与网格项的分离:CSS Grid 布局将容器和项的概念明确区分,使得布局代码更具模块化。每个网格容器可以独立定义其布局规则,而网格项只需关注自身的样式和在网格中的位置。例如,在一个包含多个产品列表的电商页面中,每个产品列表可以作为一个网格容器,产品的各个部分(图片、标题、价格等)作为网格项:

<div class="product - list">
    <img src="product1.jpg" alt="Product 1" class="product - img">
    <h3 class="product - title">Product Title</h3>
    <p class="product - price">Price: $19.99</p>
</div>
.product - list {
    display: grid;
    grid - template - rows: auto auto auto;
    grid - template - columns: 1fr;
    gap: 10px;
}
.product - img {
    width: 100%;
    height: auto;
}
.product - title,
.product - price {
    text - align: center;
}

这样每个产品列表的布局都是独立的,便于复用和维护。如果需要修改产品列表的整体布局方式,只需要修改 .product - list 网格容器的样式;如果需要修改某个产品项(如图片或标题)的样式,只需要在对应的网格项样式中进行调整,不会影响其他部分的布局。

性能提升

  1. 减少重排与重绘
    • 稳定的布局结构:CSS Grid 的布局方式相对传统布局更加稳定。传统布局中,元素的浮动、定位等操作可能会导致文档流的频繁改变,从而引发浏览器的重排和重绘。而 CSS Grid 通过明确的网格轨道和网格线定义布局,元素的位置和大小在布局阶段就已经确定,减少了在页面渲染过程中因布局变化而导致的重排和重绘次数。例如,在一个包含大量列表项的页面中,使用浮动布局时,如果其中一个列表项的高度发生变化,可能会影响到后续所有列表项的位置,导致浏览器重新计算布局并重新绘制。而使用 CSS Grid 布局,每个列表项在网格中的位置是固定的,即使某个列表项的内容发生变化,只要不改变其跨越的网格线,就不会影响其他列表项的布局,从而减少了重排和重绘的几率。
  2. 硬件加速
    • 现代浏览器的优化:现代浏览器对 CSS Grid 布局进行了优化,在某些情况下可以利用硬件加速来提高渲染性能。当使用 CSS Grid 创建复杂布局时,浏览器可以将部分渲染任务交给 GPU(图形处理器)处理,从而加快渲染速度。例如,在一个包含动画效果的网格布局中,浏览器可以通过 GPU 加速来更流畅地处理动画,使页面的交互性更好。这是因为 GPU 在处理图形和动画方面具有更高的性能和效率,能够减轻 CPU 的负担,提高整体的页面渲染性能。

综上所述,CSS Grid 网格布局通过其独特的核心概念,为前端开发带来了强大的布局控制能力、良好的响应式设计支持、与其他布局方式的兼容性、更高的代码可维护性与可读性以及性能提升等诸多优势,成为现代前端布局中不可或缺的重要工具。无论是简单的页面布局还是复杂的响应式应用界面,CSS Grid 都能为开发人员提供高效、灵活且优雅的解决方案。