CSS 零基础教程

CSS 显式网格和隐式网格

在 CSS Grid 中,理解显式网格和隐式网格的区别能够让我们掌握布局如何适应不同的内容。

  • 显式网格 (Explicit Grid): 是你使用 grid-template-rowsgrid-template-columns 属性明确定义的网格结构。
  • 隐式网格 (Implicit Grid): 当内容超出了你定义的显式网格时,或者当你将项目放置在显式网格边界之外时,浏览器会自动创建行和列来容纳这些多余的内容。这就是隐式网格。

1. 理解显式网格 (Explicit Grids)

显式网格是你通过 CSS 属性手动规划出的网格结构。它规定了行和列的数量以及它们的大小。

1.1 定义显式网格

你使用 grid-template-rowsgrid-template-columns 来指定网格中行和列的大小及数量。

.grid-container {
  display: grid;
  grid-template-columns: 1fr 2fr 1fr; /* 定义了三列 */
  grid-template-rows: 100px 200px; /* 定义了两行 */
}

在这个例子中,我们创建了一个三列两行的网格。

  • 第一和第三列各占 1fr(剩余空间的一份)。
  • 第二列占 2fr(第一列的两倍空间)。
  • 第一行高 100px,第二行高 200px。

1.2 在显式网格中放置项目

你可以使用 grid-column-startgrid-column-endgrid-row-startgrid-row-end(或它们的简写 grid-columngrid-row)将项目放置在显式网格中。或者,你可以使用 grid-template-areas 来定义命名区域并放置项目。

.item1 {
  grid-column: 1 / 3; /* 从第 1 条列线跨越到第 3 条列线 */
  grid-row: 1; /* 放置在第一行 */
}

这将 .item1 放置在第一行,并让它跨越前两列。

2. 理解隐式网格 (Implicit Grids)

当网格项目的数量多于显式网格中的单元格数量时,或者当你将一个项目放置在显式网格的边界之外时,网格容器会自动创建隐式网格

浏览器会自动生成额外的行和列来容纳这些项目。

2.1 自动创建行和列

当你添加的网格项目超过了你在显式网格中定义的数量时,容器会自动创建额外的行来容纳溢出的内容。默认情况下,这些隐式创建的行高度为 auto

HTML:

<div class="grid-container">
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
  <div>Item 4</div>
  <div>Item 5</div>
  <div>Item 6</div>
</div>

CSS:

.grid-container {
  display: grid;
  grid-template-columns: 1fr 1fr; /* 两列 */
  grid-template-rows: 100px; /* 一行 */
}

在这种情况下,只有前两个项目(Item 1 和 Item 2)会放入显式定义的网格(第一行)中。
Item 3、4、5 和 6 将被放入自动创建的行中。这些行的高度默认为 auto,通常意味着它们的高度将根据其内容自动调整。

2.2 控制隐式行和列

grid-auto-rowsgrid-auto-columns 属性允许你控制这些隐式创建的行和列的大小。

.grid-container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 100px;
  grid-auto-rows: 200px; /* 所有隐式创建的行都将是 200px 高 */
}

现在,任何隐式创建的行的高度都将是 200px,而不是默认的 auto

2.3 grid-auto-flow 属性

grid-auto-flow 属性控制自动放置的项目是如何插入到网格中的。它可以取以下值:

  • row (默认值): 项目逐行放置。如果一行没有足够的空间,就会创建一个新行。
  • column: 项目逐列放置。如果一列没有足够的空间,就会创建一个新列。
  • dense: 尝试填充网格中的空洞,可能会打乱项目的顺序。这对于创建更紧凑的布局很有用,但可能会影响项目的视觉顺序。
.grid-container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: 100px 100px;
  grid-auto-flow: column; /* 项目将逐列放置 */
}

在这个例子中,项目将按列填充。如果你有超过 6 个项目,Grid 会自动创建新的来容纳它们,而不是行。

2.4 隐式网格示例

假设你有一个产品展示网格。你为前几个产品定义了显式网格,但你希望随着更多产品的添加,网格能自动扩展。

HTML:

<div class="product-grid">
  <div class="product">Product 1</div>
  <div class="product">Product 2</div>
  <div class="product">Product 3</div>
  <div class="product">Product 4</div>
  <div class="product">Product 5</div>
  <div class="product">Product 6</div>
  <div class="product">Product 7</div>
  <div class="product">Product 8</div>
</div>

CSS:

.product-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr); /* 三列 */
  grid-template-rows: repeat(2, 200px); /* 两行 */
  grid-auto-rows: 200px; /* 隐式行也将是 200px 高 */
  gap: 10px; /* 在网格项目之间添加间距 */
}
.product {
  background-color: #f0f0f0;
  padding: 20px;
  text-align: center;
}

在这里,我们使用 grid-template-rows 显式定义了前两行。对于超出前六个产品的任何额外产品,它们将被放入隐式行中,多亏了 grid-auto-rows,这些行的高度也将是 200px。

3. 实战案例

让我们探索一些使用显式和隐式网格的实际例子。

3.1 案例 1:仪表盘布局 (Dashboard Layout)

想象你正在构建一个仪表盘,它有一个固定的页头和侧边栏,而主要内容区域需要根据你添加或删除的小部件动态调整。

HTML:

<div class="dashboard">
  <header class="header">页头 (Header)</header>
  <aside class="sidebar">侧边栏 (Sidebar)</aside>
  <main class="main-content">
    <div class="widget">小部件 1</div>
    <div class="widget">小部件 2</div>
    <div class="widget">小部件 3</div>
    <div class="widget">小部件 4</div>
    <div class="widget">小部件 5</div>
  </main>
</div>

CSS:

.dashboard {
  display: grid;
  grid-template-columns: 200px 1fr; /* 侧边栏宽度,剩余空间给内容 */
  grid-template-rows: 60px 1fr; /* 页头高度,剩余空间给内容 */
  grid-template-areas:
    "header header"
    "sidebar main-content";
  height: 100vh; /* 占满整个视口高度 */
}
.header {
  grid-area: header;
  background-color: #333;
  color: white;
  padding: 10px;
}
.sidebar {
  grid-area: sidebar;
  background-color: #eee;
  padding: 10px;
}
.main-content {
  grid-area: main-content;
  padding: 20px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); /* 响应式列 */
  grid-auto-rows: 200px; /* 统一的小部件高度 */
  gap: 10px;
}
.widget {
  background-color: #f0f0f0;
  padding: 20px;
  text-align: center;
}

在这个例子中:

  • .dashboard 容器使用显式网格来定义页头、侧边栏和主要内容区域的结构。
  • .main-content 区域使用了另一个 Grid 布局。它利用 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)) 来创建能自动适应可用空间的响应式列。
  • grid-auto-rows: 200px 确保所有小部件保持一致的高度,即使添加更多小部件(利用隐式网格),布局也不会乱。

3.2 案例 2:图片画廊 (Image Gallery)

考虑构建一个图片画廊,你想以网格布局显示图片。图片的数量可能会变化,所以你需要网格动态适应。

HTML:

<div class="gallery">
  <img src="image1.jpg" alt="Image 1">
  <img src="image2.jpg" alt="Image 2">
  <img src="image3.jpg" alt="Image 3">
  <img src="image4.jpg" alt="Image 4">
  <img src="image5.jpg" alt="Image 5">
  <img src="image6.jpg" alt="Image 6">
</div>

CSS:

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); /* 响应式列 */
  grid-auto-rows: 200px; /* 一致的图片高度 */
  gap: 10px;
}
.gallery img {
  width: 100%;
  height: 100%;
  object-fit: cover; /* 确保图片填满网格单元 */
}

在这里:

  • grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)) 创建了根据屏幕大小调整的响应式列,最小宽度为 250px。
  • grid-auto-rows: 200px 确保所有图片具有一致的高度,即使添加更多图片,依赖隐式网格也能保持整齐。

4. 总结

理解显式网格和隐式网格之间的相互作用是创建灵活且自适应 CSS Grid 布局的基础。

显式网格提供了结构化的基础,而隐式网格确保你的布局能优雅地处理不同数量的内容。通过控制 grid-auto-rowsgrid-auto-columnsgrid-auto-flow 属性,你可以微调隐式网格的行为,创建健壮、响应式的设计。