CSS布局指南
特别声明,本文根据@Rachel Andrew的《Getting Started With CSS Layout》一文整理。
在过去几年中,CSS布局已经发生了巨大的变化,现在我们开发网站的方式也发生了巨大变化。现在我们有需要可选的CSS布局方式来开发我们的网站,这也就要求我们对这些方式能作出正确而双合适的选择。在这篇文章中,将会介绍各种CSS布局的基本使用方式以及使用的目的。
如果你还是CSS方面的新手并且又想了解什么才是最好的布局方式,那么这篇文章正是你所需要的。如果你是一位比较有经验的开发者,想要了解一些关于CSS布局的最新知识,那么这篇文章值得你花费一点时间去阅读。当然,这篇文章并没有涉及CSS布局相关技术的细节,不然,围绕这个主题都可以写一本书了。不过,文章会对各种CSS布局做一个基本的概述,同时会给大家提供相关链接来进一步加强相关技术的学习。
正常文档流
如果你选择没有用任何CSS来改变页面布局的网页,那么HTML元素就会排列在一个**正常流(Normal Flow)**之中。在正常流中,元素盒子(任何一个HTML元素其实就是一个盒子)会基于文档的写作模式一个接一个地排列(根据不同的文档写作模式,排列方向不一样)。这就意味着,如果你的写作模式是水平的(句子是从左到右或从右到左写),正常流会垂直地一个接一个排列页面的块级元素。如果你是在一个垂直方向的写作模式下,句子是垂直方向书写的,那么块级元素会水平方向排列。
正常流是一种最苦的布局:当你的文档应用了CSS、创建了某些CSS布局,这些块就做了一个正常文档流之外的事。
通过页面结构来发挥正常文档流的优势
通过确保书写的页面具有良好的结构(HTML结构),如此一来就可以最大程度复用正常文档流所带来的优势。试想一下,如果浏览器中没有正常流,那么你创建的HTML元素都会堆积在浏览器的右上角。这就意味着,你必须指定所有的HTML元素的布局方式。
有了正常流,哪怕是CSS加载失败了,用户仍然能阅读你的页面内容;同时,一些不使用CSS的工具(例如屏幕阅读器)会按照元素在文档中的位置来读取页面内容。另外从可用性角度来看,这无疑是非常有帮助的,同时也让开发者轻松了一些。如果你的内容顺序和用户预期的阅读顺序一致,那就不需要为了将元素调整到正确的位置而做大量的布局调整。当你继续往下阅读,将会发现,使用新的布局方式是如何让页面布局达到事半功倍的。
因此,在思考如何布局之前,你需要认真思考你的文档结构,以及你希望用户以何种顺序来阅读文档中的内容。
脱离正常文档流
一旦页面有一个良好的结构,你就需要去决定如何利用它并将它变为我们需要的布局结构。这会涉及到脱离正常文档流(后续会详细阐述这部分)。我们有许多布局的“神器”可用,其中第一个要介绍的就是float
,它是一个描述什么是脱离正常文档流的非常好的例子。
扩展阅读
浮动
浮动被用来将元素盒子向左或向右移动,同时让内容环绕其展示。
要让一个元素进行浮动,需要给该元素的flaot
属性设置为left
或right
。float
的默认值为none
。
.item {
float: left
}
值得注意的是,当你使某个元素浮动并让文字环绕它时,内容的行框(Line Box)被缩短。如果你让一个元素浮动,同时为紧跟着的包含文本的元素设置一个背景颜色,你会发现背景色会出在浮动元素下方。
如果想要在浮动元素和环绕的文本之间有一定的间距,需要给浮动元素设置margin
。在文本元素上设置margin
只会让其相对于容器缩进。例如在下面这个例子中,你就需要为左侧浮动的图片设置右边距和下边距。
清除浮动
一旦对一个元素进行了浮动,所有接下来的元素都会环绕它,直到内容处理它下方且开始应用正常文档流。如果想要避免这种情形,可以手动清除浮动。
如果不想要在某个元素受到其之前的浮动元素影响时,可以为其添加clear
属性。left
值表示清除左边的浮动,right
值表示清除右浮动,both
值表示清除左右两边的浮动。
.clear {
clear: both;
}
如果希望元素在浮动元素之后开始排列,那么上面的代码可以达到你的需求。如果你发现在容器内有一个浮动元素,同时容器内文本内容过短时,就会出现问题。文本盒子会被绘制在浮动元素下,然后接下来的部分会以正常流方式绘制在其后。
为了避免这种情况,我们需要为容器中某个元素应用clear
属性。我们可以在容器中最后添加一个空元素并设置clear
属性。但是在某些情况之下可能无法使用这种方式(例如一些CMS系统生成的页面,HTML结构是很难重构)。因此,最常见的清除浮动的方案是:在容器内添加一个CSS伪元素,并将其clear
的值设置为both
。
块级格式化上下文
清除浮动的另一个方法是在容器内创建BFC(块格式化上下文,Block Formatting Context)。一个BFC元素完全包裹住了它内部的所有元素,包括内部的浮动元素,保证浮动元素不会超出其底部。创建BFC方式有很多种,其中最常见的方法是给其overflow
属性设置为visible
之外的值。
.container {
overflow: auto;
}
像上面这样使用overflow
,一般情况下是有效的,可以清除浮动。但是在某些情况下,可能会裁掉一些box-shadow
或是出现滚动条(事实上你并不想滚动条出现)。同时,它在样式表中看起来也有点混乱:设置overflow
其实是想要滚动条的出现,而此处却仅仅是用来清除浮动。那么设置overflow
到底是想要滚动条出现,还是清除浮动呢?
为了使用清除浮动的意图更加直观,并且避免BFC的负面影响,可以使用display
的flow-root
来清除浮动。display: flow-root
做的唯一的一件事就是去创建BFC,因此可以避免其他创建BFC方法带来的副作用。
.container {
display: flow-root;
}
浮动的一些遗留用法
在新的布局方式出现以前,float
经常用来创建多列布局。我们会给一系列元素设置width
并且将它们一个接一个的进行浮动。通过为浮动元素设置一些精细的百分比大小可以创建类似网格的效果。
我不建议在当下仍然过渡的使用浮动来布局。但是,在现有的网站中,这种布局方式仍然会存在许多年。因此,当你碰到一个页面到处是float
的时候,可以确定它就是用的浮动布局。
扩展阅读
- CSS Page Floats
- The Clearfix: Force an Element To Self-Clear its Children
- float
- clear
- Understanding CSS Layout And The Block Formatting Context
- Clearfix: A Lesson in Web Development Evolution
- CSS Floats 101
- BFC
- Float
- flow-root
定位
想要把一个元素脱离正常文档流或者改变其在正常文档流中的位置,可以使用CSS的position
属性。在正常文档流中,元素的position
的值为static
(也是position
的默认值)。在块级维度上元素会一个接一个排列下去,当你滚动页面时,元素也会随着滚动。
当改变元素position
属性时,通常也会设置一些偏移量来使元素相对于参照物进行一定的移动。不同的position
值会产生不同的参照物。
相对定位
如果一个元素设置了position
属性的值为relative
,那么它偏移的参照位是其自身原先在正常文档流中的位置。可以使用top
、right
、bottom
和left
属性将元素相对其正常文档流位置进行移动。
.item {
position: relative;
bottom: 50px;
}
请注意,页面上的其他元素并不会因该元素的位置变化而受到影响。该元素在正常文档流中的位置会被保留,因此你需要自己去处理一些元素内容覆盖的情况。
绝对定位
元素的position
属性值为absolute
可以将其完全脱离正常文档流。其原本占据的空间也会被移除。该元素定位会相对于视窗容器,除非其某个祖先元素的position
值设置了非static
。
因此,当你为某个元素设置position: absolute
时,首先发生的变化是该元素会定位在视窗的左上角。你可以通过top
、right
、bottom
和left
属性设置偏移量,将元素移动到你想要的位置。
.item {
position: absolute;
top: 20px;
right: 20px;
}
通常情况下,你并不希望元素相对于视窗进行定位,而是相对于容器元素。在这种情况下,需要为容器元素设置一个除了默认值static
之外的其他值。
由于给元素设置position:relative
并不会将其从正常文档流中移除,所以一般情况之下是一个很好的选择。给你想要相对的容器元素设置position:relative
,就可以让绝对定位的元素相对其进行偏移。
固定定位
大多数情况下,position:fixed
的元素会相对于视窗定位,并且会脱离正常文档流,同样也不会保留该元素所点点据的空间。当页面滚动时,固定的元素会留在相对于视窗的位置,而其他正常文档流中的内容则和往常一样滚动。
.item {
position: fixed;
top: 20px;
left: 100px;
}
当你想要一个固定导航栏一直停留在屏幕上时,这种做法非常有效。和其他position
值(除static
之外)一样,也可能会造成一些元素被遮盖,需要小心保证页面内容的可读而不会被固定元素遮挡。
如果需要使一个固定元素不是相对于视窗进行定位,那么需要为容器元素设置transform
、perspective
或filter
三个属性之一(不能取其默认值none
)。这样固定的元素就会相对于该块元素偏移,而不是相对于视窗。
黏贴定位(Sticky)
设置position: sticky
会让元素在页面滚动时如同在正常流中,但当其滚动到相对于视口的某个特定位置时就会固定在屏幕上,如同fixed
一般。这个属性值是position
属性的一个新值,在浏览器兼容性上会差一些,但在不兼容的浏览器中会被忽略并会退到正常的滚动情况。
.item {
position: sticky;
top: 0;
}
下面的代码展示了如何创建一个非常流行导航栏效果:导航栏会随着页面滚动,而当导航栏滚动到页面顶部时则会固定在顶部位置。
扩展阅读
- CSS Positioned Layout Module Level 3
- Positioning
position: sticky;
- Understanding and Using CSS Positions
- CSS Positioning 101
- 十步图解CSS的
position
- HTML和CSS高级指南之二:定位详解
- 你对Position的了解程度有多少?
Flex布局
Flexbox布局是一种用于一维布局而设计的布局方法。一维的意思是你希望内容是按照行或者列来布局。你可以在元素上将display
设置为flex
值,把该元素为变弹性布局。
.container {
display: flex;
}
该容器的直接子元素会变为弹性项(Flex Item),并按行排列。
Flexbox的轴
在上面的示例中,弹性项在行内是从起始位置开始排列,而不是说它们是左对齐。这些元素会按行排列是因为flex-direction
的默认值为row
,row
代表了文本的行文方向。由于我们的工作环境是英文,一种自左向右的语言,行的开始位置就在左边,因此我们的弹性项也是从左边开始的。因此,flex-direction
的值被定义为Flexbox的主轴(Main Axis)。
交叉轴(Cross Axis)则是和主轴相互垂直的一条Flexbox轴。如果flex-direction
是row
,并且弹性项是按照内方向排列的,那么交叉轴就是块级元素的排列方向。如果flex-direction
是column
,那么弹性项就会以块级元素排列的方向排列,然后交叉轴就会变为row
。
如果你习惯于从主轴与交叉轴的角度来使用Flexbox盒子,那么一切会变得非常简单。
方向和顺序
Flexbox允许我们通过flex-direction
属性设置为row-reverse
或column-reverse
值来改变主轴上弹性荐的方向。
当然,也可以通过order
属性来改变某一个弹性项的顺序。但是要特别注意,这可能会给那些通过键盘(而非鼠标或触屏)访问你的网站的用户带来一些麻烦,因为tab
的顺序是页面内元素在源码中的顺序而非显示顺序。你可以阅读之后的“显示和文档顺序”部分来了解更多相关内容。
flex属性
flex
的属性是用来控制弹性项在主轴上空间大小的。他是下面三个属性的简写方式:
flex-grow
flex-shrink
flex-basis
简写的flex
属性会有三个值,第一个值是flex-grow
,第二个是flex-shrink
,第三个是flex-basis
。
.item {
flex: 1 1 200px;
}
flex-basis
会为弹性项设置未拉伸和压缩时的初始大小。在上面的例子中,大小是200px
,因此我们会给每个项200px
的空间大小。但是大多数情况下容器元素大小不会正好被分为许多200px
大小的项,而是可能有一些不足或剩余空间。flex-grow
和flow-shrink
属性允许我们在容器大小不足或有空余时控制各个弹性项的大小。
如果flex-grow
的值是任意的正数,那么弹性项会被允许拉伸来占据更多的空间。因此,在上面的例子中,当各项被设为200px
后,所有多余的空间会被每个弹性项平分并填满。
如果flex-shrink
的值为任意的正数,那么当弹性项被设置了flex-basis
后,元素溢出容器时会进行收缩。在上面这个CSS的例子中,如果容器空间不足,每个弹性项会等比例缩放以适应容器的大小。
flex-grow
和flex-shrink
的值可以是任意的正数。一个具有较大flex-grow
值的弹性项会在容器有剩余空间时拉伸更大的比例;而一个具有更大flex-shrink
值的项则会在容器空间不足时被压缩的更多。
理解这些属性是理解如何使用弹性布局的关键,下面列出的一些资源会帮助我们进一步学习其中的细节。当你需要在容器的一个维度上拉伸或者压缩一些元素时,你可以考虑使用弹性盒子模型。如果你发现你正尝试在行和列两个维度上排列你的内容,你需要的是网格模型(grid),这时弹性盒子模型很可能不是最合适的工具了。
扩展阅读
- CSS Flexible Box Layout Module Level 1
- A Complete Guide to Flexbox
- 弹性盒子
- The Complete CSS Flex Box Tutorial
- The Difference Between Width and Flex Basis
- Understanding Flexbox: Everything you need to know
- Flexbox教程 @w3cplus
Grid布局
CSS Grid布局是一种用来进行二维布局的技术。二维意味着你希望按照行和列来排布你的内容。和Flexbox类似,Grid布局也需要设置一个display
值。你可以为容器元素设置display: grid
,并且使用grid-template-columns
和grid-template-rows
属性来控制网格中的行与列。
.container {
display: grid;
grid-template-columns: 200px 200px 200px;
grid-template-rows: 200px 200px;
}
上面这段CSS会创建一个行列元素大小固定的网格。不过这也许并不是你希望的。默认值为auto
,你可以认为这代表了“让格子尽可能的大”。如果你每没有指定行的大小,所有添加进来的行内容大小都会被置为auto
。一种常用的模式是为网格制定列宽度,但是允许网格按需添加行。
你可以使用任意的长度单位或时百分比来设置行与列,同时你可以使用为网格系统所创造的新的单位——fr
。fr
是一种弹性单位,它可以指定网格容器内的空间被如何划分。
网格会替你计算与分配空间,你不需要去计算元素的百分比去适应容器大小。在下面这个例子中,我们使用fr
来创建网格的列,这使得网格的列可以自适应。同时我们还使用了grid-gap
来保证元素间的间距(关于网格内元素与的间距会在“对齐”这一部分详细介绍)。
这个就像Flexbox布局中的flex-grow
或flex-shrink
一样,fr
会根根Grid容器的空间给Grid项目分配可用空间。如果fr
的值较大,这意味着对应的网格轨道可以获得更多可用空间。你也可以将fr
和固定长度混合在一起使用。在计算fr
之前,长度所需的空间将从可用空间中减去。
网格术语
网格系统总是有两个轴:行内轴(Inline Axis)表示页面中文字的文字排列的方向,块轴(Block Axis)表示页面中块级元素的排列方向。
一个被设置为display: grid
的元素就是所谓的网格容器。在网格容器中会有网格线(Grid Line),网格线就是你在指定grid-template-columns
和grid-template-rows
时网格中行列所生成的。网格中的最小单位(也就是被四条网格线截取生成的区域)被成为网格单元格(Grid Cell),进一步的,由若干个单元格组成的矩形区域被成为网格区域(Grid Area)。
上图中的虚线是网格线
两条网格线之间的区域是网格轨道(网格的行或列)
网格单元格和网格区域
网格的自动排列规则
一旦你创建了网格,那么网格容器的直接子元素就会开始将它们自己一个一个地放置在网格的单元格中。子元素的放置是依据网格的自动排列规则。这些规则确保了网格内元素是被安排在各个空的单元格中,而不会彼此遮盖。
网格中任何没有被进行定位的直接子元素都会根据自动排列规则进行放置。在下面这个列子中,我让每三个元素中的第一个占据两行,但仍然从起始行开始去自动排列。
基于行或列的定位
定位网格元素最简单的方式是使用基于行或列网格的定位方法,只需告诉浏览器从哪一排到哪一排来进行合并。例如,如果你需要一个2 x 2
的网格区域,你可以将指定元素从第一行开始到第三行、从第一列开始到第三列,这样就可以覆盖到四个单元格。
.item {
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 1;
grid-row-end: 3;
}
这些属性可以用缩写来表示:grid-column
和grid-row
,其中起一个值代表起始值,第二个值代表结束值。
.item {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
你也可以让网格项占据同一个单元格。支持一些内容间会覆盖的设计。网格项会像通常网页中的元素那样叠起来,在html
源码中下面的网格项会叠在其他元素上面。你仍然可以用z-index
来控制它的堆叠顺序。
通过命名区域来定位元素
你可以通过命名网格区域来定位网格中的元素。要是用这种方式,你需要给每个元素一个名字,然后通过grid-template-areas
属性的值来描述布局方式。
.item1 {
grid-area: a;
}
.item2 {
grid-area: b;
}
.item3 {
grid-area: c;
}
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-areas:
"a a b b"
"a a c c";
}
使用这种方式有几个需要注意的点。如果你想要合并一些单元格作为你的网格项,你需要重复元素的名字。网格区域需要能形成一个完整的矩形 —— 每个单元格都需要被填入一个值。如果你想要空出某些单元格,那就需要使用.
这个值。例如在下面的CSS里我将最右下角的单元格留空。
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-areas:
"a a b b"
"a a c .";
}
你也可以通过下面这个Demo的代码来看看实际的布局效果。
这篇文章只包括了CSS Grid布局的一些初级内容,其中还有非常多的内容值得学习,下面的一些资料可以帮助你进一步学习。一些组件或整个页面的布局都可以使用网格。如果你需要在两个维度进行布局,网格布局是一个不错的选择 —— 不论需要布局的区域的大小。
扩展阅读
- CSS Grid Layout Module Level 2
- CSS Grid Layout
- Grid by Example
- Layout Land
- A Complete Guide to Grid
- Learn CSS Grid
- Best Practices With CSS Grid Layout
- Styling Empty Cells With Generated Content And CSS Grid Layout
- Using CSS Grid: Supporting Browsers Without Grid
- CSS Grid Gotchas And Stumbling Blocks
- Naming Things In CSS Grid Layout
- Awesome CSS Grid
- Grid Layout tutorial
- CSS Grid Layout Collection from Codepen
显示顺序 vs 文档顺序
在文章的最开始,我建议你以从上到下的阅读顺序来组织你的文档顺序,这样会有助于可读性和CSS的布局方式。从我们关于Flexbox和CSS Grid 布局的简短介绍来看,你可能发现用这些布局方法可能会极大地改变页面元素在文档中展示的顺序。这可能会导致一个隐含的问题。
在一些非可视化的应用场景中,浏览器会遵循文档源码来进行使用。因此,屏幕阅读器会读取文档的顺序,此外使用键盘tab
键来浏览的用户访问文档的顺序是基于源码的顺序,而不是元素展示的顺序。许多屏幕阅读器的用户并非完全失明,他们可能在使用屏幕阅读器的同时也能够看到这些元素在文档的哪个部分。在这些情况下,当与源码进行对比时,这种混乱的页面展现可能会令人充满迷惑。
当你改变了元素在文档中原来的顺序时,一定确保知道自己在做什么。如果你发现你自己正在CSS中重新排序你的元素,你应该去回头看看是否要重新组织你的页面元素。你可以通过使用tab
访问来测试一下你的页面。
扩展阅读
- CSS Grid Layout and Accessibility
- HTML Source Order vs CSS Display Order
- Flexbox And The Keyboard Navigation Disconnect
- The Responsive Order Conflict For Keyboard Focus
- A Few Different CSS Methods for Changing Display Order
盒模型的生成
你写在网页里的任何东西都会生成一个盒子(HTML每一个元素都是个盒子),这篇文章讨论的所有东西其实都是如何能够使用CSS来按照你的设计布局这些盒子。然而,在某些情况下,你可能根本不想创建一个盒子。display
属性有两个值会帮你处理这种情况。
不生成盒子或内容(display: none)
如果你希望元素以及它所有的内容(包括所有子元素)都不会生成,你可以使用display: none
。这样元素就不会被展示,并且不会保留其本该占有的空间。
.item {
display: none;
}
不生成该元素,但是生成其所有子元素(display: contents
)
display: content
是display
的一个新的属性值。为一个元素应用display: content
属性会导致其自身的盒子不生成但所有的子元素都会照常生成。这有什么用呢?试想一下,如果你希望一个弹性布局或网格布局中的非直接子元素能应用这些布局,这就会非常有用。
在下面这个例子里,第一个弹性项包含了两个子元素,由于它被设为display: contents
,它的盒子不会生成并且它的两个子元素会成为弹性项,并被当作弹性盒子容器的直接子元素来布局。
扩展阅读
- Box model
- CSS Display Module Level 3
- 为什么是display:contents而不是CSS Grid的subgrid
- Vanishing Boxes With display: contents
- How display: contents; Works
对齐方式
直到现在,对齐在Web上一直是一个棘手的问题,并且能够使用的方法也非常有限。随着CSS盒模型对齐的出现,这一切都发生了变化。你将会使用它来控制Grid容器与Flexbox容器中的对齐。未来其他的各种布局方法都会应用这些对齐属性。盒模型对齐规范中的一系列详细属性如下:
justify-content
align-content
place-content
justify-items
align-items
place-items
justify-self
align-self
place-self
row-gap
column-gap
gap
由于不同的布局模型有不同的特性,因此用于不同布局模型的对齐属性会有一些表现上的差异。让我们来看看在一些简单的网格与弹性布局中对齐是如何工作的。
align-items
和justify-items
属性相对是align-self
和justify-self
属性的一种批量形式。这些属性会控制与元素在其网格区域中的对齐情况。
align-content
和justify-content
属性则会对网格中的行或列进行对齐控制(网格容器中需要在排列完行或列元素后有多余的空间)。
在Flexbox 布局中,align-items
和align-self
用来解决交叉轴上的对齐问题,而justify-content
则用于解决主轴上空间的分配。
在交叉轴上,把弹性行(Flex Line)和额外空间包裹在Flexbox容器中之后,你就可以使用align-content
了。
下面的一些链接更细节地讨论了各类布局方法中的盒模型对齐。花些时间去理解对齐的工作原理是非常值得的,它对理解弹性盒子、网格布局以及未来的一些布局方法都会很有帮助。
行或列的间隔
一个多栏布局具有column-gap
属性,到目前位置,网格布局具有grid-column-gap
、grid-row-gap
和grid-grid
。这些现在都被从grid
标准中删除而被添加进盒模型对齐中了。与此同时,grid-
的前缀属性被重命名为column-gap
、row-gap
和gap
。浏览器会将带有前缀的属性换为新的重命名属性,所以如果你在目前的代码中使用兼容性更好的老名字也不用担心。
重命名意味着这些属性也能被应用于其他布局方法,一个明显的备选就是弹性盒子。虽然目前没有浏览器支持盒子模型中的gap
属性,但是在未来我们应该可以使用column-gap
和row-gap
来创建弹性项目元素间的间距。
扩展阅读
- CSS Box Alignment Module Level 3
- CSS Box Alignment
- Box Alignment in Flexbox
- Box Alignment in CSS Grid Layout
- The New Layout Standard For The Web: CSS Grid, Flexbox And Box Alignment
- Box Alignment Cheatsheet
- CSS Grid and The Box Alignment Module
- Grid, Flexbox, Box Alignment: Our New System for Layout
多列布局
多列布局是一种支持创建多列的布局类型,如同报纸上那样。每一块都被分割成列,你会按照块方向在列中往下读然后会在回到下一列的顶部。然而用这种方式阅读在网页内容中并不总是有效,因为人们并不想去让滚动条滚动来、滚动去地去阅读。当需要展示少部分内容、折叠一组复选框或者其他一些小的UI组件时会非常有用。
当展示一组高度不同的卡片或产品时多列布局也非常有用。
设置列的宽度
要设置一个最优的列宽,并通知浏览器依此宽度展示尽可能多的列可以使用下面的CSS:
.container {
column-width: 300px;
}
这会创建尽可能多的300px
宽的列,所有剩下的空间会被所有列共享。因此,除非空间被划分为300px
时没有剩余,否则你的列会比300px
稍多一些。
设置列的数目
除了设置宽度,你可以使用column-count
来设置列的数目。在这种情况下,浏览器会将空间均分给你需要的数目的列。
.container {
column-count: 3;
}
如果你同时添加了column-width
和column-count
,那么column-count
属性会作为一个最大值限制。在下面的代码里,列会被添加直到达到三个,此时任何额外的空间都会被分给三列,即使空间足够成为一个额外的新列。
.container {
column-width: 300px;
column-count: 3;
}
间距和列规则
你无法为单个列盒子添加margin
和padding
,需要用column-gap
属性来设置间距。如果你不具体指定column-gap
的值,它会默认为1em
来防止列间碰撞。这和其他布局方法中column-gap
的行为不一样,其他布局中默认为0
。你可以在间距上使用任意的长度单元,包括0
(如果你不希望有列间距)。
column-rule
属性让你有能力向两列间添加规则。它是column-rule-width
、column-rule-color
和column-rule-style
的简写形式,和border
行为类似。注意,一个规则自身不会占用任何空间。它会占据在间距的顶部,从而增加或减少那些你设置column-gap
的规则与内容间的空间。
允许元素横跨多列
你可以使用column-span
属性让多列容器内的元素横跨多列,类似通列。
h3 {
column-span: all;
}
当column-span
出现时,多列容器分列会在这个元素上停止,因此,容器里的内容会在元素上方形成多列样式,然后在横跨元素的下方形成一组新的列盒子(Column Box)。
你只可以使用column-span: all
或column-span: none
,并不能让元素横跨某几个列(非通列)。在文章写作时,Firefox还不支持column-span
属性。
扩展阅读
碎片化
多列布局是碎片化的一个例子,页面内容会被拆分成列。这和打印时内容被分到不同页非常类似。这个过程是碎片化规范(Fragmentation specification)处理的。这个规范包括了一些帮助控制内容切分的属性。
例如,如果你有一组置于多列中的卡片,并且你想确保卡片不会被截为两半分到不同的列,你可以使用break-inside
属性的avoid
值。考虑浏览器兼容性的因素,你也可能会想使用遗留的page-break-inside
属性。
.card {
page-break-inside: avoid;
break-inside: avoid;
}
如果你想在标题元素后禁止断行,你可以使用break-after
属性。
.container h2 {
page-break-after: avoid;
break-after: avoid;
}
这些属性可以被用在打印样式或多列样式中。在下面的例子里,在多列容器中的三个段落被拆分到了三列之中。我为p
元素设置了break-inside: avoid
,这意味着每个多列会在自己的列中结束(即使这会使各列长度不同)。
扩展阅读
如何选择布局类型?
大多数的网页会混合使用多种布局类型。各布局规范都准确定义了它们之间是如何相互作用的。例如,你可能会在网格布局的网格项中使用弹性布局。一些弹性容器可能具有定位属性或浮动。这些规范根据最优的布局方式已经包含了布局模型的混合使用。在这篇指南中,我尝试概述了这种布局类型的基本使用方式,来帮助你了解实现一个效果可能的最好方法。
然而,别害怕去运用多种方式来实现布局设计。担心你的选择会不会造成实际问题的情况比你想象中要少很多。所以请在开始就组织好你的文档结构,并且注意你文档内容的可视展示顺序。剩下的大部分工作就是在浏览器中试试你的布局方式是否符合预期。
如需转载,烦请注明出处:https://www.fedev.cn/css/guide-css-layout.htmlZoom Huarache 2K4 Kobe