CSS 页面布局技术允许我们拾取网页中的元素,并且控制它们相对正常布局流、周边元素、父容器或者主视口/窗口的位置。布局有一下几种
- 正常布局流
- display属性
- 弹性盒子
- 网格
- 浮动
- 定位
- CSS 表格布局
- 多列布局
每种布局都有它们的用途,各有优缺点,相互辅助。通过理解各个布局方法的设计理念,你能够找到构建你想要的网页需要的布局方案。
正常布局流
指在不对页面进行任何布局控制时,浏览器默认的 HTML 布局方式。让我们快速地看一个 HTML 的例子:
html
<p>段落1</p>
<ul>
<li>列表1</li>
<li>列表2</li>
<li>列表3</li>
</ul>
<p>段落2</p>
当使用正常布局流将完全可以创建你所需要的布局时,尽量避免使用 css 创建一个布局。因为你可以按照默认的方式来搭建页面,而不是自造车轮。
下列布局技术会覆盖默认的布局行为:
- display 属性 --- 标准的 value,比如block, inline 或者 inline-block 元素在正常布局流中的表现形式 (见 Types of CSS boxes). 接着是全新的布局方式,通过设置display的值,比如 CSS Grid 和 Flexbox.
浮动------应用 float 值,诸如 left 能够让块级元素互相并排成一行,而不是一个堆叠在另一个上面。 - position 属性 --- 允许你精准设置盒子中的盒子的位置,正常布局流中,默认为 static ,使用其他值会引起元素不同的布局方式,例如将元素固定到浏览器视口的左上角。
- 表格布局--- 表格的布局方式可以用在非表格内容上,可以使用display: table和相关属性在非表元素上使用。
- 多列布局--- 这个 Multi-column layout 属性可以让块按列布局,比如报纸的内容就是一列一列排布的。
display 属性
在 css 中实现页面布局的主要方法是设定display属性的值。此属性允许我们更改默认的显示方式。正常布局流中的所有内容都有一个display的值,用作元素的默认行为方式。例如,段落显示在一个段落的下面,这是因为它们的样式是display:block 。如果在段落中的某个文本周围创建链接,则该链接将与文本的其余部分保持内联,并且不会打断到新行。这是因为<a>
元素默认为display:inline。
可以更改此默认显示行为。例如,<li>
元素默认为display:block ,这意味着列表项显示为一个在另一个之下。如果我们将显示值更改为inline,它们现在将显示在彼此相邻。
html
<p>段落1</p>
<ul>
<li>列表1</li>
<li>列表2</li>
<li>列表3</li>
</ul>
<p>段落2</p>
li {
display:inline
}
除了可以通过将display 的block 和inline 相互转换来更改默认显示,还有一些更大的布局方法以display值开始。但是,在使用这些属性时,通常需要调用其他属性。在讨论布局时,对我们来说最重要的两个值是 display: flex 和 display: grid。
Flexbox 弹性盒子
Flexbox 是 CSS 弹性盒子布局模块(Flexible Box Layout Module)的缩写,它被专门设计出来用于创建横向或是纵向的一维页面布局。要使用 flexbox,你只需要在想要进行 flex 布局的父元素上应用display: flex ,所有直接子元素都将会按照 flex 进行布局。我们来看一个例子。
设置 display:flex
当我们把display: flex添加到元素时,该容器就变为flex容器,元素内的元素就自动按列进行排列。这是由于它们变成了flex项,按照 flex容器相关的初值进行flex布局:它们整整齐齐排成一行,是因为该元素上flex-direction的初值是row。它们全都被拉伸至和最高的元素高度相同,是因为父元素上align-items属性的初值是stretch。这就意味着所有的子元素都会被拉伸到它们的flex容器的高度,在这个案例里就是所有flex项中最高的一项。所有项目都从容器的开始位置进行排列,排列成一行后,在尾部留下一片空白。
html
<div class="block">
<div>BOX1</div>
<div>BOX2</div>
<div>BOX3</div>
</div>
.block {
display: flex;
}
.block > div {
margin: 5px;
border-radius: 5px;
background-color: #409eff;
color: white;
padding: 1em;
}
使用display: flex;
不使用display: flex;
设置 flex 属性
除了上述可以被应用到 flex 容器的属性以外,还有很多属性可以被应用到flex项上面。这些属性可以改变 flex 项在 flex 布局中占用宽/高的方式,允许它们通过伸缩来适应可用空间。
作为一个简单的例子,我们可以在所有子元素上添加flex 属性,并赋值为1,这会使得所有的子元素都伸展并填充容器,而不是在尾部留下空白。它们会调整自己直到占用相同宽度的空间。
html
.block > div {
margin: 5px;
border-radius: 5px;
background-color: #409eff;
color: white;
padding: 1em;
/* 增加 */
flex: 1;
}
Grid 布局
Flexbox 用于设计横向或纵向的布局,而 Grid 布局则被设计用于同时在两个维度上把元素按行和列排列整齐。
设置 display: grid
同 flex 一样,你可以通过指定 display 的值来转到 grid 布局:display: grid。下面的例子除了使用display:grid,我们还分别使用 grid-template-rows 和 grid-template-columns 两个属性定义了一些行和列的轨道。定义了三个1fr 2fr 1fr(把行等分为4份)的列,还有两个50px 80px的行之后,无需再在子元素上指定任何规则,它们自动地排列到了我们创建的格子当中。
html
<div class="block">
<div>GRID1</div>
<div>GRID2</div>
<div>GRID3</div>
<div>GRID4</div>
<div>GRID5</div>
<div>GRID6</div>
</div>
.block {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
grid-template-rows: 50px 80px;
grid-gap: 5px;
}
.block > div {
border-radius: 5px;
background-color: #409eff;
color: white;
padding: 1em;
}
在网格内放置元素
一旦你拥有了一个 grid,你也可以显式地将元素摆放在里面,而不是依赖于浏览器进行自动排列。在下面的第二个例子里,我们定义了一个和上面一样的 grid,但是这一次我们只有三个子元素。我们利用 grid-column 和 grid-row 两个属性来指定每一个子元素应该从哪一行/列开始,并在哪一行/列结束。这就能够让子元素在多个行/列上展开。
html
<div class="wrapper">
<div class="box1">One</div>
<div class="box2">Two</div>
<div class="box3">Three</div>
<div class="box4">Four</div>
<div class="box5">Five</div>
<div class="box6">Six</div>
</div>
.block {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 50px 50px;
grid-gap: 5px;
}
.block > div {
border-radius: 5px;
background-color: #409eff;
color: white;
padding: 1em;
}
.box1 {
grid-column: 2 / 4;
grid-row: 1;
}
.box2 {
grid-column: 1;
grid-row: 1 / 3;
}
.box3 {
grid-row: 2;
grid-column: 3;
}
注:这两个例子只是展示了 grid 布局的冰山一角,要深入了解 grid 布局,请参阅其他资料
浮动
把一个元素"浮动"(float) 起来,会改变该元素本身和在正常布局流中跟随它的其他元素的行为。这一元素会浮动到左侧或右侧,并且从正常布局流中移除,这时候其他的周围内容就会在这个被设置浮动 (float) 的元素周围环绕。
float 属性值:
- left --- 将元素浮动到左侧。
- right --- 将元素浮动到右侧。
- none --- 默认值,不浮动。
- inherit --- 继承父元素的浮动属性。
把一个
元素浮动到左侧,并且给了他一个右侧的margin,把文字推开。这给了我们文字环绕着这个
元素的效果。
html
<h1>滕王阁序</h1>
<div class="box">王勃(约650---676年),唐代诗人。汉族,字子安。绛州龙门(今山西河津)人。王勃与杨炯、卢照邻、骆宾王齐名,世称"初唐四杰",其中王勃是"初唐四杰"之首。</div>
<p>
豫章故郡,洪都新府。星分翼轸,地接衡庐。襟三江而带五湖,控蛮荆而引瓯越。物华天宝,龙光射牛斗之墟;人杰地灵,徐孺下陈蕃之榻。雄州雾列,俊采星驰。台隍枕夷夏之交,宾主尽东南之美。都督阎公之雅望,棨戟遥临;宇文新州之懿范,襜帷暂驻。十旬休假,胜友如云;千里逢迎,高朋满座。腾蛟起凤,孟学士之词宗;紫电青霜,王将军之武库。家君作宰,路出名区;童子何知,躬逢胜饯。
</p>
<p>
时维九月,序属三秋。潦水尽而寒潭清,烟光凝而暮山紫。俨骖騑于上路,访风景于崇阿;临帝子之长洲,得天人之旧馆。层峦耸翠,上出重霄;飞阁流丹,下临无地。鹤汀凫渚,穷岛屿之萦回;桂殿兰宫,即冈峦之体势。
</p>
<p>
披绣闼,俯雕甍,山原旷其盈视,川泽纡其骇瞩。闾阎扑地,钟鸣鼎食之家;舸舰弥津,青雀黄龙之舳。云销雨霁,彩彻区明。落霞与孤鹜齐飞,秋水共长天一色。渔舟唱晚,响穷彭蠡之滨;雁阵惊寒,声断衡阳之浦。
</p>
<p>
遥襟甫畅,逸兴遄飞。爽籁发而清风生,纤歌凝而白云遏。睢园绿竹,气凌彭泽之樽;邺水朱华,光照临川之笔。四美具,二难并。穷睇眄于中天,极娱游于暇日。天高地迥,觉宇宙之无穷;兴尽悲来,识盈虚之有数。望长安于日下,目吴会于云间。地势极而南溟深,天柱高而北辰远。关山难越,谁悲失路之人?萍水相逢,尽是他乡之客。怀帝阍而不见,奉宣室以何年?
</p>
<p>
嗟乎!时运不齐,命途多舛。冯唐易老,李广难封。屈贾谊于长沙,非无圣主;窜梁鸿于海曲,岂乏明时?所赖君子见机,达人知命。老当益壮,宁移白首之心?穷且益坚,不坠青云之志。酌贪泉而觉爽,处涸辙以犹欢。北海虽赊,扶摇可接;东隅已逝,桑榆非晚。孟尝高洁,空余报国之情;阮籍猖狂,岂效穷途之哭!
</p>
<p>
勃,三尺微命,一介书生。无路请缨,等终军之弱冠;有怀投笔,慕宗悫之长风。舍簪笏于百龄,奉晨昏于万里。非谢家之宝树,接孟氏之芳邻。他日趋庭,叨陪鲤对;今兹捧袂,喜托龙门。杨意不逢,抚凌云而自惜;钟期既遇,奏流水以何惭?
</p>
<p>
呜乎!胜地不常,盛筵难再;兰亭已矣,梓泽丘墟。临别赠言,幸承恩于伟饯;登高作赋,是所望于群公。敢竭鄙怀,恭疏短引;一言均赋,四韵俱成。请洒潘江,各倾陆海云尔:
</p>
<p>
滕王高阁临江渚,佩玉鸣鸾罢歌舞。
</p>
<p>
画栋朝飞南浦云,珠帘暮卷西山雨。
</p>
<p>
闲云潭影日悠悠,物换星移几度秋。
</p>
<p>
阁中帝子今何在?槛外长江空自流。
</p>
body {
width: 90%;
max-width: 900px;
margin: 0 auto;
}
p {
line-height: 2;
word-spacing: 0.1rem;
}
.box {
background-color: rgb(207, 232, 220);
border: 2px solid rgb(79, 185, 227);
padding: 10px;
border-radius: 5px;
}
/* 浮动float */
.box {
float: left;
width: 200px;
height: 150px;
margin-right: 30px;
}
定位
定位 (positioning) 能够让我们把一个元素从它原本在正常布局流中应该在的位置移动到另一个位置。定位并不是一种用来给你做主要页面布局的方式,它更像是让你去管理和微调页面中的一个特殊项的位置。
有一些非常有用的技术在特定的布局下依赖于position属性。同时,理解定位也能够帮助你理解正常布局流,理解把一个元素移出正常布局流是怎么一回事。
有五种主要的定位类型:
- 静态定位(Static positioning)是每个元素默认的属性------它表示"将元素放在文档布局流的默认位置------没有什么特殊的地方"。
- 相对定位(Relative positioning)允许我们相对于元素在正常的文档流中的位置移动它------包括将两个元素叠放在页面上。这对于微调和精准设计(design pinpointing)非常有用。
- 绝对定位(Absolute positioning)将元素完全从页面的正常布局流(normal layout flow)中移出,类似将它单独放在一个图层中。我们可以将元素相对于页面的
<html>
元素边缘固定,或者相对于该元素的最近被定位祖先元素(nearest positioned ancestor element)。绝对定位在创建复杂布局效果时非常有用,例如通过标签显示和隐藏的内容面板或者通过按钮控制滑动到屏幕中的信息面板。 - 固定定位(Fixed positioning)与绝对定位非常类似,但是它是将一个元素相对浏览器视口固定,而不是相对另外一个元素。这在创建类似在整个页面滚动过程中总是处于屏幕的某个位置的导航菜单时非常有用。
- 粘性定位(Sticky positioning)是一种新的定位方式,它会让元素先保持和 position: static 一样的定位,当它的相对视口位置(offset from the viewport)达到某一个预设值时,它就会像 position: fixed 一样定位。
简单定位示例
其实也就是标签原本的默认位置
html
<h1>定位</h1>
<p>块元素1</p>
<p>块元素2</p>
<p>块元素3</p>
body {
width: 500px;
margin: 0 auto;
}
p {
background-color: #409eff;
color: white;
border: 2px solid rgb(79, 185, 227);
padding: 10px;
margin: 10px;
border-radius: 5px;
}
相对定位
相对定位 (relative positioning) 让你能够把一个正常布局流 (normal flow) 中的元素从它的默认位置按坐标进行相对移动。比如将一个图标往下调一点,以便放置文字。我们可以通过下面的规则添加相对定位来实现效果:
这里我们给中间段落的position 一个 relative值------这属性本身不做任何事情,所以我们还添加了top和left属性。这些可以将受影响的元素向下向右移------这可能看起来和你所期待的相反,但你需要把它看成是左边和顶部的元素被"推开"一定距离,这就导致了它的向下向右移动。
html
<h1>定位</h1>
<p>块元素1</p>
<p class='positioned'>块元素2</p>
<p>块元素3</p>
body {
width: 500px;
margin: 0 auto;
}
p {
background-color: #409eff;
color: white;
border: 2px solid rgb(79, 185, 227);
padding: 10px;
margin: 10px;
border-radius: 5px;
}
.positioned {
background: rgba(200, 150, 150, 0.2);
position: relative;
top: 30px;
left: 30px;
}
绝对定位
绝对定位用于将元素移出正常布局流 (normal flow),以坐标的形式相对于它的容器定位到 web 页面的任何位置,以创建复杂的布局。有趣的是,它经常被用于与相对定位和浮动的协同工作。
这里我们给我们的中间段一个position的 absolute值,并且和前面一样加上 top 和left 属性。但是,添加此代码将给出以下结果:
html
<h1>相对定位</h1>
<p>块元素1</p>
<p class='positioned'>块元素2</p>
<p>块元素3</p>
body {
width: 500px;
margin: 0 auto;
}
p {
background-color: #409eff;
color: white;
border: 2px solid rgb(79, 185, 227);
padding: 10px;
margin: 10px;
border-radius: 5px;
}
.positioned {
background: rgba(200, 150, 150, 0.2);
position: absolute;
color: black;
top: 30px;
left: 30px;
}
固定定位
固定定位 (fixed positioning) 同绝对定位 (absolute positioning) 一样,将元素从文档流 (document flow) 当中移出了。但是,定位的坐标不会应用于"容器"边框来计算元素的位置,而是会应用于视口 (viewport) 边框。利用这一特性,我们可以轻松搞出一个固定位置的菜单,而不受底下的页面滚动的影响。
在这个例子里面,我们在 HTML 加了三段很长的文本来使得页面可滚动,又加了一个带有position: fixed的盒子。
html
<h1>滕王阁序</h1>
<div class="positioned">王勃</div>
<p>
豫章故郡,洪都新府。星分翼轸,地接衡庐。襟三江而带五湖,控蛮荆而引瓯越。物华天宝,龙光射牛斗之墟;人杰地灵,徐孺下陈蕃之榻。雄州雾列,俊采星驰。台隍枕夷夏之交,宾主尽东南之美。都督阎公之雅望,棨戟遥临;宇文新州之懿范,襜帷暂驻。十旬休假,胜友如云;千里逢迎,高朋满座。腾蛟起凤,孟学士之词宗;紫电青霜,王将军之武库。家君作宰,路出名区;童子何知,躬逢胜饯。
</p>
<p>
时维九月,序属三秋。潦水尽而寒潭清,烟光凝而暮山紫。俨骖騑于上路,访风景于崇阿;临帝子之长洲,得天人之旧馆。层峦耸翠,上出重霄;飞阁流丹,下临无地。鹤汀凫渚,穷岛屿之萦回;桂殿兰宫,即冈峦之体势。
</p>
<p>
披绣闼,俯雕甍,山原旷其盈视,川泽纡其骇瞩。闾阎扑地,钟鸣鼎食之家;舸舰弥津,青雀黄龙之舳。云销雨霁,彩彻区明。落霞与孤鹜齐飞,秋水共长天一色。渔舟唱晚,响穷彭蠡之滨;雁阵惊寒,声断衡阳之浦。
</p>
<p>
遥襟甫畅,逸兴遄飞。爽籁发而清风生,纤歌凝而白云遏。睢园绿竹,气凌彭泽之樽;邺水朱华,光照临川之笔。四美具,二难并。穷睇眄于中天,极娱游于暇日。天高地迥,觉宇宙之无穷;兴尽悲来,识盈虚之有数。望长安于日下,目吴会于云间。地势极而南溟深,天柱高而北辰远。关山难越,谁悲失路之人?萍水相逢,尽是他乡之客。怀帝阍而不见,奉宣室以何年?
</p>
<p>
嗟乎!时运不齐,命途多舛。冯唐易老,李广难封。屈贾谊于长沙,非无圣主;窜梁鸿于海曲,岂乏明时?所赖君子见机,达人知命。老当益壮,宁移白首之心?穷且益坚,不坠青云之志。酌贪泉而觉爽,处涸辙以犹欢。北海虽赊,扶摇可接;东隅已逝,桑榆非晚。孟尝高洁,空余报国之情;阮籍猖狂,岂效穷途之哭!
</p>
<p>
勃,三尺微命,一介书生。无路请缨,等终军之弱冠;有怀投笔,慕宗悫之长风。舍簪笏于百龄,奉晨昏于万里。非谢家之宝树,接孟氏之芳邻。他日趋庭,叨陪鲤对;今兹捧袂,喜托龙门。杨意不逢,抚凌云而自惜;钟期既遇,奏流水以何惭?
</p>
<p>
呜乎!胜地不常,盛筵难再;兰亭已矣,梓泽丘墟。临别赠言,幸承恩于伟饯;登高作赋,是所望于群公。敢竭鄙怀,恭疏短引;一言均赋,四韵俱成。请洒潘江,各倾陆海云尔:
</p>
<p>
滕王高阁临江渚,佩玉鸣鸾罢歌舞。
</p>
<p>
画栋朝飞南浦云,珠帘暮卷西山雨。
</p>
<p>
闲云潭影日悠悠,物换星移几度秋。
</p>
<p>
阁中帝子今何在?槛外长江空自流。
</p>
body {
width: 500px;
margin: 0 auto;
}
.positioned {
background-color: #409eff;
color: white;
padding: 10px;
margin: 10px;
border-radius: 5px;
}
.positioned {
position: fixed;
top: 100px;
left: 10px;
}
粘性定位
粘性定位 (sticky positioning) 是最后一种我们能够使用的定位方式。它将默认的静态定位 (static positioning) 和固定定位 (fixed positioning) 相混合。当一个元素被指定了position: sticky时,它会在正常布局流中滚动,直到它出现在了我们给它设定的相对于容器的位置,这时候它就会停止随滚动移动,就像它被应用了position: fixed一样。
html
<h1>滕王阁序</h1>
<p>
豫章故郡,洪都新府。星分翼轸,地接衡庐。襟三江而带五湖,控蛮荆而引瓯越。物华天宝,龙光射牛斗之墟;人杰地灵,徐孺下陈蕃之榻。雄州雾列,俊采星驰。台隍枕夷夏之交,宾主尽东南之美。都督阎公之雅望,棨戟遥临;宇文新州之懿范,襜帷暂驻。十旬休假,胜友如云;千里逢迎,高朋满座。腾蛟起凤,孟学士之词宗;紫电青霜,王将军之武库。家君作宰,路出名区;童子何知,躬逢胜饯。
</p>
<p>
时维九月,序属三秋。潦水尽而寒潭清,烟光凝而暮山紫。俨骖騑于上路,访风景于崇阿;临帝子之长洲,得天人之旧馆。层峦耸翠,上出重霄;飞阁流丹,下临无地。鹤汀凫渚,穷岛屿之萦回;桂殿兰宫,即冈峦之体势。
</p>
<div class="positioned">王勃</div>
<p>
披绣闼,俯雕甍,山原旷其盈视,川泽纡其骇瞩。闾阎扑地,钟鸣鼎食之家;舸舰弥津,青雀黄龙之舳。云销雨霁,彩彻区明。落霞与孤鹜齐飞,秋水共长天一色。渔舟唱晚,响穷彭蠡之滨;雁阵惊寒,声断衡阳之浦。
</p>
<p>
遥襟甫畅,逸兴遄飞。爽籁发而清风生,纤歌凝而白云遏。睢园绿竹,气凌彭泽之樽;邺水朱华,光照临川之笔。四美具,二难并。穷睇眄于中天,极娱游于暇日。天高地迥,觉宇宙之无穷;兴尽悲来,识盈虚之有数。望长安于日下,目吴会于云间。地势极而南溟深,天柱高而北辰远。关山难越,谁悲失路之人?萍水相逢,尽是他乡之客。怀帝阍而不见,奉宣室以何年?
</p>
<p>
嗟乎!时运不齐,命途多舛。冯唐易老,李广难封。屈贾谊于长沙,非无圣主;窜梁鸿于海曲,岂乏明时?所赖君子见机,达人知命。老当益壮,宁移白首之心?穷且益坚,不坠青云之志。酌贪泉而觉爽,处涸辙以犹欢。北海虽赊,扶摇可接;东隅已逝,桑榆非晚。孟尝高洁,空余报国之情;阮籍猖狂,岂效穷途之哭!
</p>
<p>
勃,三尺微命,一介书生。无路请缨,等终军之弱冠;有怀投笔,慕宗悫之长风。舍簪笏于百龄,奉晨昏于万里。非谢家之宝树,接孟氏之芳邻。他日趋庭,叨陪鲤对;今兹捧袂,喜托龙门。杨意不逢,抚凌云而自惜;钟期既遇,奏流水以何惭?
</p>
<p>
呜乎!胜地不常,盛筵难再;兰亭已矣,梓泽丘墟。临别赠言,幸承恩于伟饯;登高作赋,是所望于群公。敢竭鄙怀,恭疏短引;一言均赋,四韵俱成。请洒潘江,各倾陆海云尔:
</p>
<p>
滕王高阁临江渚,佩玉鸣鸾罢歌舞。
</p>
<p>
画栋朝飞南浦云,珠帘暮卷西山雨。
</p>
<p>
闲云潭影日悠悠,物换星移几度秋。
</p>
<p>
阁中帝子今何在?槛外长江空自流。
</p>
body {
width: 500px;
margin: 0 auto;
}
.positioned {
background-color: #409eff;
color: white;
padding: 10px;
margin: 10px;
border-radius: 5px;
}
.positioned {
position: sticky;
top: 100px;
left: 10px;
}