CSS的定位与布局
定位属性:position
元素是利用top、bottom、left、right
属性进行定位的,要想使用这些属性,就需要先设置position
值。position
属性规定了应用于元素定位方法的类型。
static
static
是position
的默认属性值,使用static
定位的属性将不受top、bottom、left、right
的影响。文档将会按照源码的顺序决定每个元素的位置,每个块级元素占据自己的区块,元素与元素之间不会重叠。
relative、fixed、absolute
这三个属性值都是相对于某个基点的定位,不同之处在于基点的选择。三者都不会对其他元素的位置产生影响,因此元素之间可能会产生重叠。
relative
relative
定位的基点是元素的默认位置,需要搭配top、bottom、left、right
四个属性值一起使用,用于指定偏移的方向和距离。
fixed
fixed
定位的基点为浏览器窗口,意味着即使滚动页面,元素也始终处于同一位置,可以搭配top、bottom、left、right
。
absolute
absolute
定位的基点为父元素。该属性有一个限制条件:定位基点不可以是static
定位,否则定位基点将变成网页的根元素(html)。absolute
定位也需要搭配top、bottom、left、right
一起使用。
注:absolute
定位的元素会被“正常页面流”忽略,也就是说在“正常页面流”中,该元素占据空间为零,周边元素会不受影响。
sticky
sticky
会产生动态效果,像是relative
与fixed
的结合。该属性生效的前提是必须与top、bottom、left、right
搭配,不能省略,否则与relative
定位一样,不会产生动态固定的效果。
具体规则为:当页面滚动,父元素部分不可见时,只要与sticky
元素的距离达到生效门槛,relative
定位就会自动切换为fixed
定位;等父元素完全不可见时,fixed
定位会自动切换为relative
定位。
div.sticky {
position: -webkit-sticky;/*safari浏览器*/
position: sticky;
top: 10px;
}
上方代码块中,页面向下滚动,div.sticky
父元素部分不可见时,一旦与div.sticky
间距离小于10px,div.sticky
就将变为fixed
定位,保持与视口顶部10px的距离;页面继续向下滚动,父元素完全不可见时,恢复为relative
定位。
应用
- “动态固定”效果
上述例子即为动态固定效果的实现 - 堆叠效果
<div><img src="pic1.jpg"></div>
<div><img src="pic2.jpg"></div>
<div><img src="pic3.jpg"></div>
div {
position: sticky;
top: 0;
}
效果如下图所示,可以发现当滚轮滑动时,后面的图片会重叠在前一张图片上。
- 表格的表头锁定
th {
position: sticky;
top: 0;
}
效果如下:
布局属性:display
传统的布局是利用display
+position
+float
实现的,这种布局方式对于特殊的布局非常不方便,例如垂直居中。接下来介绍两种强大的布局方案。
flex(弹性布局)
flex是 flexible box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。任何一个容器都可以指定为 flex 布局。设为 flex 布局以后,子元素的float
、clear
和vertical-align
属性将失效。
上图为一个flex
容器,容器中存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end。
项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size。
容器属性
flex-direction
该属性决定了主轴的方向(项目的排列方向),属性值有4个:
属性值 | 效果 |
---|---|
row(默认值) | 主轴为水平方向,起点在左端 |
row-reverse | 主轴为水平方向,起点在右端 |
column | 主轴为垂直方向,起点在上沿 |
column-reverse | 主轴为垂直方向,起点在下沿 |
.box {
flex-direction: row | row-reverse | column | column-reverse;
}
flex-wrap
默认情况下,项目会排列在一条线上。flex-wrap
属性定义了 如果一条轴线排不下换行的方式
属性值 | 效果 |
---|---|
nowrap(默认值) | 不换行 |
wrap | 换行,第一行在上方 |
wrap-reverse | 换行,第一行在下方 |
.box {
flex-wrap: nowrap | wrap | wrap-reverse;
}
flex-flow
flex-flow
属性是flex-direction
属性和flex-wrap
属性的简写形式,默认值为row nowrap
。
.box {
flex-flow: <flex-direction> || <flex-wrap>;
}
justify-content
该属性定义了项目在主轴上的对齐方式,属性值为5个:
属性值 | 效果 |
---|---|
flex-start(默认值) | 左对齐 |
flex-end | 右对齐 |
center | 居中 |
space-between | 两端对齐,项目之间的间隔都相等 |
space-around | 每个项目两侧的间隔相等,因此项目之间的间隔比项目与边框的间隔大一倍 |
.box {
justify-content: flex-start | flex-end | center | space-between | space-around;
}
align-items
该属性定义项目在交叉轴上如何对齐。
属性值 | 效果 |
---|---|
flex-start | 交叉轴的起点对齐 |
flex-end | 交叉轴的终点对齐 |
center | 交叉轴的中点对齐 |
baseline | 项目的第一行文字的基线对齐 |
stretch(默认值) | 如果项目未设置高度或设为auto,将占满整个容器的高度 |
.box {
align-items: flex-start | flex-end | center | baseline | stretch;
}
align-content
该属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
属性值 | 效果 |
---|---|
flex-start | 与交叉轴的起点对齐 |
flex-end | 与交叉轴的终点对齐 |
center | 与交叉轴的中点对齐 |
space-between | 与交叉轴两端对齐,轴线之间的间隔平均分布 |
space-around | 每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍 |
stretch(默认值) | 轴线占满整个交叉轴 |
.box {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
项目的属性
order
该属性定义了项目的排列顺序。数值越小,排列越靠前,默认为0。
.item {
order: <integer>;
}
flex-grow
该属性属性定义了项目的放大比例,默认为0,即如果存在剩余空间,也不放大。
.item {
flex-grow: <number>; /*默认为0*/
}
如果所有项目的flex-grow
属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow
属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。
flex-shrink
该属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
.item {
flex-shrink: <number>; /* 默认为1 */
}
如果所有项目的flex-shrink
属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink
属性为0,其他项目都为1,则空间不足时,前者不缩小。
flex-basis
该属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。可以设为跟width
或height
属性一样的值(比如350px),则项目将占据固定空间。
.item {
flex-basis: <length> | auto; /* 默认为auto */
}
flex
flex
属性是flex-grow
,flex-shrink
和flex-basis
的简写,默认值为0 1 auto。后两个属性可选。
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。
align-self
该属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items
属性。默认值为auto,表示继承父元素的align-items
属性,如果没有父元素,则等同于stretch。
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
实例
骰子的布局
默认的Html模板为:
<div class="box">
<span class="item"></span>
</div>
只有左上一个点时,flex布局默认即为首行左对齐,所以只需要一行代码
.box {
display: flex;
}
设置项目的对齐方式,就可以实现居中对齐和右对齐
.box {
display: flex;
justify-content: center;
}
设置交叉轴对齐方式,可以垂直移动主轴。
.box {
display: flex;
align-items: center;
}
.box {
display: flex;
justify-content: space-between;
}
.box {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.box {
display: flex;
}
.item:nth-child(2) {
align-self: center;
}
.box {
display: flex;
justify-content: space-between;
}
.item:nth-child(2) {
align-self: flex-end;
}
.box {
display: flex;
}
.item:nth-child(2) {
align-self: center;
}
.item:nth-child(3) {
align-self: flex-end;
}
<div class="box">
<div class="column">
<span class="item"></span>
<span class="item"></span>
</div>
<div class="column">
<span class="item"></span>
<span class="item"></span>
</div>
</div>
.box {
display: flex;
flex-wrap: wrap;
align-content: space-between;
}
.column {
flex-basis: 100%;
display: flex;
justify-content: space-between;
}
网格布局
- 基本网格布局
最简单的网格布局,就是平均分布。在容器里面平均分配空间,跟上面的骰子布局很像,但是需要设置项目的自动缩放。 - 百分比布局
某个网格的宽度为固定的百分比,其余网格平均分配剩余的空间。
<div class="Grid">
<div class="Grid-cell u-1of4">...</div>
<div class="Grid-cell">...</div>
<div class="Grid-cell u-1of3">...</div>
</div>
.Grid {
display: flex;
}
.Grid-cell {
flex: 1;
}
.Grid-cell.u-full {
flex: 0 0 100%;
}
.Grid-cell.u-1of2 {
flex: 0 0 50%;
}
.Grid-cell.u-1of3 {
flex: 0 0 33.3333%;
}
.Grid-cell.u-1of4 {
flex: 0 0 25%;
}
- 圣杯布局
是一种最常见的网站布局。页面从上到下,分成三个部分:头部(header),躯干(body),尾部(footer)。其中躯干又水平分成三栏,从左到右为:导航、主栏、副栏。
<body class="HolyGrail">
<header>...</header>
<div class="HolyGrail-body">
<main class="HolyGrail-content">...</main>
<nav class="HolyGrail-nav">...</nav>
<aside class="HolyGrail-ads">...</aside>
</div>
<footer>...</footer>
</body>
.HolyGrail {
display: flex;
min-height: 100vh;
flex-direction: column;
}
header,
footer {
flex: 1;
}
.HolyGrail-body {
display: flex;
flex: 1;
}
.HolyGrail-content {
flex: 1;
}
.HolyGrail-nav, .HolyGrail-ads {
/* 两个边栏的宽度设为12em */
flex: 0 0 12em;
}
.HolyGrail-nav {
/* 导航放到最左边 */
order: -1;
}
- 悬挂式布局
在主栏的左侧或右侧添加一个图片栏。
<div class="Media">
<img class="Media-figure" src="" alt="">
<p class="Media-body">...</p>
</div>
.Media {
display: flex;
align-items: flex-start;
}
.Media-figure {
margin-right: 1em;
}
.Media-body {
flex: 1;
}
- 固定的底栏
有时,页面内容太少,无法占满一屏的高度,底栏就会抬高到页面的中间。这时可以采用Flex布局,让底栏总是出现在页面的底部。
<body class="Site">
<header>...</header>
<main class="Site-content">...</main>
<footer>...</footer>
</body>
.Site {
display: flex;
min-height: 100vh;
flex-direction: column;
}
.Site-content {
flex: 1;
}
grid(网格布局)
网格布局(Grid)是最强大的 CSS 布局方案。它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局。
grid 布局与 flex 布局有一定的相似性,都可以指定容器内部多个项目的位置。但是,它们也存在重大区别。
flex 布局是轴线布局,只能指定"项目"针对轴线的位置,可以看作是一维布局。grid 布局则是将容器划分成"行"和"列",产生单元格,然后指定"项目所在"的单元格,可以看作是二维布局。grid 布局远比 flex 布局强大。
基本概念
采用网格布局的区域,称为"容器"(container)。容器内部采用网格定位的子元素,称为"项目"(item)。项目只能是容器的顶层子元素,不包含项目的子元素,grid 布局只对项目生效。
容器属性
设为网格布局以后,容器子元素(项目)的float
、display: inline-block
、display: table-cell
、vertical-align
和 column-*
等设置都将失效。
display
display: grid
指定一个容器采用网格布局
div {
display: grid;
}
默认情况下,容器元素都是块级元素,但也可以设成行内元素。
div {
display: inline-grid;
}
grid-template-columns ,grid-template-rows
容器指定了网格布局以后,接着就要划分行和列。grid-template-columns
属性定义每一列的列宽,grid-template-rows
属性定义每一行的行高。
.container {
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
}
除了使用绝对单位,也可以使用百分比。
- repeat()
重复写同样的值非常麻烦,尤其网格很多时。这时,可以使用repeat()函数,简化重复的值。repeat()接受两个参数,第一个参数是重复的次数(上例是3),第二个参数是所要重复的值。
.container {
display: grid;
grid-template-columns: repeat(3, 33.33%);
grid-template-rows: repeat(3, 33.33%);
}
repeat()重复某种模式也是可以的。
grid-template-columns: repeat(2, 100px 20px 80px);
- auto-fill关键字
有时,单元格的大小是固定的,但是容器的大小不确定。如果希望每一行(或每一列)容纳尽可能多的单元格,这时可以使用auto-fill
关键字表示自动填充。
.container {
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
}
表示每列宽度100px,然后自动填充,直到容器不能放置更多的列。
- fr关键字
为了方便表示比例关系,网格布局提供了fr
关键字(fraction 的缩写,意为"片段")。如果两列的宽度分别为1fr
和2fr
,就表示后者是前者的两倍。
.container {
display: grid;
grid-template-columns: 1fr 1fr;
}
fr
可以与绝对长度的单位结合使用,这时会非常方便。
.container {
display: grid;
grid-template-columns: 150px 1fr 2fr;
}
- minmax()
minmax()函数产生一个长度范围,表示长度就在这个范围之中。它接受两个参数,分别为最小值和最大值
grid-template-columns: 1fr 1fr minmax(100px, 1fr);
minmax(100px, 1fr)表示列宽不小于100px,不大于1fr。
- auto 关键字
auto关键字表示由浏览器自己决定长度。
grid-template-columns: 100px auto 100px;
上面代码中,第二列的宽度,基本上等于该列单元格的最大宽度,除非单元格内容设置了min-width,且这个值大于最大宽度。
- 网格线的名称
grid-template-columns
属性和grid-template-rows
属性里面,还可以使用方括号,指定每一根网格线的名字,方便以后的引用。
.container {
display: grid;
grid-template-columns: [c1] 100px [c2] 100px [c3] auto [c4];
grid-template-rows: [r1] 100px [r2] 100px [r3] auto [r4];
}
上面代码指定网格布局为3行 x 3列,因此有4根垂直网格线和4根水平网格线。方括号里面依次是这八根线的名字。
网格布局允许同一根线有多个名字,比如[fifth-line row-5]。
- 布局实例
grid-template-columns
属性对于网页布局非常有用。两栏式布局只需要一行代码。
.wrapper {
display: grid;
grid-template-columns: 70% 30%;
}
上面代码将左边栏设为70%,右边栏设为30%。
传统的十二网格布局,写起来也很容易。
grid-template-columns: repeat(12, 1fr);
row-gap 、column-gap 、gap
row-gap
属性设置行与行的间隔(行间距),column-gap
属性设置列与列的间隔(列间距)。
.container {
row-gap: 20px;
column-gap: 20px;
}
gap
属性是column-gap
和row-gap
的合并简写形式,语法如下。
gap: <row-gap> <column-gap>;
如果gap省略了第二个值,浏览器认为第二个值等于第一个值。
grid-template-areas
网格布局允许指定"区域"(area),一个区域由单个或多个单元格组成。grid-template-areas
属性用于定义区域。
.container {
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
grid-template-areas: 'a b c'
'd e f'
'g h i';
}
上面代码先划分出9个单元格,然后将其定名为a到i的九个区域,分别对应这九个单元格。
多个单元格合并成一个区域的写法如下。
grid-template-areas: 'a a a'
'b b b'
'c c c';
如果某些区域不需要利用,则使用"点"(.)表示。
注意,区域的命名会影响到网格线。每个区域的起始网格线,会自动命名为区域名-start
,终止网格线自动命名为区域名-end
。
grid-auto-flow
划分网格以后,容器的子元素会按照顺序,自动放置在每一个网格。默认的放置顺序是"先行后列",即先填满第一行,再开始放入第二行,即下图数字的顺序。这个顺序由grid-auto-flow
属性决定,默认值是row
,即"先行后列"。也可以将它设成column
,变成"先列后行"。
grid-auto-flow: column;
grid-auto-flow
属性除了设置成row
和column
,还可以设成row dense
和column dense
。这两个值主要用于,某些项目指定位置以后,剩下的项目怎么自动放置。
上图中,1号项目后面的位置是空的,这是因为3号项目默认跟着2号项目,所以会排在2号项目后面。现在修改设置,设为row dense
,表示"先行后列",并且尽可能紧密填满,尽量不出现空格。
grid-auto-flow: row dense;
justify-items 、align-items 、place-items
justify-items
属性设置单元格内容的水平位置(左中右),align-items
属性设置单元格内容的垂直位置(上中下)。
.container {
justify-items: start | end | center | stretch;
align-items: start | end | center | stretch;
}
这两个属性的写法完全相同,都可以取下面这些值。
属性值 | 效果 |
---|---|
start | 对齐单元格的起始边缘 |
end | 对齐单元格的结束边缘 |
center | 单元格内部居中 |
stretch(默认值) | 拉伸,占满单元格的整个宽度 |
.container {
justify-items: start;
}
place-items
属性是align-items
属性和justify-items
属性的合并简写形式。
place-items: <align-items> <justify-items>;
justify-content 、align-content、place-content
justify-content
属性是整个内容区域在容器里面的水平位置(左中右),align-content
属性是整个内容区域的垂直位置(上中下)。
.container {
justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
align-content: start | end | center | stretch | space-around | space-between | space-evenly;
}
这两个属性的写法完全相同,都可以取下面这些值。
属性值 | 效果 |
---|---|
start | 对齐容器的起始边框 |
end | 对齐容器的结束边框 |
center | 容器内部居中 |
stretch(默认值) | 项目大小没有指定时,拉伸占据整个网格容器 |
space-around | 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与容器边框的间隔大一倍 |
space-between | 项目与项目的间隔相等,项目与容器边框之间没有间隔 |
space-evenly | 项目与项目的间隔相等,项目与容器边框之间也是同样长度的间隔 |
以后三者为例
place-content
属性是align-content
属性和justify-content
属性的合并简写形式。如果省略第二个值,浏览器就会假定第二个值等于第一个值。
grid-auto-columns 、grid-auto-rows
有时候,一些项目的指定位置,在现有网格的外部。比如网格只有3列,但是某一个项目指定在第5行。这时,浏览器会自动生成多余的网格,以便放置项目。
grid-auto-columns
属性和grid-auto-rows
属性用来设置,浏览器自动创建的多余网格的列宽和行高。它们的写法与grid-template-columns
和grid-template-rows
完全相同。如果不指定这两个属性,浏览器完全根据单元格内容的大小,决定新增网格的列宽和行高。
.container {
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
grid-auto-rows: 50px;
}
grid-template、grid
grid-template
属性是grid-template-columns
、grid-template-rows
和grid-template-areas
这三个属性的合并简写形式。
grid
属性是grid-template-rows
、grid-template-columns
、grid-template-areas
、 grid-auto-rows
、grid-auto-columns
、grid-auto-flow
这六个属性的合并简写形式。
项目属性
grid-column-start 、grid-column-end、grid-row-start 、grid-row-end
项目的位置是可以指定的,具体方法就是指定项目的四个边框,分别定位在哪根网格线。
属性名 | 效果 |
---|---|
grid-column-start | 左边框所在的垂直网格线 |
grid-column-end | 右边框所在的垂直网格线 |
grid-row-start | 上边框所在的水平网格线 |
grid-row-end | 下边框所在的水平网格线 |
.item-1 {
grid-column-start: 2;
grid-column-end: 4;
}
上面代码指定,1号项目的左边框是第二根垂直网格线,右边框是第四根垂直网格线。
上图中,只指定了1号项目的左右边框,没有指定上下边框,所以会采用默认位置,即上边框是第一根水平网格线,下边框是第二根水平网格线。
这四个属性的值,除了指定为第几个网格线,还可以指定为网格线的名字。还可以使用span
关键字,表示"跨越",即左右边框(上下边框)之间跨越多少个网格。
grid-column 、grid-row
grid-column
属性是grid-column-start
和grid-column-end
的合并简写形式,grid-row
属性是grid-row-start
属性和grid-row-end
的合并简写形式。
.item {
grid-column: <start-line> / <end-line>;
grid-row: <start-line> / <end-line>;
}
斜杠以及后面的部分可以省略,默认跨越一个网格。
grid-area
grid-area
属性指定项目放在哪一个区域。
.item-1 {
grid-area: e;
}
还可用作grid-row-start
、grid-column-start
、grid-row-end
、grid-column-end
的合并简写形式,直接指定项目的位置。
.item {
grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
}
justify-self 、align-self、place-self
justify-self
属性设置单元格内容的水平位置(左中右),跟justify-items
属性的用法完全一致,但只作用于单个项目。
align-self
属性设置单元格内容的垂直位置(上中下),跟align-items
属性的用法完全一致,也是只作用于单个项目。
.item {
justify-self: start | end | center | stretch;
align-self: start | end | center | stretch;
}
.item-1 {
justify-self: start;
}
place-self
属性是align-self
属性和justify-self
属性的合并简写形式。
place-self: <align-self> <justify-self>;
如果省略第二个值,place-self
属性会认为这两个值相等。