CSS布局
一个HTML网页常常被分为不同的区域来显示不同的内容,在设计网页时首先需要思考页面的主体结构和细节分别采用什么样的布局来实现。通常我们使用正常布局、弹性盒子、网格布局来实现页面框架,浮动和定位来进行细节调整和实现特殊效果。表格布局和多列布局在一些特殊场景下会被使用到。
正常布局
正常布局流是指在不对页面进行任何布局控制时,浏览器默认的 HTML 布局方式。HTML元素大多分为 块级元素 或 行内元素,块级元素默认占据父元素的整个水平空间,垂直空间等于其内容高度,行内元素只占据它对应标签的边框所包含的空间(显著特点是不换行)。
HTML5中块级元素和行内元素的区别被更复杂的 内容类别 所替代。块级元素大致相当于HTML5中的 流内容类别,行内元素相当于 措辞内容类别,除这两个类别外还有其它类别。
块元素
<p>I love my cat.</p>
<ul>
<li>Buy cat food</li>
<li>Exercise</li>
<li>Cheer up friend</li>
</ul>
<p>The end!</p>
- 出现在另一个元素下面的元素被称为块元素,块级元素默认占据其父元素(容器)的整个水平空间,垂直空间等于其内容高度。
- 块级元素:address、article、aside、blockquote、dd、div、dl、fieldset、figcaption、figure、footer、form、h1~h6、header、hgroup、hr、ol、p、pre、section、table、ul。
行内元素
<p>This <span>span</span> is an inline element; its background has been colored to display both the beginning and end of the inline element's influence</p>
span { background-color: #8ABB55; }
- 出现在另一个元素旁边的元素被称为行内元素,一个行内元素只占据它对应标签的边框所包含的空间,默认情况下行内元素不会新启一行。
使用CSS调整元素: 将块元素调整为内联元素。
<p>I love my cat.</p>
<p>The end!</p>
p {
display: inline;
}
使用CSS调整元素: 将行内元素调整为块元素
<span>I love my cat.</span>
<span>The end!</span>
span {
display: block;
color: #999;
background: rgba(255,84,104,.3);
border: 2px solid rgb(255,84,104);
}
inline-block
与inline
的区别:允许在元素上设置宽度和高度,也会保留上下外边距/内边距(行内元素是不可以调整宽高和边距的)。inline-block
与block
的区别:在元素之后不添加换行符,因此该元素可以位于其他元素旁边。
弹性盒子
在很长一段时间里,程序员只有 浮动 和 定位 这两个比较可靠的跨浏览器兼容的布局工具。它们俩在大部分情况下都很好使,但是它们也有一定的局限性,例如以下简单的布局需求就难以实现或实现比较困难:
- 在父内容里面垂直居中一个块内容。
- 容器的所有子项占用等量的可用宽度/高度,而不管有多少宽度/高度可用。
- 使多列布局中的所有列采用相同的高度,即使它们包含的内容量不同。
Flexbox 是 CSS 弹性盒子布局(Flexible Box Layout )的缩写,它是专门设计用于创建横向或是纵向的一维页面布局。要使用 Flexbox,只需要在想要进行Flex布局的父元素上应用display: flex
,所有直接子元素都会按照flex进行布局。
简单布局示例
<div class="wrapper">
<div class="box">One</div>
<div class="box">Two</div>
<div class="box">Three</div>
</div>
<style>
.wrapper {
display:flex;
height:50px;
}
.wrapper > div {
background: aqua;
}
</style>
- 当我们给父元素添加上
display: flex
之后,它的三个直接子元素变成了flex
项,并按照flex容器的一些flex相关的初始值进行flex布局:- 它们排成了一列:因为父元素
flex-direction
的初值是row
。 - 它们的高度相同:因为父元素上
align-items
属性的初值是stretch
。 - 排成一列后在尾部留下一片空白:
flex项
的flex
属性初始值是0
。
- 它们排成了一列:因为父元素
网格布局
与弹性盒子布局用于设计横向或纵向布局不同,网格布局被用于同时在行列两个维度上将元素排列整齐。
简单布局示例
<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>
<style>
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 100px 100px;
grid-gap: 10px;
}
.wrapper > div {
background: aqua;
}
</style>
display
:值grid
设置父元素为网格布局。grid-template-columns
:值1fr 1fr 1fr
设置父元素的网格布局有三列。grid-template-rows
:值100px 100px
设置父元素的网格布局有两行。
在网格内放置元素
一旦采用了网格布局,那么你就可以调整元素的摆放位置,不用在依赖浏览器进行自动排列。在下面的例子中,定义了一个和上面一样的网格,并利用 grid-column
和 grid-row
两个属性来指定每个子元素应该从哪一行/列开始,并在哪一行/列结束。
<div class="wrapper">
<div class="box1">One</div>
<div class="box2">Two</div>
<div class="box3">Three</div>
</div>
<style>
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 100px 100px;
grid-gap: 10px;
}
.wrapper > div {
background: aqua;
}
.box1 {
grid-column: 2 / 4;
grid-row: 1;
}
.box2 {
grid-column: 1;
grid-row: 1 / 3;
}
.box3 {
grid-row: 2;
grid-column: 3;
}
</style>
grid-column
:是CSS属性grid-column-start
和grid-column-end
的简写属性,通过指定列方向位置的开始和结束,来设置网格单元的大小和位置。grid-row
:是CSS属性grid-row-start
和grid-row-end
的简写属性,通过指定行方向的开始和结束,来设置网格单元行相关的大小和位置。
表格布局
在很早之前,浏览器还不支持基本的CSS之前。WEB开发人员常常使用表格来完成整个网页的布局,这种布局有很多问题:不灵活、繁重、不好调试、语义错误。
通过浏览器开发工具可以发现 table 标签有一些默认的布局属性,当我们用这些属性对非table元素进行布局,这种用法被称为“使用CSS表格布局”。下面的例子展示了这种用法,使用CSS表格进行布局,这是一种比较传统的方法,通常用来兼容不支持Flexbox和Grid的浏览器(目前主流浏览器都支持弹性盒子和网格布局)。
简单布局示例
<form>
<p>请告诉我们你的姓名和年龄。</p>
<div>
<label for="fname">姓氏:</label>
<input type="text" id="fname">
</div>
<div>
<label for="lname">名称:</label>
<input type="text" id="lname">
</div>
<div>
<label for="age">年龄:</label>
<input type="text" id="age">
</div>
</form>
<style>
form {
display: table;
margin: 0 auto;
}
form div {
display: table-row;
}
form label, form input {
display: table-cell;
margin-bottom: 10px;
}
form label {
width: 200px;
padding-right: 5%;
text-align: right;
}
form input {
width: 300px;
}
form p {
display: table-caption;
caption-side: bottom;
width: 300px;
color: #999;
font-style: italic;
}
</style>
display: table
:父容器使用表格布局。display: table-row
:表格行布局。display: table-cell
:表格列布局。display: table-caption
:默认 标签效果。
多列布局
多列布局可以将内容按列并排排序,就像报纸的排版一样将相关的内容并排排列,这样可以方便用户进行阅读。要把一个块转换成多列容器,可以使用 column-count
告诉浏览器你需要多少列,也可以使用 column-width
来告诉浏览器以至少某个宽度尽可能多的列来填充容器。
简单布局示例
<div class="container">
<h1>多列布局布局</h1>
<p>柳宗元《江雪》:千山鸟飞绝,万径人踪灭。孤舟蓑笠翁,独钓寒江雪。</p>
<p>白居易《问刘十九》:绿蚁新醅酒,红泥小火炉。晚来天欲雪,能饮一杯无。</p>
<p>杜牧《江南春绝句》:千里莺啼绿映红,水村山郭酒旗风。南朝四百八十寺,多少楼台烟雨中。</p>
<p>杜甫《八阵图》:功盖三分国,名成八阵图。江流石不转,遗恨失吞吴。</p>
</div>
<style>
.container {
column-width: 200px;
}
</style>
浮动布局
Float会改变元素本身和正常布局流中在它之后的元素的布局行为,float元素会浮动到它们的左侧或右侧,并从正常布局流中被移除float
属性有四个可能的值:
left
— 将元素浮动到左侧。right
— 将元素浮动到右侧。none
— 默认值,不浮动。inherit
— 继承父元素的浮动属性。
简单布局示例
.box {
float: left;
width: 150px;
height: 150px;
margin-right: 30px;
}
.box {
background-color: rgb(207,232,220);
border: 2px solid rgb(79,185,227);
padding: 10px;
border-radius: 5px;
}
<h1>浮动布局示例</h1>
<div class="box">Float</div>
<p>柳宗元《江雪》:千山鸟飞绝,万径人踪灭。孤舟蓑笠翁,独钓寒江雪。<p>
<p>白居易《问刘十九》:绿蚁新醅酒,红泥小火炉。晚来天欲雪,能饮一杯无<p>
- 元素
<h1>
不会受div的影响,在div之后的两个<p>
元素都随div元素脱离正常布局流。
定位布局
定位可以让你把一个元素从它在正常布局流中的位置移动到另一个位置。定位并用来做页面主结构布局的方案,它更多是用来针对特殊项进行微调和管理。有五种主要的定位类型:
-
静态定位:元素的默认值,放在文档布局流的默认位置不做特殊处理。
-
相对定位:相对于元素在正常文档流的位置移动它,这对于微调和精准设计非常有用。
-
绝对定位:将元素完全从正常布局流中移除,就像将它单独放在一个图层中。允许你相对于
<html>
元素或者该元素的最近被定位祖先元素进行固定。绝对定位在创建复杂布局效果时非常有用,例如:显示关闭弹层、滑动的信息面板。 -
固定定位:与绝对定位非常类似,但是它是相对于浏览器窗口进行位置调整,而不是另一个元素。可以用它来创建在页面滚动过程中总是处于屏幕的某个位置的导航菜单。
-
粘性定位:它会让元素先保持与静态定位一样的位置,当它相对于浏览器窗口的位置达到设定的值时,它就会像固定定位一样。像“返回页面顶部”导航按钮就是它的典型应用。
为了方便演示增加一段HTML
<style>
body {
width: 500px;
margin: 0 auto;
}
p {
background-color: rgb(207,232,220);
border: 2px solid rgb(79,185,227);
padding: 10px;
margin: 10px;
border-radius: 5px;
}
</style>
<h1>Positioning</h1>
<p>柳宗元《江雪》:千山鸟飞绝,万径人踪灭。孤舟蓑笠翁,独钓寒江雪。</p>
<p class="positioned">白居易《问刘十九》:绿蚁新醅酒,红泥小火炉。晚来天欲雪,能饮一杯无</p>
<p>杜甫《八阵图》:功盖三分国,名成八阵图。江流石不转,遗恨失吞吴。</p>
相对定位
.positioned {
position: relative;
top: 30px;
left: 30px;
}
- 相对定位让你能够把一个正常布局流中的元素从它的默认位置按坐标进行相对移动。我们设置中间段落的
position
值为relative
,这个属性本身不做任何事情,还需要添加top
和left
属性(距离原位置的距离)。
绝对定位
.positioned {
position: absolute;
top: 30px;
left: 30px;
}
- 绝对定位用于将元素移除正常布局流,以坐标的形式相对于它的容器定位到WEB页面的任意位置。用于创建复杂布局页面结构。它经常与相对定位和浮动协同使用。
- 容器:最近定位祖先元素(第一个position属性是有效值的祖先元素),如果没有定位祖先元素则相对于HTML标签。
固定定位
<style>
body{
height:800px;
}
.positioned {
position: fixed;
top: 30px;
left: 30px;
background: rgba(255,84,104,.3);
border: 2px solid rgb(255,84,104);
}
</style>
<div class="positioned">固定</div>
<div>杜甫《八阵图》:功盖三分国,名成八阵图。江流石不转,遗恨失吞吴</div>
- 固定定位同绝对定位一样,将元素从文档流当中移出了。不同的是固定定位是相对于浏览器窗口边框来计算元素位置。通常用它来创建不受页面滚动条影响的区块(例如菜单)。
粘性定位
<style>
.positioned {
position: sticky;
top: 30px;
left: 30px;
background: rgba(255,84,104,.3);
border: 2px solid rgb(255,84,104);
}
</style>
<div style="height:600px">内容</div>
<div class="positioned">固定</div>
<div style="height:600px">内容</div>
- 粘性定位将默认的静态定位和固定定位相结合。当一个元素被指定了
position: sticky
后,它会在正常布局流中滚动,知道它出现在了我们设置的相对于容器的位置,这时候它就会停止随滚动条移动,就像应用了position: fixed
一样