随着
Igalia 在 Chromium/Blink 以及 Safari/WebKit浏览器实现CSS网格布局的部分工作的完成,我们已经实现了对于定位网格项(positioned
items)的支持。是的,在网格中支持绝对定位。
可能你的第一反应是不希望在网格布局中使用定位的网格项,但是可能在某些使用案例中必须要使用它们。这篇文章主要用来解释定位网格项在网格容器(grid
container)中的特殊性。
实际上,定位网格项跟普通网格项(regular items)相比并没有那么大的区别。当网格容器是定位项的包含块时(例如,在网格容器中使用相对定位
position: relative; ),这些定位网格项在页面的布局与普通网格项基本是相同的。但是,还是有少许的不同:
定位网格项默认不能延伸(stretch)。
它们不能使用隐式网格。 它们不会创建隐式轨道。
使用自动布局功能时,它们不占用单元格。
auto 与网格线(grid lines)相关的时候有特殊的含义。
让我们详细介绍一下这些功能。
定位网格项会收缩到内容的宽高
我们都知道普通网格项默认可以延伸来填充它们的区域。然而,定位网格项并不是这样,类似于定位的普通块级元素,它们会收缩到内容的宽高。
这点很容易理解,但是一个简单的例子能让它更加清楚明了:
<div style="display: grid; position: relative; grid-template-columns: 300px 200px; grid-template-rows: 200px 100px;"> <div style="grid-column: 1 / 3; grid-row: 1 / 3;"></div> <div style="position: absolute; grid-column: 1 / 3; grid-row: 1 / 3;"></div> </div> |
在这个例子中,我们有一个简单的 2x2 的网格。普通网格项和定位网格项都设置了占满整个网格的CSS规则。这定义了这些网格项的_区域_包括第一行和第二行以及第一列和第二列。
普通网格项默认在水平和垂直方向都会延伸,所以它们会占据整个网格区域。然而,定位网格项会产生塌陷,它们的尺寸会根据内容来缩小。
在下面的例子中,我会忽略这个不同点以便能展示每个定位网格项所占据的区域。要实现跟图片一样的结果,你需要将定位网格项的宽高设置为
100% 。
定位网格项和隐式网格(implicit grid)
定位网格项不参与网格的布局,也不会影响到其他元素的放置。
你可以在显式网格(explicit grid)外部放置一个普通网格项,网格为了容纳元素会创建需要的轨道。然而,对于定位网格项来说,你甚至无法参考隐式网格的网格线,它们会被默认为根据
auto 属性来放置。这意味着你在隐式网格中不能放置定位元素。它们由于不参与网格的布局所以无法创建隐式轨道(implicit
tracks)。
让我们通过一个例子来更好的理解这一点:
<div style="display: grid; position: relative; grid-template-columns: 200px 100px; grid-template-rows: 100px 100px; grid-auto-columns: 100px; grid-auto-rows: 100px; width: 300px; height: 200px;"> <div style="position: absolute; grid-area: 4 / 4;"></div> </div> |
这个例子中我们定义了一个 2x2 的网格,但是定位网格项指定的网格区域为 grid-area: 4 /
4; 所以它尝试去找第四行和第四列。然而定位网格项不能创建隐式轨道。所以,它像被设置了 auto 一样进行放置,在这个例子中会占据整个显式网格。auto
对于绝对定位项有特殊的含义,后面我们会进行详细解释。
假设另外一个普通网格项创建隐式轨道的例子:
<div style="display: grid; position: relative; grid-template-columns: 200px 100px; grid-template-rows: 100px 100px; grid-auto-columns: 100px; grid-auto-rows: 100px; width: 500px; height: 400px;"> <div style="grid-area: 1 / 4;"></div> <div style="grid-area: 4 / 1;"></div> <div style="position: absolute; grid-area: 4 / 4;"></div> </div> |
在这个例子中,普通网格项会创建隐式轨道,产生一个 4x4 的网格。这时候定位网格项就可以放置在第四行第四列的位置,即便这些列在隐式网格中。
本文的这部分已经被修改过了,在此感谢@fantasai指出我的错误。
定位网格项和布局算法
再强调一次,定位网格项由于不参与布局算法,所以不会影响其他元素的布局。
所以,如果你有一个定位网格项并且对一些普通网格项使用了自动布局,那么定位网格项会覆盖住普通网格项。这些定位网格项
在自动布局时被完全忽略了。
下面是一个简单的例子来解释这个行为:
<div style="display: grid; position: relative; grid-template-columns: 300px 300px; grid-template-rows: 200px 200px;"> <div style="grid-column: auto; grid-row: auto;"></div> <div style="grid-column: auto; grid-row: auto;"></div> <div style="grid-column: auto; grid-row: auto;"></div> <div style="position: absolute; grid-column: 2 / 3; grid-row: 1 / 2;"></div> </div> |
这里我们又创建了一个 2x2 的网格,它有三个自动放置的的普通网格项以及一个绝对定位网格项。你可以看到,这个定位网格项被放置在第一行第二列,但是在这个单元格中定位网格项的下面还有一个自动放置的普通网格项。这说明网格容器在放置普通网格项的时候并不会考虑定位网格项,会忽略它。
如果所有的子元素都没有进行定位,最后一个元素就会在它默认的位置(第一行第二列),其他自动放置的元素会占据其他单元格,不会产生覆盖。
定位网格项和自动网格线(auto lines)
这可能是定位网格项跟普通网格项相比最大的区别。如果你没有指定网格线,那会被认为设置了 auto 值,
但是 auto 并不会像普通网格项一样被当做 span 1 来处理。对于定位网格项来说auto被认为是内边距(padding)的边缘。
规范介绍了网格线 0 和 -0 的概念,尽管听起来有点奇怪,但是它们确实是很有意义的。 auto 网格线会引用名称为
0 和 -0 的网格线,它们代表了网格容器的内边距边缘。
让我们再用几个例子来解释一下:
<div style="display: grid; position: relative; grid-template-columns: 300px 200px; grid-template-rows: 200px 200px; padding: 50px 100px; width: 500px; height: 400px;"> <div style="position: absolute; grid-column: 1 / auto; grid-row: 2 / auto;"></div> </div> |
现在我们有一个 2x2 的网格容器,它设置了内边距。定位网格项将被放置在第二行第一列,由于设置了
auto 属性,它的区域会延伸到内边距的边缘。
我们甚至可以将定位网格项放置在内边距里面。例如使用 “grid-column: auto / 1;”
,网格项就会被放置在左侧内边距中。
当然,如果网格容器更宽,Content Box还有一些空白区域,那么定位网格项也会占据那些空白区域。例如:
<div style="display: grid; position: relative; grid-template-columns: 300px 200px; grid-template-rows: 200px 200px; padding: 50px 100px; width: 600px; height: 400px;"> <div style="position: absolute; grid-column: 3 / auto; grid-row: 2 / 3;"></div> </div> |
这个例子中网格的列总共宽 500px,但是网格容器的宽度为 600px。这意味着在网格内容区域中有 100px
的空白区域。从这个例子可以看到,这部分区域在定位网格项延伸到内边距边缘的时候也会被占用。
偏移量(Offsets)
当然,你也可以使用偏移量来放置定位网格项(left, right, top 以及 bottom 属性)。
定位网格项会遵循上面的规则创建网格区域,这些偏移量会应用在网格区域内部。
让我们来看另一个例子:
<div style="display: grid; position: relative; grid-template-columns: 300px 200px; grid-template-rows: 200px 200px; padding: 50px 100px; width: 500px; height: 400px;"> <div style="position: absolute; grid-column: 1 / auto; grid-row: 2 / auto; left: 90px; right: 70px; top: 80px; bottom: 60px;"></div> </div> |
还是一个具有内边距的 2x2 的网格容器。定位网格项在它的网格区域中有一些偏移。
总结
我不是很确定对于使用网格布局的Web开发者来说,支持定位元素有多重要。如果你发现某种情况下确实要用到这些的话,请一定要告诉我。我希望这篇文章能帮助你更好地理解它,同时注意到现实生活中可能会用到它们的场景。
好消息是 你已经可以在大多数主流浏览器的最近几个版本中测试以上内容了:Chrome Canary, Safari
Technology Preview 以及 Firefox。我们希望这三个浏览器的实现都是可操作的,但是如果你发现什么问题一定要告诉我们。
还有一件事情:定位网格项对于'对齐'的支持。这一点在所有浏览器都还没有被支持,但是这种行为跟你使用的普通网格项是很相似的。我们将会在今后的几个月里实现它,这是很有希望的。
最后,感谢Bloomberg对于实现在Blink 和 WebKit上支持CSS网格布局所做的贡献。 |