跳到主要内容

基础-布局

Flex布局

Flex 弹性布局越来越方便, 用来为盒状模型提供最大的灵活性.

基本概念

采用 Flex 布局的元素, 称为 Felx 容器, 简称容器, 它的所有子元素自动称为容器成员, 称为 flex item, 简称项目.

image

  • 水平的主轴: main axis
  • 垂直的交叉轴: cross axis.
  • 主轴开始的位置: main start
  • 主轴结束的位置: main end
  • 交叉轴开始位置: cross start
  • 交叉轴结束位置: cross end

默认主轴排列, 单个项目占据的主轴空间叫做 main size, 占据交叉轴空间叫做 cross size

容器属性

flex-direction

决定主轴的方向

  • row : 从左到右
  • row-reverse: 从右到左
  • column:从上到下
  • column-reverse:从下到上

flex-wrap

决定轴线是否换行

  • nowrap: 不换行
  • wrap:自动换行
  • wrap-reverse: 自动换行并且第一行在下方

flex-flow

flex-direction(<flex-direction> || <flex-wrap>) 属性和 flex-wrap 属性的简写形式

  • row nowrap: 默认值

justify-content

项目在主轴上的对齐方式

  • flex-start:左对齐
  • flex-end:右对齐
  • center:居中
  • space-between:两端对齐,项目之间的间隔都相等。
  • space-around:每个项目两侧的间隔相等

image

align-items

定义项目在交叉轴上如何对齐

  • flex-start:交叉轴的起点对齐。
  • flex-end:交叉轴的终点对齐。
  • center:交叉轴的中点对齐。
  • baseline: 项目的第一行文字的基线对齐。
  • stretch(默认值):如果项目未设置高度或设为 auto,将占满整个容器的高度。

image

align-content

定义了多根轴线的对齐方式

  • flex-start:与交叉轴的起点对齐。
  • flex-end:与交叉轴的终点对齐。
  • center:与交叉轴的中点对齐。
  • space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
  • space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
  • stretch(默认值):轴线占满整个交叉轴。

image

项目属性

order

定义项目的排列顺序, 数值越小, 排列越靠前, 默认为 0

.item {
order: <integer>;
}

flex-grow

定义项目的放大比例, 默认为 0, 即如果存在剩余空间, 也不放大

.item {
flex-grow: <number>; /* default 0 */
}

image

flex-shrink

定义了项目的缩小比例, 默认为 1, 如果空间不足, 该项目将缩小

.item {
flex-shrink: <number>; /* default 1 */
}

如果所有项目的 flex-shrink 属性都为 1,当空间不足时,都将等比例缩小。如果一个项目的 flex-shrink 属性为 0,其他项目都为 1,则空间不足时,前者不缩小。

image

flex-basis

定义了在分配多余空间之前, 项目占据的主轴空间. 浏览器根据这个属性, 计算主轴是否有多余空间. 它的默认值为 auto, 即项目本来大小.

.item {
flex-basis: <length> | auto; /* default auto */
}

它可以设为跟 width 或 height 属性一样的值(比如 350px),则项目将占据固定空间。

flex

flex 属性是 flex-grow, flex-shrink 和 flex-basis 的简写,默认值为 0 1 auto。后两个属性可选。

.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

该属性有两个快捷值:

  • 1 (0 1 0%): 均匀分配元素
  • auto (1 1 auto): 自动放大和缩小
  • none (0 0 auto): 既不放大也不缩小

建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。

align-self

允许单个项目与其他项目不一样的对齐方法, 可以覆盖容器的align-item, 默认auto, 继承容器的align-items, 没有父元素时, 等于stretch.

.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

Grid 布局

Grid 将网页划分成一个个网格, 可以任意组合不同的网格. 与 Flex 具有一定的相似性, 但是 Flex 是轴线布局(一维布局), Grid 是网格布局(二维布局).

基本概念

容器和项目

采用网格布局的区域, 叫做容器, 内部采用网格定位的子元素, 称为“项目”.

行,列, 单元格

  • 水平居于为行(row)
  • 垂直区域为列(column)
  • 行和列的交叉区域, 叫单元格(cell)

网格线

grid line, 水平网格线划分行, 垂直网格线划分列.

image

容器属性

display:grid启用 grid 布局.

div {
display: grid;
}

效果如下:

image

默认情况下, 容器元素是块级元素, 当然也可以设为行内元素:

div {
display: inline-grid;
}

设置为网格布局以后, 项目的float,display: inline-block,display: table-cell,vertical-align,column-*都会失效

划分行/列

指定 Grid 布局之后, 就要定义每一列的列宽和行高:

.container {
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
}
  • grid-template-columns: 指定列宽
  • grid-template-rows: 指定行高

除了绝对单位, 可以使用百分比:

.container {
display: grid;
grid-template-columns: 33.33% 33.33% 33.33%;
grid-template-rows: 33.33% 33.33% 33.33%;
}
repeat()

可以使用repeat()函数简化写法:

.container {
display: grid;
grid-template-columns: repeat(3, 33.33%);
grid-template-rows: repeat(3, 33.33%);
}

该函数接受两个参数: 重复的次数, 重复的值

还可以重复某种模式:

grid-template-columns: repeat(2, 100px 20px 80px);
auto-fill

可以使用该关键子来自动以固定的数值填充满容器:

.container {
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
}

这段代码表示每列宽度 100px, 填充满容器.

fr

改关键字(fraction, 片段)表示倍数.

.container {
display: grid;
grid-template-columns: 1fr 2fr;
}

这段代码表示第二列是第一列的两倍.

可以与绝对长度结合起来使用:

.container {
display: grid;
grid-template-columns: 150px 1fr 2fr;
}
minmax()

该函数产生一个长度范围,表示长度就在这个范围之中。它接受两个参数,分别为最小值和最大值。

grid-template-columns: 1fr 1fr minmax(100px, 1fr);
auto

表示由浏览器自己决定长度:

grid-template-columns: 100px auto 100px;
网格线的名称

可以使用方括号指定网格线的名字, 方便以后的引用:

.container {
display: grid;
grid-template-columns: [c1] 100px [c2] 100px [c3] auto [c4];
grid-template-rows: [r1] 100px [r2] 100px [r3] auto [r4];
}

网格布局允许同一根线有多个名字,比如[fifth-line row-5]

两栏式布局
.wrapper {
display: grid;
grid-template-columns: 70% 30%;
}
12 网格布局
grid-template-columns: repeat(12, 1fr);

行/列间距

  • grid-row-gap: 设置行与行的间隔
  • grid-column-gap: 设置列与列的间隔
  • grid-gap: <grid-row-gap> <grid-column-gap>; 合并属性, 省略第二个值将被视为等于第一个值.
.container {
grid-row-gap: 20px;
grid-column-gap: 20px;
}

区域

grid-template-area: 指定区域, 一个区域有一个或者多个单元格组成:

.container {
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
grid-template-areas:
'a a c'
'a a f'
'g h i';
}

a 就是一个占据两行两列的区域.

可以用语义更明确的:

grid-template-areas:
'header header header'
'main main sidebar'
'footer footer footer';

或者用.来忽略某些语气:

grid-template-areas:
'a . c'
'd . f'
'g . i';

区域的命名会影响到网格线, 每个区域的起始网格线为区域名-start, 终止网格线自动命名为区域名-end

项目顺序

grid-auto-flow: 默认值为row, 即"先行后列", 也可以设为column, 变成"先列后行"

grid-auto-flow: column|row;

dense关键字表示尽量填满空格.

项目位置

  • justify-items:<start | end | center | stretch>:设置单元格内容的水平位置
  • align-items:<start | end | center | stretch>:设置单元格内容的垂直位置
  • place-items: <align-items> <justify-items>: 上面两个的合并形式,,如果省略第二个值,则浏览器认为与第一个值相等。

值说明:

  • start:对齐单元格的起始边缘。
  • end:对齐单元格的结束边缘。
  • center:单元格内部居中。
  • stretch:拉伸,占满单元格的整个宽度(默认值)。

容器位置

  • justify-content:<start | end | center | stretch | space-around | space-between | space-evenly>:整个内容区域在容器里面的水平位置
  • align-content:<start | end | center | stretch | space-around | space-between | space-evenly>: 整个内容区域的垂直位置
  • place-content:<align-content> <justify-content>:上面两个的合并形式,如果省略第二个值,则浏览器认为与第一个值相等。

自动生成的行/列

.container {
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
grid-auto-rows: 50px;
}

不指定这两个属性的话, 浏览器完全根据单元格的内容决定新增网格的列宽和行高

简写

  • 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属性:下边框所在的水平网格线

可以使用span关键字跨域网格:

grid-column-start: span 2;

跟下面的写法是一样的:

.item-1 {
grid-column-end: span 2;
}

如果项目产生重叠, 则使用z-inde属性指定的重叠顺序.

  • grid-column:<grid-column-start> / <grid-column-end>: 列左右的简写
  • grid-row: <grid-raw-start> / <grid-raw-end>: 行左右的简写

斜杠后面省略的话, 默认跨域一个网格

指定区域

.item-1 {
grid-area: e;
}

指定项目位于e区域.

还可以用作简写, 直接指定项目的位置:

.item {
grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
}

单元格位置

.item {
justify-self: start | end | center | stretch;
align-self: start | end | center | stretch;
}

跟容器中的用法一致, 只是作用于单个项目.

place-self类似于align-self, 同样的省略第二个值的情况下, 认为这两个值相等

常见的布局方案

单列布局

image

常见的单列布局有两种, 如图所示.

对于第一种, 可以这样写:

<div class="header"></div>
<div class="content"></div>
<div class="footer"></div>
.header {
margin: 0 auto;
max-width: 960px;
height: 100px;
background-color: blue;
}
.content {
margin: 0 auto;
max-width: 960px;
height: 400px;
background-color: aquamarine;
}
.footer {
margin: 0 auto;
max-width: 960px;
height: 100px;
background-color: aqua;
}

第二种与第一种的区别在上下栏铺满页面宽度

两列自适应布局

两列自适应布局是指一列由内容撑开,另一列撑满剩余宽度的布局方式

  1. float+overflow:hidden

普通的两列布局使用浮动+普通元素的 margin 就可以实现了, 但如果是自适应的两列布局, 利用 float+overflow:hidden 可以实现, 主要原理是被触发 BFC, 利用 BFC 不会重叠浮动元素的特性, 但是 overflow:hidden 不会触发 IE-6 的 haslayout 属性, 所以需要设置 zoom:1 来兼容 IE6.

<div class="parent" style="background-color: lightgrey;">
<div class="left" style="background-color: lightblue;">
<p>left</p>
</div>
<div class="right" style="background-color: lightgreen;">
<p>right</p>
<p>right</p>
</div>
</div>
.parent {
overflow: hidden;
zoom: 1;
}
.left {
float: left;
margin-right: 20px;
}
.right {
overflow: hidden;
zoom: 1;
}

注意点:如果侧边栏在右边时,注意渲染顺序。即在 HTML 中,先写侧边栏后写主内容

  1. flex 布局
.parent {
display: flex;
background-color: beige;
height: 100%;
}
.left {
width: 200px;
flex-shrink: 0;
background-color: cadetblue;
}
.right {
background-color: coral;
flex: 1;
}
  1. grid 布局
//html部分同上
.parent {
display: grid;
grid-template-columns: auto 1fr;
grid-gap: 20px;
}

三栏布局

中间列自适应宽度, 旁边两侧固定宽度

  1. 圣杯布局

比较特殊的三栏布局,同样也是两边固定宽度,中间自适应,唯一区别是 dom 结构必须是先写中间列部分,这样实现中间列可以优先加载。

.container {
padding-left: 220px; //为左右栏腾出空间
padding-right: 220px;
}
.left {
float: left;
width: 200px;
height: 400px;
background: red;
margin-left: -100%;
position: relative;
left: -220px;
}
.center {
float: left;
width: 100%;
height: 500px;
background: yellow;
}
.right {
float: left;
width: 200px;
height: 400px;
background: blue;
margin-left: -200px;
position: relative;
right: -220px;
}
<article class="container">
<div class="center">
<h2>圣杯布局</h2>
</div>
<div class="left"></div>
<div class="right"></div>
</article>

实现步骤:

  1. 三个部分都设定为左浮动,否则左右两边内容上不去,就不可能与中间列同一行。然后设置center的宽度为 100%(实现中间列内容自适应),此时,leftright部分会跳到下一行
  2. 通过设置margin-left为负值让leftright 部分回到与center部分同一行
  3. 通过设置父容器的padding-leftpadding-right, 让左右两边留出间隙.
  4. 通过设置相对定位,让leftright部分移动到两边.

这种布局的问题:

  • center 部分的最小宽度不能小于 left 部分的宽度, 否则 left 部分会掉到下一行
  • 如果其中一列内容高度拉长, 其他两列的背景并不会自动填充.
  1. 双飞翼布局

同样也是三栏布局, 在圣杯布局的基础上进一步优化, 解决了圣杯布局错乱问题, 实现内容与布局的分离, 而且任何一栏都可以是最高栏, 不会出现问题。

.container {
min-width: 600px; //确保中间内容可以显示出来,两倍left宽+right宽
}
.left {
float: left;
width: 200px;
height: 400px;
background: red;
margin-left: -100%;
}
.center {
float: left;
width: 100%;
height: 500px;
background: yellow;
}
.center .inner {
margin: 0 200px; //新增部分
}
.right {
float: left;
width: 200px;
height: 400px;
background: blue;
margin-left: -200px;
}
<article class="container">
<div class="center">
<div class="inner">双飞翼布局</div>
</div>
<div class="left"></div>
<div class="right"></div>
</article>

实现步骤:

  1. 前两步与圣杯布局一致
  2. 三个部分设定为左浮动, 然后设置 center 为 100%, 此时,left 和 right 部分会跳到下一行;
  3. 通过设置 margin-left 为负值让 left 和 right 部分回到与 center 部分同一行;
  4. center 部分增加一个内层 div,并设 margin: 0 200px;

缺点:

多了一层 DOM 树节点, 增加了渲染树生成的计算量

  1. 两种布局的对比
  • 两种布局方式都是把主列放在文档流最前面,使主列优先加载。
  • 两种布局方式在实现上也有相同之处,都是让三列浮动,然后通过负外边距形成三列布局。
  • 两种布局方式的不同之处在于如何处理中间主列的位置: 圣杯布局是利用父容器的左、右内边距+两个从列相对定位; 双飞翼布局是把主列嵌套在一个新的父级块中利用主列的左、右外边距进行布局调整

等高布局

等高布局是指子元素在父元素中高度相等的布局方式. 下面是几种实现方式:

  1. 正 padding+负 margin

我们通过等高布局可以解决圣杯布局的第二个缺点, 因为背景是在 padding 区域显示的, 设置一个大数值的 padding-bottom, 在设置相同数值的负的 margin-bottom, 并在所有列外面加上一个容器, 并设置 overflow:hidden 把移除背景切掉, 这种可能实现多列等高布局, 并且也能实现列与列之间分隔线效果, 结果简单, 兼容所有浏览器.

.center,
.left,
.right {
padding-bottom: 10000px;
margin-bottom: -10000px;
}
.container {
padding-left: 220px;
padding-right: 220px;
overflow: hidden; //把溢出背景切掉
}
  1. 模仿表格布局

这是一种非常简单,易于实现的方法。不过兼容性不好,在 ie6-7 无法正常运行。

<div class="container table">
<div class="containerInner tableRow">
<div class="column tableCell cell1">
<div class="left aside">
....
</div>
</div>
<div class="column tableCell cell2">
<div class="content section">
...
</div>
</div>
<div class="column tableCell cell3">
<div class="right aside">
...
</div>
</div>
</div>
</div>
.table {
width: auto;
min-width: 1000px;
margin: 0 auto;
padding: 0;
display: table;
}
.tableRow {
display: table-row;
}
.tableCell {
display: table-cell;
width: 33%;
}
.cell1 {
background: #f00;
height: 800px;
}
.cell2 {
background: #0f0;
}
.cell3 {
background: #00f;
}
  1. 使用边框和定位

这种方法是使用边框和绝对定位来实现一个假的高度相等列的效果。结构简单,兼容各浏览器,容易掌握。假设你需要实现一个两列等高布局,侧栏高度要和主内容高度相等。

#wrapper {
width: 960px;
margin: 0 auto;
}
#mainContent {
border-right: 220px solid #dfdfdf;
position: absolute;
width: 740px;
height: 800px;
background: green;
}
#sidebar {
background: #dfdfdf;
margin-left: 740px;
position: absolute;
height: 800px;
width: 220px;
}
<div id="wrapper">
<div id="mainContent">...</div>
<div id="sidebar">...</div>
</div>

粘连布局

特点:

  • 有一块内容<main>,当<main>的高康足够长的时候,紧跟在<main>后面的元素<footer>会跟在<main>元素的后面。
  • <main>元素比较短的时候(比如小于屏幕的高度),我们期望这个<footer>元素能够“粘连”在屏幕的底部

image

代码如下:

#wrap {
min-height: 100%;
background: rgb(43, 43, 43);
text-align: center;
overflow: hidden;
}
#wrap .main {
padding-bottom: 50px;
height: 100%;
}
#footer {
height: 50px;
line-height: 50px;
background: rgb(99, 122, 255);
text-align: center;
margin-top: -50px;
}
<div id="wrap">
<div class="main title">
MAIN
</div>
</div>
<div id="footer" class="title">FOOTER</div>

实现步骤:

  1. footer 是一个独立的机构, 与 wrap 没有嵌套关系
  2. wrap 的高度通过 min-height 设置为视口高度
  3. footer 使用 margin 设置负值来确定位置
  4. 在 main 区域设置 paddingbottom, 防止负的 margin 导致 footer 覆盖实际内容

栅格布局

上个系统就是利用浮动实现的多栏布局, 在 bootstrap 中使用的非常多. 下面是一个实例:

#container {
width: 100%;
margin: 0 auto;
height: 10%;
}

#container div {
height: 100%;
}

.col25 {
width: 25%;
background: rgb(95, 216, 95);
float: left;
}

.col50 {
width: 50%;
background: rgb(255, 87, 87);
float: left;
}

.col75 {
width: 75%;
background: rgb(128, 186, 240);
float: left;
}

html:

<div id="container">
<div class="col50 title">
A1
</div>
<div class="col50 title">
A2
</div>
<div class="col75 title">
B
</div>
<div class="col25 title">
C
</div>
<div class="col25 title">
D1
</div>
<div class="col25 title">
D1
</div>
<div class="col25 title">
D1
</div>
<div class="col25 title">
D1
</div>
</div>

参考链接