flex布局(弹性布局)
采用 Flex 布局的父元素叫容器(container) ,它的所有顶层子元素称为项目(items) 。
首先,需要将容器元素(父元素)class="container",项目元素(子元素)class="item"。并设置容器元素:
.container {
display: flex | inline-flex; 父元素是独占一行/行内排列
}
容器内存在两根轴:
- 主轴:水平,默认从左到右,项目默认沿主轴排列。
- 交叉轴:垂直,默认从上到下。
容器的属性
首先将container元素设置为flex布局
display: flex;
1. flex-direction 主轴方向
flex-direction: row | row-reverse | column | column-reverse;
row(默认值):主轴为水平,从左到右。row-reverse:主轴水平,从右往左。column:主轴垂直,从上到下。column-reverse:主轴垂直,从下到上。
2. flex-wrap:元素排不下,是否换行
flex-wrap: nowrap | wrap | wrap-reverse;
nowrap(默认):不换行,不断挤的更小,设置items的width也不好使了。wrap:换行,第一行在上方。wrap-reverse:换行,第一行在下方。
flex-flow :flex-direction 和 flex-wrap的合写,默认值为row nowrap。
flex-flow: <flex-direction> || <flex-wrap>;
3. justify-content:items 在主轴对齐方式
justify-content: flex-start | flex-end | center | space-between | space-around;
下面假设主轴为从左到右:
flex-start(默认值):左对齐,向主轴开始对齐flex-end:右对齐center: 居中space-between:两端对齐,项目之间的间隔都相等。space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
4. align-items:items 在交叉轴对齐方式
align-items: flex-start | flex-end | center | baseline | stretch;
下面假设交叉轴从上到下:
flex-start:交叉轴的起点对齐。flex-end:交叉轴的终点对齐。center:交叉轴的中点对齐。baseline: 项目的第一行文字的基线对齐。stretch(默认值):如果项目未设置高度时,将占满整个容器的高度。
5. align-content:items太多一行放不下,出现多行多轴线的对齐
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
flex-start:与交叉轴的起点对齐。flex-end:与交叉轴的终点对齐。center:与交叉轴的中点对齐。space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。stretch(默认值):轴线占满整个交叉轴。
items 属性
单独选中某个item:
.item:first-child { } /* 第一个item儿子 */
.item:nth-child(2) { } /* 第二个item儿子 */
.item:nth-child(3) { } /* 第三个item儿子 */
...
.item:last-child{ } /* 最后一个item儿子 */
1. order:items 排列顺序
项目的排列顺序,数值越小,排列越靠前,默认为0。-99~-1,0,1~99
2. flex-grow:items放大比例
默认为0,即如果存在剩余空间,也不放大,能有多小有多小。
.item {
flex-grow:1; /* 所有item同宽度铺满整个container */
}
若container容器的宽度设置为400px,三个items的放大比例为 1:2:1,那么三个items的实际占据为:100px,200px,100px。
.item:first-child {
width:100px;
flex-grow:1;
}
.item:nth-child(2) {
width:50px;
flex-grow:2;
}
.item:first-child {
width:50px;
flex-grow:1;
}
若三个items的放大比例为 1:1:1,那么三个items的实际占据比例为,设置的width+(400-100-50-50)/3
3. flex-shrink:items缩小比例
默认为1,(未设置宽度时)items会能缩多小缩多小。
.item {
flex-shrink:1; /* 当空间不足时,items 同比例缩小 */
}
如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。
.item:first-child {
flex-shrink:1;
}
.item:nth-child(2) {
flex-shrink:0; /* 不想变瘦 */
}
.item:first-child {
flex-shrink:1;
}
4. flex-basis:项目基准宽度
默认值为auto,即项目的本身设置的宽度。浏览器根据这个属性,计算主轴是否有多余空间。
一旦设定为某具体数值,项目的width属性失效。
.item1 {
width:100px;
flex-basis:auto; /* 项目宽度为设置的宽度100px */
}
.item2 {
width:100px; /* 失效 */
flex-basis:300px; /* 项目宽度为300px */
}
flex:是flex-grow, flex-shrink 和 flex-basis的合写,默认值为0 1 auto。后两个属性可选。
.item {
flex: 0 1 auto; /* 等同于写 flex:0; */
}
5. align-self :让单个项目有特殊的对齐方式
可覆盖align-items属性。默认值为auto,其余与align-items属性值一致。
align-self: auto | flex-start | flex-end | center | baseline | stretch(默认);
flex:1 与 flex:auto
flex: 1代表flex:1 1 0%基准宽度为0,items设置的width失效,items能够实现真正的均分flex: auto代表flex: 1 1 auto此时如果设置了items的width,items有可能不等分:宽度一部分要考虑设置width的宽度,还要考虑将多余的均分
左右两边固定距离,中间自适应的方法:两边元素设置固定宽度,中间元素flex-grow: 1
总结
- 布局:display: flex
- 流动方向:flex-direction: row / column
- 是否换行:flex-wrap: wrap
- 主轴如何对齐:justify-content: center / space-between
- 纵轴如何对齐:align-items: center
Grid布局——网格布局
flex需要按照横竖轴线来设置每个项目对齐方式,可以看作是一维布局。grid功能更加强大,将容器划分成"行"和"列",产生单元格,然后指定"项目所在"的单元格,可以看作是二维布局,首先明确以下概念:
- 容器:最外层的父元素。
- 项目:容器的顶层子元素,gird只对项目生效。
- 单元格cell:
n行和m列会产生n x m个单元格。 - 网格线grid line:
n行有n + 1根水平网格线,m列有m + 1根垂直网格线。
容器的属性
首先,设置容器元素为grid布局:
.container {
display: grid | inline-grid; 父元素是独占一行/行内排列
}
容器内存在两根轴:
grid-template-columns 列宽, grid-template-rows 行高
指定了一个三行三列的网格
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
或者使用百分比、repeat、fr份数、auto
grid-template-columns: 33.33% 33.33% 33.33%;
grid-template-rows: 33.33% 33.33% 33.33%;
grid-template-columns: repeat(3, 33.33%);
grid-template-columns: repeat(3, 100px 20px 80px); /* 6列,第一列和第四列的宽度为100px */
grid-template-columns: 1fr 1fr 1fr; /* 三等分 */
grid-template-columns: 150px 1fr 2fr;/* fr与绝对长度的单位结合使用,第一列的宽度为150像素,第二列的宽度是第三列的一半 */
grid-template-columns: 100px auto 100px; /*第二列的宽度,基本上等于该列单元格的最大宽度 */
grid-row-gap 行间距, grid-column-gap 列间距, grid-gap 合写
grid-row-gap: 20px;
grid-column-gap: 40px;
grid-gap: 20px 40px; /*先行后列 */
grid-template-areas 划分区域
划分出9个单元格,然后将其定名为a到i的九个区域:
grid-template-areas: 'a b c'
'd e f'
'g h i';
多个单元格合并成一个区域,将9个单元格分成header页眉、aside侧边、main主要内容、footer页脚四个区域:
grid-template-areas: "header header header"
"aside main aside"
"footer footer footer";
item属性
grid-column/row-start/end 指定项目所在网格
指定1号项目从左边第1根垂直网格线开始,右边第3根垂直网格线结束。
.item:first-child {
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 2;
grid-row-end: 4;
}
以上内容可合写成:
grid-column: 1 / 3;
grid-row: 2 / 4;
可再次合写成:
grid-area: 2 / 4 / 1 / 3;
也可用grid-area来指定1号项目位于main区域
.item:first-child {
grid-area: main;
}
定位
定位:快速精准地在脱离文档流束缚的情况下将元素放在你想放置的位置。就跟精确制导定位系统一样,输入坐标就可以轻松搞定。
定位分类
| 定位模式 | 是否脱标占有位置 | 是否可以使用边偏移 | 移动位置基准 |
|---|---|---|---|
| 静态定位static | 不脱标,正常模式 | × | 默认值 |
| 相对定位relative | 脱标,占有位置 | √ | 相对自己原来位置移动 |
| 绝对定位absolute | 完全脱标,不占有位置 | √ | 相对于相对定位父级移动位置 |
| 固定定位fixed | 完全脱标,不占有位置 | √ | 相对于视口viewport移动位置 |
注意
- 绝对定位是相对于相对定位父级,也就是从该元素向上找离的最近的一个position不为static的祖先,如果没有则相对于 viewport 定位。
sticky 粘性定位
基于滚动后的位置来定位。在 position:relative 与 position:fixed 定位之间切换,用作导航。
#one {
position: sticky;
top: 10px;
}
- 在 viewport 视口滚动到元素 top 距离小于 10px 之前,元素为相对定位。
- 而当页面滚动,使得viewport超出目标区域时,元素为固定定位,不再随着滚动条滚动,直到 viewport视口回滚到阈值以下。
- 指定 top, right, bottom 或 left 四个阈值其中之一,才可使粘性定位生效,否则其行为与相对定位相同。
层叠上下文——一个的小世界
在被一个父元素包裹着的层叠上下文中,俯视由上到下依次可以看见的是:
内联子元素 > 浮动元素 > 块级子元素 > 边框 > 背景
- 元素的z-index属性,默认为auto,计算出来的值约等于0。将定位元素(position不为static的元素)的z-index=1/2/....999就超越了最顶层的文字,z-index=-1/-2/...就落到了背景下面,只有这两种选择,不会在中间那些区域做夹层。
z-index作用域
每个处于自己的小世界里的z-index才有可比性:
- 如果a2、b2的z-index分别是10、5,那么a2盖住b2,因为他们同在container为祖先的小世界里。
- 如果给a的z-index是1,这时a与b2在container小世界里比较,1<5,所以b2盖住a2
<div class=container>
<div class="a">
<div class="a2">10</div>
</div>
<div class="b">
<div class="b2">5</div>
</div>
</div>
总结:有哪些属性可以创建层叠上下文?(z-index默认值是auto 不会创建层叠上下文的)
- 根元素(HTML)
- z-index值不为"auto",且:
- position值为absolute绝对定位或relative相对定位的元素
- flex的子元素
- grid的子元素
- position值为fixed或sticky的元素,z-index可为auto
- opacity属性值小于1的元素
- transform属性值不为"none"的元素
两栏布局
⼀般两栏布局指的是左边⼀栏宽度固定,右边⼀栏宽度自适应。
<body>
<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>
</body>
1 利用左浮动+右margin-left
左边元素宽度设置为200px,并且设置向左浮动。将右边元素的margin-left设置为200px,宽度设置为auto(默认为auto,撑满整个父元素)。
.container {
width:100%;
height:500px;
border:1px solid black;
}
.left {
width: 200px;
height:100%;
float:left;
background: tomato;
}
.right {
width: auto;
height:100%;
background: gold;
margin-left: 200px;
}
2 利用左浮动+右overflow:hidden
左边设置浮动,右边设置overflow:hidden就触发了BFC,BFC的区域不会与浮动元素发生重叠,所以两侧就不会发生重叠。
.left {
width: 200px;
height:100%;
float:left;
background: tomato;
}
.right {
width: auto;
height:100%;
background: gold;
overflow:hidden;
}
3 利用flex布局
将左边元素设置为固定宽度200px,将右边的元素设置为flex:1。
.container {
width:100%;
height:500px;
border:1px solid black;
display:flex;
}
.left {
width: 200px;
height:100%;
background: tomato;
}
.right {
height:100%;
background: gold;
flex:1;
}
4 左绝对定位+右margin-left
将⽗级元素设置为相对定位。左边元素设置为absolute定位。将右边元素的margin-left的值设置为200px。
.container {
width:100%;
height:500px;
border:1px solid black;
position:relative;
}
.left {
width: 200px;
height:100%;
background: tomato;
position:absolute;
top:0;
left:0;
}
.right {
height:100%;
background: gold;
margin-left:200px;
}
5 右绝对定位
.container {
width:100%;
height:500px;
border:1px solid black;
position:relative;
}
.left {
width: 200px;
height:100%;
background: tomato;
}
.right {
height:100%;
background: gold;
position:absolute;
top:0;
left:200px;
right:0;
bottom:0;
}
三栏布局
指的是页面中⼀共有三栏,左右两栏宽度固定,中间自适应的布局。
<body>
<div class="container">
<div class="left">左边</div>
<div class="main">中间</div>
<div class="right">哈哈</div>
</div>
</body>
1 flex布局
父元素设置display:flex;左右两侧固定宽度,中间flex:1
.container {
width:100%;
height:500px;
border:1px solid black;
display:flex;
}
.left {
width: 100px;
height:100%;
background: tomato;
}
.right {
width:100px;
height:100%;
background: gold;
}
.main {
height:100%;
background: orange;
flex:1;
}
2 左右绝对定位+中间margin-left/right
父元素设置为相对定位,左右两边设置为绝对定位,中间使用margin-left
.container {
width:100%;
height:500px;
border:1px solid black;
position:relative;
}
.left {
width: 100px;
height:100%;
background: tomato;
position:absolute;
}
.right {
width:100px;
height:100%;
background: gold;
position:absolute;
top:0;
right:0;
}
.main {
height:100%;
background: orange;
margin-left:100px;
}
水平垂直居中
让一个子元素在父元素内水平垂直居中
<body>
<div class="container">
<div class="item"></div>
</div>
</body>
1 flex布局
设置父元素的justify-content:center和align-items:center,去设置主轴/交叉轴的对齐方式
.container {
width:100%;
height:400px;
border:1px solid black;
display:flex;
justify-content:center;
align-items:center;
}
.item {
width:100px;
height:100px;
background:orange;
}
2 绝对定位+四马分尸+margin:auto
.container {
position:relative;
}
.item {
width:100px;
height:100px;
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
margin:auto;
}
3 绝对定位+margin-top/left:-50%
.container {
width:100%;
height:400px;
border:1px solid black;
position:relative;
}
.item {
width:100px;
height:100px;
background:orange;
position:absolute;
top:50%;
left:50%;
margin-top:-50px;
margin-left:-50px;
}
4 绝对定位+translate
.container {
position:relative;
}
.item {
width:100px;
height:100px;
position:absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);
}
外边距合并问题
1 父子上下外边距合并
在父div里面有子元素div1时,若父元素div在没有设置overflow:hidden或者是border属性,则父元素的margin-top = max(父元素设置的margin-top,子元素设置的margin-top)。
body {
background:pink;
}
.parent {
width:200px;
height:200px;
background:red;
margin-top:50px;
}
.son {
width:100px;
height:100px;
background:yellow;
margin-top:50px;
}
解决办法:
- 设置父元素的overflow属性为hidden。
- 设置父元素的border属性,如:border:1px solid red;
2 兄弟上下外边距合并
兄弟元素,不设置float和position:absolute时,上面兄弟的margin-bottom和下面兄弟的margin-top会合并为两者中的最大值。
<div class="parent">
<div class="son1_bfc">
<div class="son1"></div>
</div>
<div class="son2"></div>
</div>
.parent {
width:200px;
height:200px;
background:pink;
}
.son1 {
width:50px;
height:50px;
background:yellow;
margin-bottom:25px;
}
.son2 {
width:50px;
height:50px;
background:green;
margin-top:25px;
}
解决办法:给任何一个元素套一个父元素,触发bfc
.son1 {
float:left;
}
.son1_bfc {
overflow:hidden;
}