CSS:在容器查询中使用子网格的教程

303 阅读9分钟

如果你经常使用CSS,你可能会遇到这样的情况:并排放置的布局在一侧的尺寸发生变化时,会出现中断或错位。几乎每个网页设计师都遇到过这种情况,而且解决起来也很令人沮丧。幸运的是,CSS有一些功能允许你创建网页布局,在其内容发生变化时保持对齐;这些功能被称为子网格和容器查询。

CSS子网格和容器查询是两个可以极大地改善网页布局设计和响应式网页开发的功能。本文将深入研究CSS子网格,提供一个关于无缝使用子网格和容器查询的教程。

什么是CSS子网格?

CSS子网格是CSS生态系统中一个相对较新的功能,被证明是对二级CSS网格网页设计和布局规范的一个重要补充。

你在传统网格容器内构建和调整的元素(子组件)并不直接继承其父组件的行和列。这就造成了将它们与父网格保持一致的困难,因为每个元素都倾向于独立行动。

然后你必须管理两个独立的网格,这可能会变得多余。你可以通过添加subgrid 作为grid-template-rowsgrid-template-columns 属性的值来快速解决这个问题,因为网格子组件现在可以与它们的父组件完美同步。

CSS子网格允许子组件继承其父组件的行和列设置,而不需要维护其网格设置。

考虑一下下面这个嵌套网格系统中的三个卡片:

Cards in a nested grid system

看看当你在中心位置增加卡片的内容时会发生什么:

Nested grid cards increased center content

你可以立即看到,随着内容的增加,标题和页脚的位置会受到影响。

有几种处理这个问题的方法。不过,它们最终都需要你手动管理嵌套网格系统中的各个网格,这在处理较大的代码库时可能会有问题。

子网格现在提供了一个替代性的解决方案,允许行和列在网格系统中保持它们的初始位置,尽管它们的内容有所改变。

从我上面的例子来看,添加subgrid 作为我的卡片的grid-template-rows的值将产生不同的输出:

.card {
  grid-template-rows: subgrid;
}

这就是结果:

subgrid cards

尽管第二张卡片的内容增加了,但标题和页脚元素的位置仍然完美,并与父网格同步。

Subgrid是对CSS网格布局规范的一个重要补充,因为子组件能够继承其父和祖父组件的属性。它在构建嵌套网格系统、完美对齐的表单布局和其他编辑性的网页排列时非常方便。

目前,只有Firefox浏览器支持CSS subgrid,但其他流行的浏览器也不甘落后。你可以参考本指南,深入了解CSS子网格及其功能。

什么是容器查询?

自从媒体查询被引入浏览器后,响应式网页设计向未来迈出了一大步,因为你现在可以为浏览器的视口设计特定的布局。

这很好,但媒体查询在创建更复杂的网页结构时也暴露了一个冗余问题。例如,包裹在包含部分中的组件需要调整它们的主要布局属性(如宽度或高度)以与网页视口的变化保持一致,这就会影响并破坏设计。

为了解决这个问题,要让组件的媒体查询与包含部分保持同步,以确保你的组件在所有视口尺寸上都看起来不错。你可以用容器查询轻松地解决这个问题,因为你现在不是根据视口尺寸来设计元素,而是根据它们的实际属性。容器查询允许任何组件按照指定的容器来响应。

例如,在一个网格系统中,子组件可以与它们的容器对齐,并决定它们的行为和响应性。你可以根据它们在容器中的位置(而不是视口)来修改它们的样式。虽然你仍然可以用响应式网格布局来构造网页,但使用容器查询是响应式网页设计的一种更直接的方法。

容器查询是如何工作的?

关于CSS容器查询,首先要了解的是,虽然 "容器 "是被查询的元素,但容器查询中的规则只影响容器的后代。例如,如果你查询一个mainsection ,或者可能是一个div ,作为你的目标容器,容器查询将允许你定义规则,让其中的元素随着容器大小的变化而变化。

你可以用@container 来创建一个容器查询。它寻找最接近的容器上下文。

.card {
  display: flex;
  flex-direction: column;
}

.container {
  background: #fff;
  container-type: layout inline-size
  container-name: something;
}

@container something (min-width: 450px) {
  .card {
    display: flex;
    flex-direction: row
  }
}

上面的代码是一个关于使用容器查询的说明。它只是指示浏览器,如果容器的宽度至少为450px,则将卡片的flex-direction 列的值改为row

容器查询被指定包含在CSS containment 。有三个属性伴随着它们。

1.container-type

这个属性为一个元素分配了一个查询容器,这样它的子组件就可以查询其布局特征的几个方面。

  • size 为块和内联轴尺寸查询创建一个查询容器。布局、样式和尺寸控制被应用于该元素。
  • inline-size 创建一个查询容器,用于对容器的内联轴进行尺寸查询。该元素的布局、样式和内联尺寸的限制被应用到
  • block-size 创建一个查询容器,用于在容器的块轴上进行尺寸查询。元素的布局、样式和块大小的限制被应用于
  • style 是用于样式查询,并创建一个查询容器
  • state 创建一个查询容器,用于状态查询

2.container-name

一个可选的属性,进一步指定了容器的名称。当我们不想以最近的父级容器为目标时,这个属性就像一个逃生舱口。

考虑一下下面的代码:

.sidebar {
  container-type: inline-size;
  container-name: sidebar;
}

上面的CSS生成了一个具有指定名称的容器(sidebar ),它只包含内联轴上的内容,这意味着内容可以在块轴上任意增长。然后你可以用它的container-name ,像这样查询那个特定的容器:

@container sidebar (min-width: 450px){
  .card {
    display: flex;
    flex-direction: row
  }
}

3.container

这个属性经常被用作速记属性,你可以用它在一条语句中同时设置container-typecontainer-name

容器查询的用例

容器查询适用于高度可重用的组件,其布局取决于可用的容器空间。它们可以在各种情况下使用,或添加到页面上的多个容器中。

其他容器查询的使用情况包括:

  • 可适应的布局
  • 卡片、表单元素、横幅和其他模块化组件
  • CSS调整大小的实验
  • 具有不同功能的移动和桌面分页

大多数浏览器仍然不支持容器查询,但你可以随时在Google Chrome Canary上测试其功能。前往chrome://flags 并启用CSS Container Queries

Enabling css container queries

你也可以在Mozilla Firefox上试验容器查询,方法是进入about:config ,启用layout.css.container-queries

enabling container queries firefox

容器查询目前还处于第一次公开的工作草案中,但这一功能已被证明是有帮助的,并有可能被纳入所有的浏览器版本中。

使用带有容器查询的CSS子网格

CSS子网格和容器查询是两个迷人的CSS功能,我认为它们将改变你对网页布局设计和响应式造型的方法,但我们如何将它们结合起来呢?

假设我们有一个包含三篇文章的栏目,格式如下:

<section class="container">
  <article class="article1">...</article>
  <article class="article2">...</article>
  <article class="article3">...</article>
</section>

现在让我们把这些文章放在一个嵌套的网格系统中,子网格和容器查询可以发挥它们的作用。

/* this creates a container with containment on the inline axis only and gives it an optional name "main" */
html, section {
  container-type: inline-size;
  container-name: main;
}

/* targetting the section's minimum width at "60ch" */
@container main (min-width: 60ch) {
  section {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

/* targetting the section's minimum width at "100ch" */
@container main (min-width: 100ch) {
  article {
    padding: 1rem;
    font-size: 1rem;
    border: 1px solid #000;
    margin: 10px 20px;
    display: grid;
    grid-template-rows: auto 1fr auto;
  }

  /* enabling a more responsive grid layout so elements don't break */
  .article1, .article2 {
    grid-template-columns: subgrid;
  }

  .article3 {
    display: grid;
    grid-column: span 2;
  }
}

/* targetting the section's containment context at a maximum width of "100ch" */
@container main (max-width: 100ch) {
  main {
    display: flex;
    flex-direction: column;
  }
}

从上面的CSS代码来看,我们让前两列在双列网格系统中的空间和第三列一样大,而第三列就在下面。然后我们在文章内部创建了一个子网格,以确保里面的元素是同步的,即使在文章内容增加时也不会中断。

example card grid system

为了使这个系统的响应速度更快,我们不得不以栏目为目标,设置一些容器查询规则,适用于作为其后代的文章。你可能会注意到,我们查询了部分的inline-size 属性,因为我们希望文章(子)组件能够随着部分(容器)的宽度而增长或缩小。

在这种情况下,当部分的宽度达到最大80ch ,我们让文章在列的方向上弯曲。这使得我们的文章不是响应视口的大小,而是响应它们容器的宽度。

下面是结果。

container queries subgrids working together

结论

这篇文章介绍了CSS子网格和容器查询,它们的工作原理和使用案例。我们还尝试了这两个概念,并将它们结合起来,实现了响应式布局。容器查询和CSS子网格目前还处于第一次公开的工作草案中,但它们的功能已经被证明是有帮助的,并有可能被纳入大多数新的浏览器版本中。

我希望这篇文章对你有价值。编码愉快