图解CSS: Grid布局(Part15)

特别声明:如果您喜欢小站的内容,可以点击申请会员进行全站阅读。如果您对付费阅读有任何建议或想法,欢迎发送邮件至: airenliao@gmail.com!或添加QQ:874472854(^_^)

当 CSS Grid 布局在 2017 年最初发布时,设计师和开发人员为二维布局和优化布局系统而设计时感到非常兴奋。 通过前面的学习,我们也领略到了网格布局的魅力,CSS 网格让我们可以轻松地做许多以前做不到的事情。其中一个较大的限制是,嵌套的网格不能参与其父网格的大小调整。这也是一个从一开始就被认为很重要的功能,然而,由于其复杂性,一度曾被废弃的子网格被推迟到 CSS Grid布局模块的 Level 2 中。

一段时间以来,关于subgrid的使用情况、如何实现它的问题有很多讨论,甚至还有一些关于是否需要它的辩论。很多讨论都是围绕着另外两种可以处理许多与subgrid相同问题的方法:嵌套网格display: contents。接下来,我们将花一些篇幅来阐述嵌套网格和subgrid,即我们将了解哪些是相似的,哪些是subgrid与嵌套网格区别?以及阐述在一些非常有效的情况下,子网格是真正需要的,而在另一些情况下,它并不是严格需要的,但会带来一个更简洁的解决方案。

那我们先从嵌套网格开始。

什么是嵌套网格

CSS 中的嵌套网格有点类似于嵌套表格。简单地说,任何网格项目都可以成为一个网格容器,也就是说,只需要在网格项目上显式设置 display 的值为 gridinline-grid 即可实现一个嵌套网格。比如下面这个示例:

<!-- HTML -->
<div class="grid__container">
    <div class="grid__item"></div>
    <div class="grid__item grid__container-subgrid">
        <div class="grid__item"></div>
    </div>
    <div class="grid__item"></div>
</div>

/* CSS */
/* 创建父网格容器 */
.grid__container {
    display: grid;
    grid-template-columns: 1fr 2fr 3fr 2fr 1fr;
    grid-template-rows: 1fr 2fr 2fr 1fr;
    gap: 1rem;
}

/* 创建嵌套网格 */
.grid__container--subgrid {
    grid-column: 2 / 5;
    grid-row: 2 / 4;

    display: grid;
    grid-template-columns: 2fr 3fr 2fr;
    grid-template-rows: repeat(3, 1fr);
    gap: 1rem;
}

上面的示例在 .grid__container 创建了一个 5 x 4 (五列四行)的网格,并且在网格项G,也就是.grid__container--subgrid 创建了一个 3 x 3(三列三行)的网格,并且 .grid__container--subgrid 网格容器同时又是 .grid__ccontainer 网格中的第七个网格项目(网格项目G):

上图中,白色网格线构建的是父网格(.grid__container),红色网格线构建的是子网格(.grid__container--subgrid),这两个网格是相互嵌套的关系。其中 .grid__container--subgrid 网格也被称为嵌套网格。

这是两个完全不同的网格,父网格和嵌套网格都有自己的独立的网格系统,比如网格线编号,网格轨道尺寸等。也就是说,在父网格和嵌套网格中都可以显式使用 grid-template(即其子属性grid-template-columnsgrid-template-rowsgrid-template-areas)或 grid-auto-rowgrid-auto-column。也可以使用grid-columngrid-rowgrid-area等属性在各自网格系统中放置网格项目。

当然,我们也可以采用下面的方式,完全嵌套一个与父网格一模一样的子网格:

.grid__container {
    display: grid;
    grid-template-columns: 1fr 2fr 3fr 2fr 1fr;
    grid-template-rows: 1fr 2fr 2fr 1fr;
    gap: 1rem;
}

/* 创建嵌套网格 */
.grid__container--subgrid {
    grid-column: 2 / 5;
    grid-row: 2 / 4;

    display: inherit;
    grid-template-columns: inherit;
    grid-template-rows: inherit;
    gap: inherit;
}

使用开发者审查工具,你可以看到白色网格(父网格)和红色网格(子网格)都是 5 x 4(五行四列)网格,不同之处只是它们的网格轨道尺寸不同:

如果在父网格的grid-template-columnsgrid-template-rows 显式定义了网格线名称,并且使用 grid-template-areas 定义了网格区域。同样可以使用 inherit 将父网格网格线名称、网格区域名称复制过来:

.grid__container {
    display: grid;
    grid-template-columns:
        [header-start nav-start footer-start] fit-content(100px) [nav-end main-start] 1fr [main-end aside-start] fit-content(100px) [header-end aside-end footer-end];
    grid-template-rows: 
        [header-start] 80px [header-end nav-start main-start aside-start] 1fr [nav-end main-end aside-end footer-start] 60px [footer-end];
    grid-template-areas:
        "header header header"
        "nav    main   aside"
        "footer footer footer";
    gap: 1rem;
}

.grid__container--subgrid {
    display: inherit;
    grid-template-columns: inherit;
    grid-template-rows: inherit;
    grid-template-areas: inherit;
    gap: inherit;
}

header {
    grid-area: header;
}

nav {
    grid-area: nav;
}

main {
    grid-area: main;
}

aside {
    grid-area: aside;
}

footer {
    grid-area: footer;
}

子网格(被嵌套的网格)继承了父网格所有网格系统的相关参数:

从上面的示例中,不难发现嵌套网格布局的缺陷。换句话说,嵌套网格最大的问题是, 嵌套网格是独立于父网格和相互之间的,即 嵌套网格是独立的一个网格,但又是父网格的的一个网格项目。这也意味着嵌套网格不从父网格中获取它们的轨道尺寸,这使得嵌套网格项目与父网格的排列更加困难。我们嵌套网格内所做的更改不会涉及父级容器,因此,在布局时需要考虑两个独立的网格,出错率就更大,维护更难,效率也变得更低。

嵌套网格还存在的一个问题就是它的灵活性,在响应式设计中会产生一个问题,即里面的元素溢出了网格容器元素的边界之外。

什么是子网格(subgrid)

由于嵌套网格布局存在一定的缺陷,同时为了避免嵌套网格给布局带来的不利因素,CSS Grid 布局模块 Level 2 新增了一个 subgrid (子网格)的新功能。 subgridgrid-template-rowsgrid-template-columns 属性的一个值。即:

grid-template-rows: subgrid <line-name-list>?
grid-template-columns: subgrid <line-name-list>?
<line-name-list>      = [ <line-names> | <name-repeat> ]+

grid-template-rowsgrid-template-columns 或两者都显式设置了subgrid的值,嵌套网格将采用其父网格定义的网格轨道。子网格的项目将参与任何与父网格共享的网格轨道的内在尺寸计算。从本质上讲,子网格提供了通过嵌套元素向下传递网格参数的能力,以及将其基于内容信息向上传递到父网格的能力。

如果在subgrid 后面指定了 <line-name-list> 参数的话,将允许对与父网格共享的网格线进行本地命名:如果给出了<line-name-list>,指定的<line-name>(网格线名称)将被分配给子网格的显式网格线,每条一个,从第一条网格线开始,并且多余的网格线名称会被忽略

我们把上面的嵌套网格稍微调整一下,先来感受一下子网格(subgrid)与嵌套网格的差异:

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

.grid__container--subgrid {
    grid-column: 2 / 5;
    grid-row: 2 / 4;

    display: inherit;
    grid-template-columns: subgrid;
    grid-template-rows: subgrid;
    gap: inherit;
}

使用 Firefox 浏览器,查看上面的示例,你将看到下图这样的效果:

.grid__container--subgrid 是一个subgrid(子网格), 将为它所跨越的区域采用网格容器的网格轨道(行和列)。在这个示例中,垂直方向有三列,水平方向有两行(grid-rowgrid-column属性定义)。

.grid__container {
    display: grid;
    grid-template-columns: 1fr 2fr 3fr 2fr 1fr;
    grid-template-rows: 1fr 2fr 2fr 1fr;
    gap: 1rem;
}

.grid__container--nested,
.grid__container--subgrid {
    grid-column: 2 / 5;
    grid-row: 2 / 4;
    gap: inherit;
}

.grid__container--nested {
    display: inherit;
    grid-template-columns: inherit;
剩余80%内容付费后可查看

如需转载,烦请注明出处:https://www.w3cplus.com/css/grid-layout-part-15.html

如果文章中有不对之处,烦请各位大神拍正。如果你觉得这篇文章对你有所帮助,打个赏,让我有更大的动力去创作。(^_^)。看完了?还不过瘾?点击向作者提问!

赏杯咖啡,鼓励他创作更多优质内容!
返回顶部