在众多浏览器刚刚支持 CSS 的时候,我就已经开始使用它了,并且应该算是最早采用 CSS 进行页面布局的开发者之一了。那时候,浏览器之间的兼容性虽然不好,但我仍然热衷于尝试层出不穷的新特性。最近几年在 CSS 领域,我们看到了许多重大进展。其中,web 字体、渐变、阴影和媒体查询已经成为了我们日常工作流的必备工具。
然而,CSS 布局却发展缓慢。开发者们曾经尝试使用 display:table
和 display:inline-block
来布局,用来缓解绝对定位和浮动布局所带来的束缚。然而,这些方法并不标准,因此它们又产生了新的问题。
CSS 布局的未来看起来一片大好。在这篇文章中,我将会介绍 CSS 规范中一些激动人心的布局模块。在未来,我们可以更有效地实现网格布局,更轻松地创建等高列或者均匀分配内容到整个页面。类似 Adobe 的公司往往熟悉布局设计的细节,借助它们的帮助来制定相关规范,我们就能更准确地控制页面在浏览器上的显示方式,同时避免对页面内容的影响。
对于本文中示例,我已经在一个或多个浏览器上进行了测试,当然你也可以继续测试它们。这些布局模块中的一部分可能还处于发展的初期阶段,其具体实现未来可能还会有变化,所以,你也可以就相关问题反馈给制定标准的团队。这是我们的 web,我们应该热衷于参与到制定规范的工作中。
如果你在线上产品中使用本书中的这些技巧,那么你要确保页面对低版本浏览器用户同样是友好的——即使这些低版本浏览器并不支持相关的布局模块。虽然我不想花过多的时间解决浏览器的兼容性问题,但在每一章节的最后,我会给你一些有用的建议和提示。
浏览器前缀
本文所涉及到的大部分属性,都会需要多个浏览器前缀。对于那些规范比较稳定的布局模块,比如多列布局和 flexbox 布局,我会使用 Lea Verou 的 -prefix-free 脚本,从而只需要演示标准属性,也可以实现跨浏览器的兼容性。对于线上产品,我建议你要么为 CSS 添加浏览器前缀,要么使用 CSS 预处理器将浏览器前缀编译到最终的 CSS 文件中。
对于那些非常新的布局模块(只被个别浏览器所支持,相关规范频繁变动的布局模块),我会为其添加所测试浏览器的前缀。在本书出版之时,通过添加特定浏览器前缀,其他浏览器可能也已经支持相关布局模块了。鉴于这些布局模块的实验性特征,所以在不同浏览器上可能会有不同的渲染结果。应该尽可能地为其他浏览器使用前缀并做相关的测试,最后在线上产品中还要加上无前缀的相关属性。
多列布局
CSS3 的多列布局已经风靡多年,然而,由于 IE 的不支持,它并没有获得预期的受欢迎程度。在 IE10 支持这些特性之后,它对于响应式设计就显得更为有用了——非常期待它能流行起来。多列布局模块是本书提到的所有模块中,技术最成熟、浏览器支持度最高的一个模块,所以从它开始讲述 CSS 中的新布局模块是一个不错的选择。
多列布局使内容均匀分散到多列成为可能,它非常类似于报纸中的“内容流动”效果。首先,你需要在文档中选择一个容器(container
),然后声明该容器具有多列布局,那么浏览器就能实现预期的多列效果。如果你为内容(content)指定了列数,浏览器就会自动计算出每一列的宽度,自动适应父级元素的尺寸;如果你指定了每一列的宽度,那么浏览器就会自动计算列数,当父级元素尺寸发生变化,浏览器还可以自动重新计算。
示例:设置 column-width
–查看示例
1 2 3 |
.col-wrapper { column-width: 220px; } |
设置 column-width
属性意味着要求浏览器尽可能多地为容器创建纵列(columns),而开发者指定的宽度则会被视为理想宽度。你可能已经注意到了,当我们指定单列的宽度时,实际上并没有得到预期的宽度。多列之间往往填充了空白(space),这有助于浏览器根据指定的宽度计算最合适的列数。CSS 多列规范中是这样解释的:
“
column-width
的值指定了最理想的单列宽度。实际的单列宽度可能会更宽一些(多列之间填充了空白),或更窄一些(只有可用宽度小于指定宽度时才会出现这种情况)。该属性的指定值必须大于0
。”
因此,当需要设定单列宽度时,你只需指定一个理想宽度即可,因为为了设计的灵活性,实际宽度可能会出现一些差异。
示例:设置 column-count
–查看示例
你也可以使用 column-count
指定所需要的列数,然后让浏览器自行决定单列宽度。
1 2 3 |
.col-wrapper { column-count:3; } |
调节间距
在上面的例子中,你会发现多列之间并没有紧紧相邻:这是因为多列之间存在间距(gap)。在多列布局中,间距是由column-gap
属性控制的。如果将 column-gap
设为 0
,那么多列之间就不会有间距,所有的文字会拥挤在一起。规范中建议浏览器在默认样式中为该属性预设 1em
的宽度。不过,如果让多列的间距保持一致性,那么你应该显式地为该属性设定一个值。
示例:设置 column-gap
属性–查看示例
1 2 3 4 |
.col-wrapper { column-width: 220px; column-gap: 1.5em; } |
美化多列布局
在最新的规范中已经限制了对多列布局的美化。不过,相关的工作草案也提示说:“或许在未来的规范中会添加额外的功能。比如,允许多列中的任意一列设置不同的宽度和背景。”目前来说,你还不能单独地美化多列中的某一列。
虽然没法设置单列的内外边距、宽度和背景色,但是我们可以使用一些规则来隔离多列。实现这一布局效果需要使用column-rule
属性:
column-rule-style
column-rule-width
column-rule-color
这些属性的用法非常类似 border-style
、border-width
和 border-color
,而且也可以使用 column-rule
属性作为一种简写形式:
1 |
column-rule: [width] [style] [color]; |
上面的纵列属性(column rules)将会被应用到 column-gap
上。要想修改纵列两边的空白间距,就需要调整column-gap
的属性值。如果上述纵列属性的值大于可用间距,那么它就会与文本区重叠——但它不会占用任何的空间。
示例:使用 column-rule
–查看示例
单列跨度(span)
如果你想让某一个元素延伸到所有的纵列中,那么可以为该元素添加 column-span
并赋值为 all
。在下面的示例中,我要让 h1
标题可以延伸到所有的纵列上。
示例:强制 h1
延伸到多列–查看示例
1 2 3 4 |
.col-wrapper h1 { column-span: all; padding: 0 0 .5em 0; } |
当前的规范中 column-span
只有两个值:all
和 none
。
多列截断
当使用多列布局的时候,你需要控制多列截断的方式。如果不希望某些元素被截断到新的纵列,或者确保某个元素固定在某一列时,下面的这个属性对你就会很有帮助。
示例:避免在段落内和引用块之前被截断–查看示例
1 2 3 4 5 6 |
.col-wrapper p { break-inside: avoid; } .col-wrapper blockquote { break-before: avoid; } |
印刷和分页媒体类型
规范指出,多列布局内部的元素不应该出现在下一页上。如果阅读时翻到了下一页,然后让用户再返回前一页继续阅读,那么这样的体验就太让人恼火了。
你可以预设分页时段落或者元素内部内容的布局方式——就像控制多列截断一样。属性 avoid-page
和 avoid-column
就可以帮助你实现良好的控制。如果你允许段落进行截断而不允许内容分页,那么对于上面的例子,就可以使用 break-inside: avoid-page
替代 break-inside: avoid;
。
响应式设计
由于多列默认就是响应式的,所以多列布局也有助于实现响应式设计。正如我们所知,虽然可以根据需求设定单列宽度,但本质上浏览器会使用自己的算法,计算出一个用于渲染的宽度。
单列内的图片会被限制在单列范围之内,所以使用 max-width
设置的最大宽度也被局限在单列之内。如果你没有为图片设置 max-width: 100%;
,同时图片的宽度还大于单列宽度,那么浏览器就会自动裁剪掉多余的部分。该规则同样适用于其他宽度大于单列宽度的元素。
示例:图片宽度限制于单列之内–查看示例
一定不要认为多列布局模块只适用于创建类似报纸的版式。下面示例中的多列布局,就包含了一系列的盒模型和图片。
示例:盒模型和图片–查看示例
下面的示例演示浏览器视口较窄时的单列布局,无需编写额外的代码即可实现。
浏览器提示
当我写下这些文字的时候,还只有几个浏览器支持多列布局。因此,有时你需要添加浏览器前缀才能使用这些属性,此外,在有一些情况下某些属性并不会生效。更多更新的浏览器支持信息,可以查看 Can I Use。如果浏览器不支持多列布局,那么它在解析样式表时就会忽略相关属性,因此可以放心使用这些属性。不支持多列布局的浏览器会将内容渲染为单列,这种渲染结果在大多数情况下也是可以接受的——不建议使用腻子脚本模拟多列布局效果。
CSS Flexbox布局
CSS 弹性盒布局模块,通常被称为 flexbox,为我们提供了一种新的布局——flex 布局。设计该布局的初衷是为了简化复杂应用和页面的布局代码。在本节中,我将会着重介绍一些使用 flexbox 解决的布局问题。
均匀排列
在传统的布局设计中,将一组布局元素沿坐标轴均匀排列是件很麻烦的工作。如果使用浮动布局,那么每个浮动元素都必须设置一个宽度,否则就会宽窄不一,此外,往往需要使用 JavaScript,才能让所有的浮动元素均匀排列在同一行上。
Flexbox 极大简化了这一布局过程。在下面的示例中,我使用无序列表创建了一个导航条。
示例:flexbox 简单用法–查看示例
1 2 3 4 5 6 7 8 9 |
<nav class="mainnav"> <ul> <li><a href="">Introductory</a></li> <li><a href="">The First Cat Show</a></li> <li><a href="">Habits</a></li>
<li><a href="">Trained Cats</a></li> <li><a <li><a 然而,CSS 布局却发展缓慢。开发者们曾经尝试使用 CSS 布局的未来看起来一片大好。在这篇文章中,我将会介绍 CSS 规范中一些激动人心的布局模块。在未来,我们可以更有效地实现网格布局,更轻松地创建等高列或者均匀分配内容到整个页面。类似 Adobe 的公司往往熟悉布局设计的细节,借助它们的帮助来制定相关规范,我们就能更准确地控制页面在浏览器上的显示方式,同时避免对页面内容的影响。 对于本文中示例,我已经在一个或多个浏览器上进行了测试,当然你也可以继续测试它们。这些布局模块中的一部分可能还处于发展的初期阶段,其具体实现未来可能还会有变化,所以,你也可以就相关问题反馈给制定标准的团队。这是我们的 web,我们应该热衷于参与到制定规范的工作中。 如果你在线上产品中使用本书中的这些技巧,那么你要确保页面对低版本浏览器用户同样是友好的——即使这些低版本浏览器并不支持相关的布局模块。虽然我不想花过多的时间解决浏览器的兼容性问题,但在每一章节的最后,我会给你一些有用的建议和提示。 浏览器前缀本文所涉及到的大部分属性,都会需要多个浏览器前缀。对于那些规范比较稳定的布局模块,比如多列布局和 flexbox 布局,我会使用 Lea Verou 的 -prefix-free 脚本,从而只需要演示标准属性,也可以实现跨浏览器的兼容性。对于线上产品,我建议你要么为 CSS 添加浏览器前缀,要么使用 CSS 预处理器将浏览器前缀编译到最终的 CSS 文件中。 对于那些非常新的布局模块(只被个别浏览器所支持,相关规范频繁变动的布局模块),我会为其添加所测试浏览器的前缀。在本书出版之时,通过添加特定浏览器前缀,其他浏览器可能也已经支持相关布局模块了。鉴于这些布局模块的实验性特征,所以在不同浏览器上可能会有不同的渲染结果。应该尽可能地为其他浏览器使用前缀并做相关的测试,最后在线上产品中还要加上无前缀的相关属性。 多列布局
多列布局使内容均匀分散到多列成为可能,它非常类似于报纸中的“内容流动”效果。首先,你需要在文档中选择一个容器( 示例:设置
设置
因此,当需要设定单列宽度时,你只需指定一个理想宽度即可,因为为了设计的灵活性,实际宽度可能会出现一些差异。 示例:设置 你也可以使用
调节间距在上面的例子中,你会发现多列之间并没有紧紧相邻:这是因为多列之间存在间距(gap)。在多列布局中,间距是由 示例:设置
美化多列布局在最新的规范中已经限制了对多列布局的美化。不过,相关的工作草案也提示说:“或许在未来的规范中会添加额外的功能。比如,允许多列中的任意一列设置不同的宽度和背景。”目前来说,你还不能单独地美化多列中的某一列。 虽然没法设置单列的内外边距、宽度和背景色,但是我们可以使用一些规则来隔离多列。实现这一布局效果需要使用
这些属性的用法非常类似
上面的纵列属性(column rules)将会被应用到 示例:使用 单列跨度(span)如果你想让某一个元素延伸到所有的纵列中,那么可以为该元素添加 示例:强制
当前的规范中 多列截断当使用多列布局的时候,你需要控制多列截断的方式。如果不希望某些元素被截断到新的纵列,或者确保某个元素固定在某一列时,下面的这个属性对你就会很有帮助。 示例:避免在段落内和引用块之前被截断–查看示例
印刷和分页媒体类型规范指出,多列布局内部的元素不应该出现在下一页上。如果阅读时翻到了下一页,然后让用户再返回前一页继续阅读,那么这样的体验就太让人恼火了。 你可以预设分页时段落或者元素内部内容的布局方式——就像控制多列截断一样。属性 响应式设计由于多列默认就是响应式的,所以多列布局也有助于实现响应式设计。正如我们所知,虽然可以根据需求设定单列宽度,但本质上浏览器会使用自己的算法,计算出一个用于渲染的宽度。 单列内的图片会被限制在单列范围之内,所以使用 示例:图片宽度限制于单列之内–查看示例 一定不要认为多列布局模块只适用于创建类似报纸的版式。下面示例中的多列布局,就包含了一系列的盒模型和图片。 示例:盒模型和图片–查看示例 下面的示例演示浏览器视口较窄时的单列布局,无需编写额外的代码即可实现。 浏览器提示当我写下这些文字的时候,还只有几个浏览器支持多列布局。因此,有时你需要添加浏览器前缀才能使用这些属性,此外,在有一些情况下某些属性并不会生效。更多更新的浏览器支持信息,可以查看 Can I Use。如果浏览器不支持多列布局,那么它在解析样式表时就会忽略相关属性,因此可以放心使用这些属性。不支持多列布局的浏览器会将内容渲染为单列,这种渲染结果在大多数情况下也是可以接受的——不建议使用腻子脚本模拟多列布局效果。 CSS Flexbox布局
均匀排列在传统的布局设计中,将一组布局元素沿坐标轴均匀排列是件很麻烦的工作。如果使用浮动布局,那么每个浮动元素都必须设置一个宽度,否则就会宽窄不一,此外,往往需要使用 JavaScript,才能让所有的浮动元素均匀排列在同一行上。 Flexbox 极大简化了这一布局过程。在下面的示例中,我使用无序列表创建了一个导航条。 示例:flexbox 简单用法–查看示例 |