Flex 弹性布局
display: flex
弹性盒子,提供一种更加有效的方式来对一个容器中的子元素进行排列、对齐和分配空白空间。
父容器属性
属性名 | 默认值 | 说明 |
---|---|---|
flex-direction | row | 定义主轴方向,指定子元素在父容器中的从哪个方向排列 |
flex-wrap | nowrap | 指定子元素换行方式(唯一能改变交叉轴开始、结束方向的属性) |
flex-flow | row nowrap | flex-flow 是 flex-direction flex-wrap 的简写 |
justify-content | flex-start | 子元素沿着父容器的主轴(理解成row方向的X轴)的对齐方式 |
align-items | stretch | 子元素沿着父容器的交叉轴(理解成row方向的Y轴)的对齐方式 |
align-content | stretch | 设置了 flex-wrap 换行才生效,控制各行的对齐(多行交叉轴对齐) |
若子元素未设置高度或设为 auto
,stretch
属性值会使子元素的尺寸尽可能接近所在行的尺寸(撑满父元素),但同时会遵照 (min/max)-(width/height)
属性的限制。
弹性子元素属性
属性名 | 默认值 | 说明 |
---|---|---|
order | 0 | 定义排列顺序,数值小的排在前面。可以为负值 |
align-self | auto | 设置弹性元素自身在交叉轴方向上的对齐方式,可覆盖align-items属性值 |
flex-grow | 0 | 一般取值为数字,表示占分配父容器 剩余宽度(高度)的份数 |
flex-shrink | 1 | 子项目的宽度和(或者高度和)超过 flex 父容器的宽度,子项目会不会缩小 |
flex-basis | auto | 元素本身大小的基准值。可以是0,auto,百分比,像素值 |
flex | 0 1 auto | flex 是 flex-grow flex-shrink flex-basis 的简写 |
flex
搭配 margin: auto
可以做到很多其他的效果
例如:左边1个,右边两个,中间的给 margin-left: auto
,或者最左边的给 margin-right: auto
/* 下方示例的前置代码 */
/* css */
.container{
width: 550px;
height: 250px;
border: 5px solid silver;
display: flex;
}
.item{
width: 100px;
height: 100px;
}
.item:nth-child(1) {
background-color: green;
}
.item:nth-child(2) {
background-color: yellow;
}
.item:nth-child(3) {
background-color: pink;
}
.item:nth-child(4) {
background-color: purple;
}
/* html */
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
flex-grow
表示在主轴方向上,如果子项目的宽度和(或者高度和)并没有完全占满 flex 父容器的宽度,父容器剩余宽度将如何分配。flex-grow
默认是0,即不拉伸子容器,即使父容器没有被占满
.item:nth-child(1){
flex-grow: 1
}
.item:nth-child(2){
flex-grow: 2
}
.item:nth-child(3){
flex-grow: 2
}
表示如果父容器宽度还有剩余,则第一个元素占 1 份,第二个元素占 2 份,第三个元素占 2 份
// 结果
父元素剩余宽度:550 - 100 - 100 - 100 = 250
总份数:1 + 2 + 2 = 5
每份占的宽度:250 / 5 = 50
第一个子元素宽度:50*1 + 100 = 150
第二个子元素宽度:50*2 + 100 = 200
第三个子元素宽度:50*2 + 100 = 200
flex-shrink
表示在主轴方向上,如果子项目的宽度和(或者高度和)超过 flex 父容器的宽度,子项目会不会缩小。flex-shrink
默认为1,即如果空间不足,该项目将缩小。
.item{
width: 200px;
height: 100px;
}
.item:nth-child(1){
flex-shrink: 1
}
.item:nth-child(2){
flex-shrink: 2
}
.item:nth-child(3){
flex-shrink: 2
}
如果父容器被超过时,则第一个元素缩小占 1 份,第二个元素缩小占 2 份,第三个元素缩小占 2 份
// 结果
父元素超过的宽度:200 + 200 + 200 - 550 = 50
每份占的宽度:50/(200*1 + 200*2 + 200*2) = 0.05
第一个子元素宽度:200 - 1*0.05*200 = 190
第二个子元素宽度:200 - 2*0.05*200 = 180
第三个子元素宽度:200 - 2*0.05*200 = 180
flex-basis
控制项目本身的宽度,浏览器根据这个属性,计算主轴是否有多余空间
- 0:优先将内容项目会尽量占较小空间显示(本身元素能够渲染内容的最小宽度)
- 百分比:相对比父容器的大小
- auto:本身的原始大小显示
父容器无剩余空间时,需要设置 flex-shrink: 0
才有效
优先级: (min/max)-(width/height)
> flex-basis
> width
.item{
width: 200px;
height: 100px;
}
.item:nth-child(1){
flex-basis: 0;
}
.item:nth-child(2){
min-width: 100px;
flex-basis: 50px;
}
.item:nth-child(3){
flex-basis: auto;
}
flex属性
按照以往的经验,css
的属性只有一个值的时候,另外缺省的值应该使用默认值才对,但是 flex
属性并不是这样的。
flex
简写表示flex-grow flex-shrink fkex-basis
的组合写法,后两个属性值可选
简写值 | 实际值 | 备注 |
---|---|---|
flex: initial | flex: 0 1 auto | 初始值 |
flex: 1 | flex: 1 1 0% | 适合等分布局 |
flex: none | flex: 0 0 auto | 适用于不换行的内容固定 |
flex: 0 | flex: 0 1 0% | 使用较少 |
flex: auto | flex: 1 1 auto | 适合基于内容动态适配的布局 |
误区:以为 flex:1;flex:2;
可以按 1:2
比例分配项目;
实际:flex: n
只是在父容器确定有多余空间的时候才按照相应的比例分配,而不是元素本身的比例,元素本身的大小比例是通过 max-width
实现的
项目本身的宽度以及是否拉伸或者缩小要根据 (min/max)-width
、flex
、width
一起计算
/* flex + max-width 实现等比例栅格布局 */
.container {
display: flex;
}
.item {
flex:0 0 33.33333333%;
max-width: 33.33333333%;
}
Grid 网格布局
display: grid
网格布局,比较擅长将一个页面划分为几个主要区域,以及定义这些区域的大小、位置、层次等关系,是目前唯一一种 CSS
二维布局。
注意:某些时候可能需要加上一个 min-width: 0;
或者 overflow: hidden
例如:当父元素采用 flex
布局或 grid
布局时
- 防止父元素被无限撑开:父容器没设宽度的情况,父元素可能会被子节点无限撑开。通过设置
min-width: 0
,可以确保父元素中的子元素内容不会超出父元素容器。 - 解决
white-space: nowrap
导致的问题:有助于解决由于white-space: nowrap
导致的布局问题,确保元素不会因为内容过长而被撑开。
父容器属性
定义行、列
grid-template-columns
属性设置列宽,grid-template-rows
属性设置行高
固定列宽、行高
.contaienr {
display: grid;
/* 声明了三列,宽度分别为 200px 100px 200px */
grid-template-columns: 200px 100px 200px;
/* 声明了两行,行高分别为 50px 50px */
grid-template-rows: 50px 50px;
}
repeat
简化重复的值。该函数接受两个参数,第一个参数是重复的次数,第二个参数是所要重复的值。
.contaienr {
display: grid;
grid-template-columns: 200px 100px 200px;
/* 2行,而且行高都为 50px */
grid-template-rows: repeat(2, 50px);
}
auto-fill
自动填充,让一行(或者一列)中尽可能的容纳更多的单元格。
.contaienr {
display: grid;
/* 列宽是 200 px,但列的数量是不固定的,只要浏览器能够容纳得下,就可以放置元素 */
grid-template-columns: repeat(auto-fill, 200px);
grid-auto-rows: 50px;
}
fr
fr
单位代表网格容器中可用空间的一等份。
.contaienr {
display: grid;
/* 第一个列宽设置为 200px,后面剩余的宽度分为两部分,宽度分别为剩余宽度的 1/3 和 2/3 */
grid-template-columns: 200px 1fr 2fr;
grid-gap: 5px;
grid-auto-rows: 50px;
}
minmax
minmax()
函数产生一个长度范围,表示长度就在这个范围之中都可以应用到网格项目中。它接受两个参数,分别为最小值和最大值。
.contaienr {
display: grid;
/* 第三个列宽最少也是要 300px,但是最大不能大于第一第二列宽的两倍 */
grid-template-columns: 1fr 1fr minmax(300px, 2fr);
grid-gap: 5px;
grid-auto-rows: 50px;
}
auto
由浏览器决定长度
.contaienr {
display: grid;
/* 表示第一第三列为100px,中间自适应 (三栏布局) */
grid-template-columns: 100px auto 100px;
grid-gap: 5px;
grid-auto-rows: 50px;
}
gap间距
row-gap
属性、column-gap
属性分别设置行间距和列间距。 gap
属性是两者的简写形式。
.container {
display: grid;
row-gap: 10px;
column-gap: 20px;
/* 等同于 */
gap: 10px 20px;
}
定义渲染区域
grid-template-areas
属性用于定义区域,一个区域由一个或者多个单元格组成。
这个属性跟网格元素的 grid-area
一起使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
html,body {
width: 100%;
height: 100%;
}
.container {
display: grid;
height: 100vh;
grid-template-rows: 50px auto 50px;
grid-template-columns: 140px 1fr 1fr;
grid-template-areas:
"left top top"
"left middle middle"
"left footl footr";
}
.item:nth-child(1) {
grid-area: left;
background-color: red;
}
.item:nth-child(2) {
grid-area: top;
background-color: blue;
}
.item:nth-child(3) {
grid-area: middle;
background-color: yellow;
}
.item:nth-child(4) {
grid-area: footl;
background-color: orange;
}
.item:nth-child(5) {
grid-area: footr;
background-color: green;
}
</style>
</head>
<body>
<section>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
</div>
</section>
</body>
</html>
排列顺序
grid-auto-flow
属性控制着自动布局算法怎样运作,精确指定在网格中被自动布局的元素怎样排列。
row
:默认值,先行后列,左到右,即先填满第一行,再开始放入第二行。
row dense
:尽可能填满表格。中途有空位,后面的补上来
column
:先列后行,上到下
column dense
内容区域对齐方式
justify-content
属性是整个内容区域在容器里面的水平位置(左中右),align-content
属性是整个内容区域的垂直位置(上中下),类似 flex
的属性。
.container {
display: grid;
justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
align-content: start | end | center | stretch | space-around | space-between | space-evenly;
}
隐式网格
如果你在网格定义之外又放了一些东西,或者因为内容的数量而需要的更多网格轨道的时候,网格将会在隐式网格中创建行和列。
假如有多余的网格(也就是上面提到的隐式网格),那么它的行高和列宽可以根据 grid-auto-columns
属性和 grid-auto-rows
属性设置。
.wrapper {
display: grid;
grid-template-columns: 200px 100px;
grid-template-rows: 100px 100px;
/* 只设置了两行,但实际的数量超出了两行,超出的行高会以grid-auto-rows算 */
grid-auto-rows: 50px;
}
网格元素属性
grid-column / grid-row
grid-column
: 下面两个属性的简写方式grid-column-start
:左边框线grid-column-end
:右边框线
grid-row
:简写方式grid-row-start
:上边框线grid-row-end
:下边框线
下方示例中,.item
元素渲染位置是 列3 - 列4
,行2 - 行4
,所以是在右下角的位置。多个元素单元格占据同样的格子,可以通过 z-index
控制层级渲染关系。
grid-area
指定项目放在哪一个区域。看上方 父级容器属性 定义渲染区域示例;
Grid 解决空缺单元格问题
auto-fit
、minmax
、dense
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-gap: 10px 20px;
grid-auto-rows: 50px;
grid-auto-flow: row dense;
}
.item {
text-align: center;
font-size: 200%;
color: #fff;
}
.item:nth-child(1) {
background-color: #ff0000;
}
.item:nth-child(2) {
background-color: #00ff00;
}
.item:nth-child(3) {
background-color: #0000ff;
}
.item:nth-child(4) {
background-color: #ff00ff;
}
.item:nth-child(5) {
background-color: #ffff00;
}
.item:nth-child(6) {
background-color: #00ffff;
}
.item:nth-child(7) {
background-color: #2bff00;
}
.item:nth-child(8) {
background-color: #f56161;
}
.item:nth-child(9) {
background-color: #ae8cfc;
}
</style>
</head>
<body>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item" style="grid-column-start: span 3;">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item" style="grid-column-start: span 3;">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
</div>
</body>
</html>
小知识
css
单位
-
px
:像素,屏幕上显示的最小单位 -
rem
:相对单位, 相对于根元素字体大小的倍数 -
em
:相对单位,当前元素的字体大小的倍数,如果用于设置字体大小,则相对于父元素的字体大小 -
vw / vh
:相对单位,相对于浏览器可视区域窗口的宽高比 -
%
: 相对单位,相对于父容器的宽高比
选择器
优先级
!important
- 行内样式
Id
选择器- 类选择器、属性选择器、伪类
- 元素(标签)选择器,伪元素
同级选择器
# 选择h1的同级元素中的所有p标签
h1 ~ p {
color: blue;
}
奇数偶数选择器
li:nth-child(even) {
background-color: #f2f2f2;
}
li:nth-child(odd) {
background-color: #e6e6e6;
}
倍数选择器
/* 选择所有3的倍数元素 */
li:nth-child(3n) {
color: green;
}
/* 选择所有的5的倍数加3的元素 */
li:nth-child(5n+3) {
color: purple;
}
选中文字样式
::selection {
background-color: #ffcc00;
color: #333;
}
水平垂直居中方式
定位
.parent { position: relative; }
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
flex
.parent {
display: flex;
justify-content: center;
align-items: center;
}
grid
.parent {
display: grid;
justify-content: center;
align-items: center;
}
table
.parent {
display: table-cell;
text-align: center;
vertical-align: middle;
}
.child {
display: inline-block;
}
文字
.text {
text-align: center;
line-height: 父容器的高度
}
字体懒加载
使用 font-display: swap;
属性提高网页字体性能,让自定义字体加载时显示备用字体。
@font-face {
font-family: 'YourFont';
src: url('your-font.woff2') format('woff2');
font-display: swap;
}
像素
设备像素 / 物理像素(DP)
:物理屏幕上的实际像素,设备出场时就确定了,是固定不变的,每个设备像素代表显示器上的一个点。比如分辨率为1920 * 1080
的屏幕有1920
个水平像素和1080
个垂直像素。css
像素 :抽象单位,与设备无关(DIPs
),主要用于浏览器上,就是常用的px
。根据设备的屏幕分辨率和尺寸进行适配的,确保在不同设备上显示的一致性。DIP 设备独立像素
:是一种逻辑上的像素单位,在不同的设备上会映射到不同数量的物理像素,取决于设备,用于保证设计和应用的跨设备兼容性,例如CSS像素
。DPR 设备像素比
:DPR = DP / DIP
。高DPR
的设备能够以更精细的物理像素点来显示一个CSS像素点
,从而提供更清晰的显示效果。- 电脑端:
1dip
===1dp
,1px
就是一个像素点 (页面缩放比为1:1
) - 手机两倍屏:
1dip
===0.5dp
- 电脑端:
DPI像素密度
:衡量显示清晰度的一个主要参数,它表示每英寸所包含的像素点数。
浏览器渲染过程
- 解析
HTML
,生成DOM
树 - 解析
CSS
,生成CSSOM
树 - 将
DOM
树和CSSOM
树结合,生成渲染树Render Tree
- 从DOM树的根节点开始遍历每个可见节点,就是除了
display:none
的节点 - 对于每个可见的节点,找到
CSSOM
树中对应的内容,使用css
样式 - 组合生成渲染树
- 从DOM树的根节点开始遍历每个可见节点,就是除了
- 根据生成的渲染树,进行回流
Layout
运行布局,计算每个节点的几何图形,得到节点的几何信息(位置,大小) - 重绘
painting
,根据渲染树
以及 回流得到的几何信息,得到节点的绝对像素 GPU
将各个节点绘制到屏幕上
回流 / 重绘
- 回流
- 指的是浏览器必须重新计算元素的大小和位置等布局信息,并根据新的布局信息重新布局页面的过程
- 添加或删除可见的DOM元素
- 元素的位置发生变化
- 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
- 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
- 页面一开始渲染的时候(这肯定避免不了)
- 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
- 回流是一种相对耗费性能的操作,可能会导致全局的重新布局。
- 指的是浏览器必须重新计算元素的大小和位置等布局信息,并根据新的布局信息重新布局页面的过程
- 重绘
- 指的是浏览器对页面进行重新绘制的过程,这个过程是根据元素在页面上的显示位置、边框、背景等样式属性进行的
- 重绘则比较快捷,仅涉及到样式的变化,不会触及页面的布局信息。
注意:回流一定重绘,但是重绘不一定回流
属性 | ||
---|---|---|
display: none | 脱离文档流 | 回流,重绘 |
visibility: hidden | 占据文档流 | 重绘 |
opacity: 0 | 占据文档流 | 重绘,若是动画,则不发生回流重绘 |
position: absolute | 脱离文档流 | 回流,重绘 |
clip-path: circle(0%) | 占据文档流 | 重绘 |
减少回流重绘
-
style
样式操作使用class
切换 或者style.cssText
一次性替换 -
批量修改
DOM
时- 使元素脱离文档流 ,例如
display: none
,定位之类的 - 对其进行多次修改
- 将元素带回到文档中
- 使元素脱离文档流 ,例如
-
动画效果使用
绝对定位
, 脱离文档流 -
transform
、opacity
、filters
这些动画不会引起回流重绘
clip-path
clip-path
是裁剪属性,可以将元素裁剪为指定的形状,使得元素只显示裁剪区域的内容,隐藏裁剪外的元素。
clip-path: circle(0)
也可以做到隐藏元素。
裁剪工具网站: https://bennettfeely.com/clippy/
常用函数
/* 圆形:半径50%,x位置50%,y位置50% */
clip-path: circle(50% at 50% 50%);
/* 椭圆: x半径25%, y半径25%,位置同上 */
clip-path: ellipse(50% 25% at 50% 50%);
/* 多边形:每一组数据代表一个x,y坐标点 */
clip-path: polygon(25% 0%, 100% 25%, 75% 100%, 0% 75%);
/* 内嵌裁剪区域:上、右、下、左, 圆角效果,上右下左。 可以简写 */
clip-path: inset(20px 40px 60px 80px round 15px);
/* 定义任意形状(使用一个可选的 SVG 填充规则和一个 SVG 路径定义) */
clip-path: path('M 100 0 Q 200 100 Q 100 200, 0 100');
cubic-bezier
贝塞尔曲线
贝塞尔曲线是计算机图形学中一个非常有用的工具,它可以用来创建平滑的曲线,而不是直线,在 CSS
中可以使用贝塞尔曲线来 创建复杂的形状
,定义 动画的速度曲线
。
由四个点构成,只需要关注 P1
和 P2
两点的取值
P0:默认值 (0, 0)
P1:动态取值 (x1, y1)
P2:动态取值 (x2, y2)
P3:默认值 (1, 1)
最直接的理解是,将以一条直线放在范围只有 1 的坐标轴中,并从中间拿出两个点来拉扯(X 轴的取值区间是 [0, 1],Y 轴任意),最后形成的曲线就是动画的速度曲线。
语法:
cubic-bezier(x1,y1,x2,y2)
使用:
- X 轴的取值范围是
0 ~ 1
,当取值超出范围时cubic-bezier
将失效 - Y 轴的取值没有规定
transition-timing-function: cubic-bezier(0.1, 0.7, 1.0, 0.1);
调试网站: https://cubic-bezier.com/#.17,.67,.83,.67