CSS基础---了解CSS2.1以后的知识(2)

117 阅读1小时+

五、更丝滑的体验

(1)CSS渐变

==> 了解linear-gradient()线性渐变 <==

<== 渐变的两种方向表示 ==>

说明: 渐变的方向共有两种表示方法,一种是使用关键字to加方位值,另一种是直接使用角度值对于线性渐变来说,默认的方向就是从上到下的,如果没有其它的设置,那么to bottom的设置就是多余的,一般来说,to加方位值的适用范围更广

/* to bottom是多余的 */ 
linear-gradient(to bottom, white, skyblue);

/* 和上面写法的作用是一样的 */
linear-gradient(white, skyblue);

举例: 使用CSS渐变绘制两条对角线来表示没有数据的时候的占位效果,这里是使用to加方位值来表示方向的

img {
    width: 100px;
    height: 100px;
}

img:not([src]) {
    /* 此时,无论元素的尺寸是多少,对角线都有符合预期的表现 */
    background-color: #eee;
    background-image: linear-gradient(
        to right bottom,
        transparent calc(50% - 1px),
        #ccc calc(50% - 1px),
        #ccc,
        transparent calc(50% + 1px)
    ),
    linear-gradient(
        to top right,
        transparent calc(50% - 1px),
        #ccc calc(50% - 1px),
        #ccc,
        transparent calc(50% + 1px)
    );
}
<img />

image.png

注意: 对于角度所表示的方向,可以看这张图,也就是0deg表示向上,也就是to top,顺时针旋转是正角度,到90deg的时候就是表示向右,也就是to right,后面的方位可以以此类推了

image.png

<== 渐变的起点和终点 ==>

  • 如果是to加方位: 渐变的起点在元素的某一条边上或者某一个定点上面

  • 如果是角度: 过元素的中心点以这个角度作直线,然后元素的顶点向这条直线作垂线,此时就会存在交点,交点所产生越长的那条线段的两个顶点就是起点和终点,在直线上越靠后的那个点就是起点,另外一个点就是终点

举例:

.example {
    width: 300px;
    height: 150px;
    border: solid deepskyblue;
    background-image: linear-gradient(
        45deg,
        white 100px,
        skyblue 100px 200px,
        white 200px
    );
}
<div class="example" />

image.png

<== 渐变断点 ==>

说明: 比如需要一个红色到蓝色的渐变色,那么这里的红色和蓝色就是渐变断点,对于渐变断点,需要注意以下内容

  • 渐变断点至少有2个颜色值

  • 断点语法中的颜色值和位置值的前后顺序是有要求的,位置值必须在颜色值的后面

  • 没有指定具体断点位置的时候,各个渐变颜色所形成的色块大小是自动等分

  • 如果起点和终点的颜色与相邻断点的颜色值一样,则起点色值和终点色值是可以省略

  • 渐变的断点位置可以是负数,也可以大于100%

  • 在同一个渐变中,不同类型的断点位置值是可以同时使用的

  • 当存在多个渐变断点的时候,前面的渐变断点设置的位置值有时候比后面的渐变断点设置的位置值要大,这时后面的渐变断点位置值会按照前面的断点位置值计算

  • 渐变断点还支持同时设置两个位置值

  • 除渐变断点之外,还可以设置颜色的转换点位置

  • 如果不是高清显示器,则在Chrome浏览器中,不同颜色位于同一断点位置的时候,两个颜色连接处可能会有明显的锯齿

/* 1.不合法,断点最少需要两个颜色值 */ 
linear-gradient(white);

/* 2.不合法,颜色值和位置值存在顺序要求 */ 
linear-gradient(white, 50% skyblue);

/* 3.这4种颜色形成了3个渐变色块,也就是这两种写法等价 */
linear-gradient(red, orange, yellow, green);
linear-gradient(red 0%, orange 33.33%, yellow 66.66%, green 100%);

/* 4.25%~75%的渐变效果,这两种写法等价 */
linear-gradient(white, white 25%, skyblue 75%, skyblue);
linear-gradient(white 25%, skyblue 75%);

/* 5.断点位置可以小于0,可以大于100% */
linear-gradient(white -50%, skyblue, white 110%);

/* 6.断点位置可以使用不同的值类型 */
linear-gradient(white 100px, skyblue 50%);

/* 7.如果后面位置值比前面的小,则会按照前面的位置值进行渲染,因此 */
/* 这两种渲染的效果一致 */
linear-gradient(skyblue 20px, white 0px, skyblue 40px);
linear-gradient(skyblue 20px, white 20px, skyblue 40px);

/* 8.一次设置两个值,这里表示40%~60%这个范围内的颜色都是天蓝色 */
linear-gradient(white 40%, skyblue 40% 60%, white 50%);

/* 9.表示白色和天蓝色渐变的中心转换点位置在70%这里 */
linear-gradient(white, 70%, skyblue);

==> 了解radial-gradient()径向渐变 <==

<== 基础语法 ==>

说明: 径向渐变的方向是由中心往外部的,默认终止于元素的边框内边缘,其次所有径向渐变语法都是围绕改变径向渐变的半径值、中心点坐标,以及渐变颜色的起点和终点位置展开的

.example {
    width: 300px;
    height: 150px;
    background-image: radial-gradient(white, deepskyblue);
}
<div class="example" />

image.png

<== 设置渐变半径 ==>

说明: 这里的半径同样有水平和垂直之分,如果需要更改半径,将它们作为第一个参数就可以,如果水平和垂直的半径设置是一样的,则可以简写为一个,简写的时候只能只用长度值,不能够使用百分比

/* 简写的时候百分比不合法 */
radial-gradient(50%, white, deepskyblue);

/* 简写只能使用长度值,此外这两种写法是等价的 */
radial-gradient(50px, white, deepskyblue);
radial-gradient(50px 50px, white, deepskyblue);

<== 设置渐变中心点 ==>

说明: 可以使用at加上方位关键字或者坐标点的形式进行中心点的更改

/* 渐变的中心点在左上角 */
radial-gradient(100px at 0 0, white, deepskyblue); 
radial-gradient(100px at left top, white, deepskyblue);

/* 渐变的中心点在距离右边缘和下边缘100px的位置 */
radial-gradient(100px at right 100px bottom 100px, white, deepskyblue);

image.png

image.png

<== 设置渐变终止点 ==>

说明: 如果渐变的中心点不在元素的中心位置,又希望渐变的结束位置在元素的某一侧边缘或某一个边角,此时可以使用过四个关键字来完成效果,如下

关键字描述
closest-side渐变中心距离容器最近的边作为终止位置
closest-corner渐变中心距离容器最近的角作为终止位置
farthest-side渐变中心距离容器最远的边作为终止位置
farthest-corner默认值。渐变中心距离容器最远的角作为终止位置

image.png

举例:

radial-gradient(farthest-corner circle at right 100px bottom 100px, white, deepskyblue);

image.png

解释: 这里存在关键字circle,表示渐变的形状是一个圆,与之对应的关键字ellipse表示椭圆,由于径向渐变默认的形状就是椭圆,因此这个关键字是用不到的,此外circle关键字必须要出现的场景也不多,一般是结合上面的四个关键字一起出现

<== 语法细节 ==>

  • 出现了circle关键字,后面的值只能是长度值,不能是百分比值

  • circle关键字和ellipse关键字在与设置渐变终止点的四个关键字一起用的时候,是没有顺序而言的,谁前谁后都可以

  • 改变中心点的位置是固定的,必须在半径值的后面、渐变断点的前面

/* 这些设置的效果都是一样的 */
radial-gradient(white, deepskyblue);
radial-gradient(ellipse, white, deepskyblue);
radial-gradient(farthest-corner, white, deepskyblue);
radial-gradient(ellipse farthest-corner, white, deepskyblue);
radial-gradient(at center, white, deepskyblue);
radial-gradient(ellipse at center, white, deepskyblue);
radial-gradient(farthest-corner at center, white, deepskyblue);
radial-gradient(ellipse farthest-corner at center, white,deepskyblue);

<== 简单应用 ==>

各色各样的按钮:

button {
    height: 40px;
    border: none;
    padding: 0 20px;
    background-color: #2a80eb;
    color: #fff;
    border-radius: 4px;
    outline: none;
}

.button-a {
    background-image: radial-gradient(
        farthest-side at bottom left,
        rgba(255, 0, 255, 0.5),
        transparent
    ),
    radial-gradient(
        farthest-corner at bottom right,
        rgba(255, 255, 50, 0.5),
        transparent
    );
}

.button-a:active {
    box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.1);
}

.button-b {
    background-image: radial-gradient(
        160% 100% at 50% 0%,
        hsla(0, 0%, 100%, 0.3) 50%,
        hsla(0, 0%, 100%, 0) 52%
    );
}

.button-b:active {
    background-image: radial-gradient(
        160% 100% at 50% 0%,
        hsla(0, 0%, 100%, 0.2) 50%,
        hsla(0, 0%, 100%, 0) 52%
    );
}

.button-c {
    background-image: radial-gradient(
        closest-side circle,
        rgba(255, 70, 70, 0.9),
        rgba(255, 70, 70, 0.9) 99%,
        rgba(255, 70, 70, 0) 100%
    );
    background-repeat: no-repeat;
    background-position: center;
    background-size: 0% 0%;
    transition: all 0.2s;
}

.button-c:active {
    background-size: 250% 250%;
}
<p><button class="button-a">炫彩按钮</button></p>
<p><button class="button-b">高光按钮</button></p>
<p><button class="button-c">点击我</button></p>

image.png

波形效果:

.radial-wave {
    width: 200px;
    height: 100px;
    background: linear-gradient(to top, transparent 10px, red 10px)
        no-repeat,
        radial-gradient(
        20px 15px at left 50% bottom 10px,
        red 10px,
        transparent 11px
    );
    background-size: auto, 20px 10px;
}
<div class="radial-wave"></div>

image.png

==> 了解conic-gradient()锥形渐变 <==

<== 基础语法 ==>

说明: 锥形渐变由起始角度、中心位置和角渐变断点三部分组成,其中前两部分的默认值是0deg和元素的中心,因此可以省略,从下面这个例子中可以得到渲染的关键要素,如图

.example {
    width: 300px;
    height: 150px;
    background-image: conic-gradient(white, deepskyblue);
}

image.png

image.png

改变起始角度和中心位置: 渐变起始角度改成45度,中心点位置移动到了相对元素左上角25%的位置

.example {
    background-image:conic-gradient(from 45deg at 25% 25%, white, deepskyblue);
}

image.png

注意: 对于渐变断点,锥形渐变不支持长度值,只支持角度值,这个角度值是一个相对角度值,最终渲染的角度值是设置的角度值和起始角度累加的值,其次100%就相当于360deg,这两个单位之间是可以相互转化的

/* 这两个的区别只是更改了起始的角度值而已 */
conic-gradient(white, deepskyblue 45deg, white);
conic-gradient(from 45deg, white, deepskyblue 45deg, white);

image.png

image.png

<== 实现饼状图效果 ==>

.pie {
    width: 150px;
    height: 150px;
    border-radius: 50%;
    /* 这里需要结合前面的语法细节第七第八点来理解 */
    /* 小技巧:如果我们想要A、B两种渐变颜色界限分明,设置B颜色的起始位置值为0%就行 */
    background: conic-gradient(
        yellowgreen 40%,
        gold 0deg 75%,
        deepskyblue 0deg
    );
}

image.png

<== 取色盘效果 ==>

.hs-wheel {
    width: 150px;
    height: 150px;
    border-radius: 50%;
    background: radial-gradient(closest-side, gray, transparent),
                conic-gradient(red, magenta, blue, aqua, lime, yellow, red);
}

image.png

<== 加载效果 ==>

/* 使用CSS遮罩属性只让外圈25%的范围显示,于是loading的圆环效果就出现了 */
.loading {
    width: 100px;
    height: 100px;
    border-radius: 50%;
    background: conic-gradient(deepskyblue, 30%, white);
    --mask: radial-gradient(closest-side, transparent 75%, black 76%);
    -webkit-mask-image: var(--mask);
    mask-image: var(--mask);
    animation: spin 1s linear infinite reverse;
}

@keyframes spin {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}

image.png

==> 重复渐变 <==

说明: 线性渐变、径向渐变和锥形渐变都有对应的重复渐变函数,就是在各自的函数名前面添加repeating-前缀,语法和非重复渐变是一样的,区别在于对于重复渐变起始颜色位置需要明确

.stripe-border {
    width: 150px;
    height: 200px;
    border: 20px solid;
    border-image: repeating-linear-gradient(
        135deg,
        deepskyblue 0 6px,
        white 7px 12px
    ) 20;
}

image.png

(2)CSS的3D变换

3D坐标轴: 跟高中的空间直角坐标系的区别在于y轴和z轴要换一下

image.png

注意: 3D变换能够开启GPU加速,从而使变换效果性能要更高,但是单纯的2D变换请一定使用2D变换函数,没有任何理由需要使用3D变换函数,因为此时让GPU加速是一种糟糕的做法

==> 了解rotate3d()函数 <==

语法:

rotate3d(x, y, z, angle)

理解: 参数x、y、z分别表示旋转向量的x轴、y轴、z轴的坐标。参数angle表示围绕该旋转向量旋转的角度值,如果为正,则顺时针方向旋转;如果为负,则逆时针方向旋转,这里的向量指的是以坐标原点为起点,过坐标(x,y,z)的一条直线而已,所谓3D旋转就是元素绕着这条直线旋转

举例:

/* 元素绕着坐标(0, 0, 0)和坐标(1, 1, 1)连成的向量线旋转45度 */
transform:rotate3d(1, 1, 1, 45deg);

image.png

==> 透视perspective属性 <==

说明: 透视属性的存在决定你看到的效果是二维还是三维的,这里存在一个名词叫做透视点,简单来说就是通过这个点去看元素你会看到元素的3D版本的效果,不过在CSS中这个点在显示器的前面,看下面的例子就明白了

举例: 显示器宽度是1680px,浏览器中 有一个img元素设置了下面的CSS代码

img { 
    perspective: 2000px;
}

解释: 这就意味着这张图片的3D视觉效果和本人在距离1.2个显示器宽度远的地方(1680×1.2≈2000)所看到的真实效果是一致的

image.png

==> 理解透视点的translateZ() <==

说明: 都知道近大远小的理论,而translateZ()函数可以控制元素在视觉上的远近距离,从而可以用这个函数来理解透视点

举例:

/* 设置透视点的位置 */
.container { 
    perspective: 201px;
}

理解:

  • 子元素设置的translateZ()函数值越小,则子元素的视觉大小越小,因为子元素在视觉上远去,我们眼睛看到的子元素的视觉尺寸就会变小

  • 子元素设置的translateZ()函数值越大,该元素的视觉大小也会越大,因为元素在视觉上越近,看上去也就越大

  • 当子元素设置的translateZ()函数值非常接近201像素,但是不超过201像素的时候(如200像素),该元素就会撑满整个屏幕 (如果父元素没有类似overflow:hidden的限制的话)。因为这个时候,子元素正好移到了你的眼睛前面,看起来非常大,所谓“一叶障目,不见泰山”,就是这么回事

  • 当子元素设置的translateZ()函数值再变大,即超过201像素的时候,就看不见该元素了——这很好理解,我们是看不见眼睛后面的东西的

image.png

==> 透视点的两种写法 <==

说明: 一种设置在3D渲染元素的共同父元素上;另一种是设置在当前3D渲染元素上,与transform其他变换属性值写在一起,如果舞台上只有一个元素,那么其看到的效果是一样的,如果存在多个元素,则效果存在差别,看下面的例子

.stage {
    display: flex;
    height: 150px;
    width: 600px;
    max-width: calc(100% - 2rem);
    border: 1px solid darkgray;
}

.box {
    height: 100%;
    flex: 1;
    opacity: 0.75;
}

.darkblue {
    perspective: 600px;
}

.darkblue .box {
    background-color: darkblue;
    transform: rotateY(45deg);
}

.darkred .box {
    background-color: darkred;
    transform: perspective(600px) rotateY(45deg);
}
<div>透视设置在舞台元素上:</div>
<section class="stage darkblue">
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
</section>

<div>透视设置在自己的身上:</div>
<section class="stage darkred">
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
</section>

image.png

解释: 第一种就是我们看到的每个子元素都共用同一个透视点,因此每一个子元素的视觉形状都不一样,这个效果比较符合现实世界的3D透视效果,比如你的视线前方有一排人,远处的人只能被看到侧脸,近处的人可以被看到正脸。而第二种中的每个子元素都有一个自己独立的透视点,加上旋转的角度又是一样的,因此每个元素看上去也就一模一样了。

==> 理解perspective-origin属性 <==

说明: 这个属性的作用可以理解为改变眼睛的位置,从而不同的位置就会看到不同的效果,从而改变元素的3D渲染效果,它的语法跟background-position的语法是一致的,因为它支持<positon>数据类型

注意: perspective-origin属性初始值是50% 50%,表示默认的透视点是舞台或元素的中心。但是有时候,需要让变换的元素不在舞台的中心,或让透视角度偏上或者偏下,此时就可以通过设置 perspective-origin属性值实现

image.png

==> transform-style属性 <==

说明: 这个属性支持两个属性值,分别是preserve-3d和flat,在使用的时候,transform-style属性需要用在3D变换元素的父元素上,也就是舞台元素上才有效果

  • preserve-3d: 表示应用3D变换的元素位于三维空间中, preserve-3d属性值的渲染表现更符合真实世界的3D表现

  • flat: 默认值,表示应用3D变换的元素位于舞台或元素的平面中,把三维空间压缩在舞台元素的二维空间中

.stage {
    display: inline-block;
    width: 150px;
    height: 150px;
    background-color: rgba(0, 191, 255, 0.75);
    perspective: 600px;
}

.box {
    height: 100%;
    opacity: 0.75;
    background-color: darkred;
    transform: rotateY(45deg);
}

.preserve-3d {
    transform-style: preserve-3d;
}
<section class="stage preserve-3d">
    <div class="box"></div>
</section>

<section class="stage">
    <div class="box"></div>
</section>

image.png

解释: 第一种有部分区域藏到了舞台元素的后面,因为此时整个舞台按照真实的三维空间渲染,自然看不到旋转到后面的图形区域,第二种因为3D效果都会被渲染在舞台元素所在的二维平面之上,所以没有视觉上的穿透效果,因此旋转到后面的图形一样可以被看见

==> backface-visibility属性 <==

说明: 当一个元素绕z轴旋转的时候,它不就会存在正面和反面嘛,有时候不想看到它的反面,比如翻转的扑克牌效果,如果看到反面就是看到花纹了,但是这个扑克牌效果需要正面和反面都能看见扑克牌,因此需要将背面隐藏起来,然后使用其它元素来摸你,从而完成3D扑克牌翻转效果,此时控制扑克牌的背面不显示的CSS属性就是backface-visibility,它接收两个属性值,一个是visible,一个是hidden

  • visible: 默认值,元素翻转时背面是可见的
  • hidden: 元素翻转时 背面是不可见的
<section class="stage backface-hidden">
    <div class="box"></div>
    <div class="box"></div>
</section>

<section class="stage">
    <div class="box"></div>
    <div class="box"></div>
</section>
.stage {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: 1px solid darkgray;
    perspective: 600px;
    transform-style: preserve-3d;
}

.box {
    width: inherit;
    height: inherit;
    opacity: 0.75;
    background-color: darkred;
    transform: rotateY(225deg);
}

.box:first-child {
    transform: rotateY(45deg);
    background-color: darkblue;
    position: absolute;
}

.backface-hidden .box {
    backface-visibility: hidden;
}

image.png

==> 理解跑马灯效果 <==

.stage {
    /* 设置视距 */
    perspective: 800px;
    padding: 50px 400px;
}

.container {
    /* 添加3D视图声明 */
    transform-style: preserve-3d;
    width: 128px;
    height: 90px;
    /* 从0开始旋转 */
    transform: rotateY(0deg);
    /* 增加过渡 */
    transition: transform 1s;
}

.piece {
    width: inherit;
    height: inherit;
    position: absolute;
    /* 设置图片从那个角度开始旋转,这里也就是每张图片比前一张多旋转40° */
    /* translateZ就是让原本挤在一起的图片向它面对的那个方向远去,起到散开的作用 */
    transform: rotateY(calc(var(--index) * 40deg)) translateZ(195.839px);
    box-shadow: 0 0 transparent;
}
<!-- 舞台 -->
<div class="stage">
    <!-- 容器 -->
    <div class="container">
        <!-- 内容 -->
        <img class="piece" src="D:1.jpg" style="--index: 0" />
        <img class="piece" src="D:1.jpg" style="--index: 1" />
        <img class="piece" src="D:1.jpg" style="--index: 2" />
        <img class="piece" src="D:1.jpg" style="--index: 3" />
        <img class="piece" src="D:1.jpg" style="--index: 4" />
        <img class="piece" src="D:1.jpg" style="--index: 5" />
        <img class="piece" src="D:1.jpg" style="--index: 6" />
        <img class="piece" src="D:1.jpg" style="--index: 7" />
        <img class="piece" src="D:1.jpg" style="--index: 8" />
    </div>
</div>
let container = document.querySelector(".container");
container.onclick = function () {
    var index = (this.index || 0) + 1;
    this.style.transform = "rotateY(" + index * 40 + "deg)";
    this.index = index;
};

image.png

image.png

(3)CSS过渡

说明: 使用transition属性可以实现元素A状态到B状态的过渡效果,经常使用:hover伪类或者:active伪类触发。

==> 了解不知道的transition属性 <==

说明: transition属性是一个缩写属性,它是transition-duration、transition-delay、transition-property、transition-timing-function这4个CSS属性的缩写,然后了解一下这些CSS属性的细节

<== transition-duration属性 ==>

说明: 这个属性表示过渡时间,它可以是0,但是不可以为负数,一般情况下,transition属性的前两个值是不可以换位置的,也就是过渡时间和延迟时间,但是如果延迟时间是负数,则二者是可以交换位置的,因为过渡时间是不可以为负数,这个负数只能表示延迟时间

/* 效果一样,都表示过渡时间2s,延迟时间为-1s */
transition: 2s -1s;
transition: -1s 2s;

<== transition-delay属性 ==>

说明: 用来指定过渡效果延迟多久才执行,单位是s或者ms,它可以存在负值,当延迟的值为负的时候,会省略部分动画的进程,因为最终过渡的时间是等于动画过程时间加上动画延迟时间的,比如我过渡时间设置为1s,延迟时间为-0.5s,那么总的过渡时间就只有0.5s了,假设这段时间需要从0px的位置位移到100px的位置,由于前面0.5s是省略的,它会从后面0.5s开始运动,因此会从50px的位置开始位移,也就是运动的速度是不变的

举例: 使用:hover伪类实现的浮层是一种很常见的交互效果,传统的效果都是鼠标指针一旦经过元素,浮层立即出现,这个增加了用户如果误触会带来浮层一直在显示和隐藏中切换,体验不好,此时可以通过延迟来进行优化

.target + img {
    display: block;
    width: 256px;
    position: absolute;
    transition-delay: 0.2s;
    visibility: hidden;
}

.target:hover + img,
.target:focus + img {
    visibility: visible;
}
<a href class="target">显示图片</a>
<img src="D:1.jpg" />

image.png

<== transition-property属性 ==>

说明: 用于指定哪些属性需要过渡,默认值是all;对于显示隐藏的时候,使用visibility属性,因为display属性不支持过渡;其次就是对于指定的CSS属性,是不需要它是合法的,但是这些属性不能够以数字或者引号开头,这种属性是不支持的

/* 多余的all属性值 */
transition: all .2s;

/* 可以省略all */
transition: .2s;

注意: 如果过渡的属性与过渡的时间的个数对不上,则进行有缺则补,多之则除;当然,也可以进行简写,每一组之间使用逗号隔开就好

div {
    transition-property: opacity, left, top;
    transition-duration: 3s, 5s;
}
div {
    transition-property: opacity, left, top, height;
    transition-duration: 3s, 5s;
}

/* 上下两组是等价的 */
div {
    transition-property: opacity, left, top;
    transition-duration: 3s, 5s, 3s;
}
div {
    transition-property: opacity, left, top, height;
    transition-duration: 3s, 5s, 3s, 5s;
}
div {
    transition-property: opacity, left;
    transition-duration: 3s, 5s, 2s, 1s;
}

/* 这两组也是等价的 */
div {
    transition-property: opacity, left;
    transition-duration: 3s, 5s;
}
/* 简写,逗号隔开 */
transition: opacity .2s, transform .5s;

<== transition-timing-function属性 ==>

说明: 通过设置过渡时间函数来影响过渡效果的过渡速率,它支持以下三类属性值

  • 线性运动类型: linear

  • 三次贝塞尔时间函数类型:ease、ease-in、ease-out、 ease-in-out等关键字和cubic-bezier()函数

  • 步进时间函数类型:step-start、step-start等关键字和steps()函数

==> 了解三次贝塞尔时间函数类型 <==

<== 常用运动函数关键字 ==>

ease: 等同于cubic-bezier(0.25, 0.1, 0.25, 1.0),是transition-timing-function属性的默认值,表示过渡的时候先加速再减速

image.png

ease-in: 等同于cubic-bezier(0.42, 0, 1.0, 1.0),表示过渡速度刚开始慢,然后过渡速度逐渐加快

image.png

ease-out: 等同于cubic-bezier(0, 0, 0.58, 1.0),表示过渡刚开始速度快,然后速度逐渐变慢

image.png

ease-in-out: 等同于cubic-bezier(0.42, 0, 0.58, 1.0),表示过渡刚开始速度慢,然后速度逐渐加快,最后再变慢

image.png

<== 三次方贝塞尔曲线函数 ==>

说明: 这个指的是cubic-bezier()函数,三次方贝塞尔曲线由起点、终点和两个控制点组成,在CSS中,起点和终点的位置是确定的,分别表示(0,0)和(1,1),因此这个函数的参数只有四个,就是两个控制点的坐标,前两个参数表示起点控制点的坐标,后两个表示终点控制点的坐标,对于曲线的绘制可以在这个网站上操作

语法:

cubic-bezier(x1, y1, x2, y2)

注意: 在早期的时候,这四个参数的值是在0-1之间的,超过1会被认为是不合法的,不过现在可以,当超过的时候,会先到那个位置,后面再回到1这里,也就是存在一个回弹效果

==> 过渡与隐藏案例 <==

举例: 浮层的淡入淡出的效果

<button>点击出现浮层</button>
<div id="popup" class="popup">
    <div class="content">底部浮层</div>
</div>
.popup {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    top: 0;
    z-index: 19;
    background: rgba(0, 0, 0, 0.5);
    overflow: hidden;
    /* 实现淡入淡出的效果 */
    opacity: 0;
    transition: opacity 0.2s, visibility 0.2s;
    /* 不使用opacity:0是因为虽然浮层元素不可见,但是浮层元素依然覆盖在页面上,影响正常的交互 */
    /* 不使用display:none是因为其不支持过渡效果 */
    visibility: hidden;
}

.content {
    line-height: 100px;
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #fff;
    /* 控制底部浮层的移入移出 */
    transform: translateY(100%);
    transition: transform 0.2s;
}

/* 通过切换“active”类名实现交互效果 */
.popup.active {
    transition-property: opacity;
    opacity: 1;
    visibility: visible;
}

.active > .content {
    transform: translateY(0%);
}
let button = document.querySelector("button");
let popup = document.getElementById("popup");

button.onclick = function () {
    popup.classList.add("active");
};

popup.onclick = function () {
    this.classList.remove("active");
};

(4)CSS动画

==> 初始动画 <==

举例: 常用的淡出动画效果

/* 使用的时候将这个class放在某一个元素上面那个元素在0.25s里面会从隐藏到显示 */
.fade-in {
    /* 在执行动画的时候需要使用animation属性,后面跟执行的动画名称 */
    /* 以及动画的执行一次的时间 */
    animation: fadeIn 0.25s;
}

/* @keyframes规则用来定义动画的关键帧 */
/* fadeIn表示定义的动画名称 */
@keyframes fadeIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

理解: 因此可以知道一个CSS动画效果要想出现,动画名称、动画时间、animation属性和@keyframes规则是必不可少的基本单元

==> 了解animation属性 <==

说明: 这个一样是多个CSS属性的缩写,分别是animation-name、animation- duration、animation-timing-function、animation-delay、animation-iteration-count、animation-direction、animation-fill-mode和animation-play-state

举例: 实现元素淡出和右侧划入同时进行的动画效果

/*不推荐这种写法,因为不方便复用动画*/
.element {
    animation: fadeInSlideInRight 0.2s;
}

@keyframes fadeInSlideInRight {
    from {
        opacity: 0;
        transform: translateX(100%);
    }
    to {
        opacity: 1;
        transform: translateX (0%);
    }
}
/* 这样做的好处在于我们自定义的动画规则可以在其他场合重复利用 */
.element {
    animation: fadeIn 0.2s, slideInRight 0.2s;
}

@keyframes fadeIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

@keyframes slideInRight {
    from {
        transform: translateX(100%);
    }
    to {
        transform: translateX(0%);
    }
}

注意: 这个属性支持一次设置多个动画规则,但不要把多个动画写在一个规则里面,因为这不方便动画的复用,正确的做法是分开设置动画,然后用animation属性来统一调用

==> @keyframes规则 <==

说明: 这个规则用来定义动画的一个或者多个关键帧,每一个关键帧由关键帧选择器对应的CSS样式组成,其中关键帧选择器用来指定当前关键帧在整个动画过程中的位置,它支持from和to两个关键字和百分比值,规定from关键字等价于0%,to关键字等价于100%

/* 这两段动画的效果是一样的 */
@keyframes fadeIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

@keyframes fadeIn {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

<== 元素与起始关键帧 ==>

说明: 动画初始状态与元素本身的状态息息相关,看下面的例子就理解了

.element {
    opacity: 0.5;
}

@keyframes fadeInBy {
    100% {
        opacity: 1;
    }
}

/* 此时这个.element的元素在执行动画的时候是从透明度0.5开始的 */
.element.active {
    animation: fadeInBy 0.2s;
}

<== 关键帧列表可以合并 ==>

说明: 如果关键帧对应的CSS样式是一样的,则可以合并在一起书写

@keyframes blink {
    0%,
    50%,
    100% {
        opacity: 0;
    }

    25%,
    75% {
        opacity: 1;
    }
}

<== 关键帧选择器可以无序 ==>

说明: 动画的执行都是从0%到100%的,但是对于写的代码而言,就不存在顺序了,但是推荐按顺序写,这样便于代码的维护

/* 这两组动画的效果是一样的 */
@keyframes fadeIn {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

@keyframes fadeIn {
    100% {
        opacity: 1;
    }
    0% {
        opacity: 0;
    }
}

<== 重复定义的关键帧 ==>

说明: 如果关键帧重复定义,不同的CSS样式是累加的,而相同的CSS样式是后面的样式覆盖前面的样式

/* 最终的效果就是top: 10px left: 20px */
@keyframes identifier {
    50% {
        top: 30px;
        left: 20px;
    }
    50% {
        top: 10px;
    }
}

<== 关键帧的样式可以不连续 ==>

说明: 前面关键帧里面的CSS属性后面的关键帧不一定需要有,中间没有就是一个过渡而已

/* 这里left在30%的地方没有,没有就表示从0%-60%的时候其left的值从0到50px */
@keyframes identifier {
    0% {
        top: 0;
        left: 0;
    }
    30% {
        top: 50px;
    }
    60%,
    90% {
        left: 50px;
    }
    100% {
        top: 100px;
        left: 100%;
    }
}

<== !important无效 ==>

说明: @keyframes规则中的CSS优先级最高,比内置样式和!important还要高

@keyframes identifier {
    0% {
        top: 30px;
        /* 无效 */
        left: 20px !important;
    }
    100% {
        top: 10px;
    }
}

==> 动画的命名与<custom-ident>数据类型 <==

说明: 根据规定,动画名称支持两种数据类型,一种是<string>,一种是<custom-ident>,前者表示带引号的字符串,但是浏览器的支持性很差,就介绍后者,后者支持下列字符的组合

  • 任意字母: a~z或A~Z
  • 数字: 0~9
  • 短横线: -
  • 下划线: _
  • 转义字符: 使用反斜杠 \ 转义
  • Unicode字符: 反斜杠 \ 后面跟十六进制数字

注意:

  • 不能是CSS属性本身支持的关键字,例如animation属性支持关键字none,也支持全局关键字unset、initial和 inherit。因此,在CSS动画中,不能把动画名称定义为none、 unset、initial或inherit。

  • 不能以十进制数字开头

  • 可以使用短横线作为开头,但是短横线后面不能是十进制数字

  • 短横线和下划线之外的英文标点字符(包括空格)都需要转义

  • 连续短横线开头的名称除了IE浏览器都支持

  • 如果是Unicode编码转义字符,记得在后面添加一个空格

==> 负延时与即时播放 <==

说明: 延迟播放需要使用animation-delay这个属性,后面跟延迟的时间,不过需要注意的是,如果动画是无限循环的,设置的延时不会跟着循环

/* 这段动画会延迟300ms后不断的旋转,而不是每延迟300ms转一圈 */
.loading {
    animation: spin 1s infinite;
    animation-delay: 300ms;
}
@keyframes spin {
    0% {
        transform: rotate(0deg);
    }
    100% {
        transform: rotate(360deg);
    }
}
.loading {
    animation: spin 1s infinite;
}
/* 如果希望存在延迟效果,则需要在关键帧处进行设置,比如下面的0%-30% */
@keyframes spin {
    0%,
    30% {
        transform: rotate(0deg);
    }
    100% {
        transform: rotate(360deg);
    }
}

<== 音频波形动画 ==>

说明: 通过设置负延迟让动画的初始状态为动画中间的某一阶段,以此解决初期动画没动起来的时候矩形的高度是默认值的问题

<h4>正延时</h4>
<div class="loading"><i></i><i></i><i></i><i></i></div>

<h4>负延时</h4>
<div class="loading negative"><i></i><i></i><i></i><i></i></div>
.loading i {
    display: inline-block;
    border-left: 2px solid deepskyblue;
    height: 2px;
    animation: scaleUp 4s linear infinite alternate;
    margin: 0 1px;
}

.loading i:nth-child(2) {
    animation-delay: 1s;
}

.loading i:nth-child(3) {
    animation-delay: 2s;
}

.loading i:nth-child(4) {
    animation-delay: 3s;
}

.negative i:nth-child(2) {
    animation-delay: -1s;
}

.negative i:nth-child(3) {
    animation-delay: -2s;
}

.negative i:nth-child(4) {
    animation-delay: -3s;
}

@keyframes scaleUp {
    to {
        transform: scaleY(10);
    }
}

image.png

<== 理解延迟负值 ==>

举例: 下面代码的透明度变化是0.75→1还是0.25→1

.element {
    animation: fadeIn 1s linear -0.25s;
}

@keyframes fadeIn {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

理解; 如果是延迟0.25s的话就表示动画在0.25s之后从0%开始播放,如果增加一个负号就表示在0.25s之前动画就已经从0%开始播放,那也就意味着动画真正播放的时候已经执行了0.25s,因此负号可以理解为提前执行

==> 动画的方向 <==

说明: 控制动画的方向需要使用animation-direction属性,它支持四个关键字属性值,分别是normal、reverse、alternate和alternate-reverse,其默认值是normal,通过一个例子简单了解一下这四个值

举例: 常见的淡入淡出动画效果

.element {
    /* fadeIn动画执行2次 */
    animation: fadeIn 1s 2;
}
@keyframes fadeIn {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

解释:

  • normal:那么动画执行的方向是0%→100%、0%→100%,每一轮的动画方向都是正常的

  • reverse: 那么动画执行的方向是100%→0%、100%→0%,每一轮的动画方向都是与第一轮相反的

  • alternate: 那么动画执行的方向是0%→100%、100%→0%,每轮的动画方向都是与前一轮相反的

  • alternate-reverse: 那么动画执行的方向是100%→0%,0%→100%,每轮的动画方向与前一轮是相反的

<== reverse关键字举例 ==>

说明: 比如顺时针旋转和逆时针旋转就不需要设置两套动画了,直接使用reverse关键字改变方向就好

/* 顺时针旋转 */
.turntable {
    animation: spin 5s 5;
}

/* 逆时针旋转 */
.loading {
    animation: spin 1s reverse infinite;
}

@keyframes spin {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}

<== alternate关键字举例 ==>

说明: 对于来回时间一致的动画可以使用这个关键字来完成,比如钟摆运动

.clock-pendulum {
    width: 20px;
    height: 100px;
    background: radial-gradient(
        10px at left 50% bottom 10px,
        deepskyblue 100%,
        transparent 0
    )
        no-repeat center,
    radial-gradient(4px at 50% 4px, deepskyblue 100%, transparent 0)
        no-repeat center,
    linear-gradient(to right, currentColor, currentColor) 
        no-repeat center;
    background-size: 100%, 100%, 2px 100%;
    margin: auto;
}

/* 动画相关 */
.clock-pendulum {
    transform-origin: center 4px;
    animation: pendulum 1s infinite alternate ease-in-out;
}

@keyframes pendulum {
    0% {
        transform: rotate(-10deg);
    }
    100% {
        transform: rotate(10deg);
    }
}
<div class="clock-pendulum"></div>

==> 播放次数 <==

说明: 动画的播放次数需要使用animation-iteration-count属性来指定,它的值是一个数字,这个数字不能是负数,可以是0,也可以是小数,对于小数而言,比如1.5次,其表现的结果就是在第二次动画播放的时候,播放到0.5这个位置就停止,可以理解为50%这个地方,假设动画的是opacity从0%到100%,那么此时元素在进行第二轮动画的播放的时候,在透明度50%这个地方结束动画

<p><input value="可用" class="visible " /></p>
<p><input value="禁用" disabled /></p>
input {
    opacity: 0;
    border: 1px solid darkgray;
}

.visible {
    animation: fadeIn 0.25s both;
}

/* 对于ease时间函数,透明度提高到40%只需要25%的完整动画时间,因此只执行0.25次动画就好 */
/* 能够这样做的原因是CSS关键帧的优先级更高,会覆盖原有的样式 */
.visible:disabled {
    animation: fadeIn 1s 0.25 both;
}

@keyframes fadeIn {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

image.png

注意: 它还支持infinite关键字属性值,表示无限次的执行,也就是动画会一直运动下去

==> 动画时间之外的过渡 <==

说明: 此时需要使用animation-fill-mode属性,它用来定义动画在执行时间之外应用的值,它支持四个关键字属性值,分别是none、forwards、backwards和both

<== 默认值none ==>

说明: 这个表示默认值,也就是动画开始之前和动画结束之后不会对元素应用@keyframes规则中定义的任何样式,这种可能存在样式突然变化的情况,举个例子可能就明白了

举例: 假设存在这样的动画,那么element元素会有怎样的表现呢

.element {
    opacity: 0.5;
    animation: fadeIn 2s 1s;
}

@keyframes fadeIn {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

理解: 由于设置了延迟1s,那么element元素会先保持透明度0.5的状态1s,之后动画开始,由于动画是从0开始的,那么透明度会从0.5突变到0,然后从0-1的透明度之间进行过渡,这个过渡的过程存在2s,动画结束后,又会从1突变到0.5,从而给人一种很差的体验

<== forwards和backwards ==>

说明: forwards表示动画结束后元素将应用当前动画结束时的属性值,而backwards表示动画开始前元素将应用当前动画开始时的属性值,还是用上面的例子理解,至于什么时候动画结束这个由播放次数来决定

.element {
    opacity: 0.5;
    /* 在动画结束后element元素的透明度就一直保持1的状态 */
    /* 就不存在从1突变到0.5的情况 */
    animation: fadeIn 2s 1s forwards;
}

@keyframes fadeIn {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}
.element {
    opacity: 0.5;
    /* 在动画开始的时候element元素就一直保持透明度为0的状态 */
    /* 直到动画开始透明度才开始变化 */
    animation: fadeIn 2s 1s backwards;
}

@keyframes fadeIn {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

<== 最后一个关键帧 ==>

对于forwards: 由于动画的最后一帧是由animation-direction和animation-iteration-count属性共同决定的,因此forwards有时候对应的是@keyframes规则中的to或100%对应的帧,有时候对应的是@keyframes规则中的from或0%对应的帧,那么就可以总结成下面的表格

animation-directionanimation-iteration-count最后一个关键帧
normal奇数或偶数(不包括0)100%或to
reverse奇数或偶数(不包括0)0%或from
alternate正偶数0%或from
alternate奇数100%或to
alternate-reverse正偶数100%或to
alternate-reverse奇数0%或from
normal或alternate00%或from
reverse或alternate-reverse0100%或to

对于backwards: 由于backwards只取决于animation-direction的属性值,因为backwards设置的是动画第一次播放的第一帧的状态,与 animation-iteration-count次数没有任何关系,所以可以得到下面的表格

animation-direction第一个关键帧
normal或alternate0%或from
reverse或alternate-reverse100%或to

<== 对于both关键字 ==>

说明: 很好理解,就是同时应用forwards和backwards这两个关键字,因此就不用去记住哪一个的作用是啥了,避免混淆

==> 动画的暂停与播放 <==

说明: 这个需要使用animation-play-state属性来进行控制,它支持两个属性值,一个是paused表示暂停,另一个是running表示播放,它可以配合精灵图实现动图的效果,相比于传统的GIF动图,使用animation实现的动图效果,支持无损PNG,图像质量更高,而且可以随时播放和暂停,这种操作一般是需要JavaScript来支持的

==> 了解steps()函数 <==

说明: animation-timing-function的属性值由cubic-bezier()函数和steps()函数组成,前者让动画十分的丝滑,后者是将动画分为几段,让其不连续,这个理解起来有点难!!!

语法:

steps(number, position)

解释:

  • number: 指整数,表示将动画分为多少段,比如这里的值是5,而动画的过程是从0位移100px,那么此时动画就分为0-20px、21-40px、41-60px、61-80px和81-100px这5段,也就是平均分配的

  • position: 指关键字属性值,表示动画跳跃执行是在时间段的开始还是结束,它支持很多关键字,比如传统的start和end关键字,这里start表示在时间段的开头处跳跃,而end表示在时间段的结束处跳跃

<== 了解start和end关键字 ==>

前提: 在高中物理里面,存在1s末和1s初这个东西,可以这么理解,1s末,那也就是1s结束了,是不是下一秒就开始了呢,因此1s末也就是2s初,那么同理1s初岂不是0s末嘛,这个理解了,这两个关键字就理解了

理解: 从上面的定义来看,strat可以理解为某一段动画的开头不就是上一段时间的末尾嘛,因此start就对应每一段动画的结尾那个部分,相同的道理,那么end是不是就理解为每一段动画开头的那个部分呢,由于steps()函数是将动画分为多段,动画的表现不是连续的,因此看到的效果只是一段动画上某一个标志性的值来进行体现,从而可以得到如果关键字是start的话,那么得到的值就是每一段动画里面最后的哪一个值来体现动画的效果,同时,end就用每一段动画最开始的那个值来体现动画的效果

.start {
    /* 元素会位移到的地方:20、40、60、80、100 */
    animation-timing-function: steps(5, start);
}
.end {
    /* 元素会位移到的地方:0、20、40、60、80 */
    animation-timing-function: steps(5, end);
}

@keyframes move {
    0% {
        left: 0;
    }
    100% {
        left: 100px;
    }
}

<== 如果animation-fill-mode属性来凑热闹 ==>

说明: 由于这个属性会保持最开始或者最末尾的关键帧的状态嘛,比如关键字使用end,但是forwards关键字保持最后一个关键帧的状态,还是以上面的位移例子为例,虽然只分成了5段,但是最后一段动画的末尾是下一段动画开始的时候,由于它保持上一个关键帧的状态,那么这个地方也是会受影响的,从而会多往后位移一段,从而导致动画的效果是从0、20、40、60、80、100,其它关键字也是同理的,至于怎么修复,既然你会多一段位移,为了保持与原来相同的效果,那在分段的时候少分一段就好了,设置4段,根据其特点,也会有5段位移的效果

六、面试喜欢问的布局

(1)分栏布局

说明: 这种布局可以将内容布局到多个列框中,类似报纸上的排版,它会将所有的子元素拆分为列,其主要针对图文排版布局

优点: 不会改变元素原本的display计算值

<ul>
    <li>重庆市</li>
    <li>哈尔滨市</li>
    <li>长春市</li>
    <li>兰州市</li>
    <li>北京市</li>
    <li>杭州市</li>
    <li>长沙市</li>
    <li>沈阳市</li>
    <li>成都市</li>
    <li>合肥市</li>
    <li>天津市</li>
    <li>西安市</li>
</ul>
ul {
    /* 只将内容分为两列 */
    columns: 2;
}

image.png

==> columns属性 <==

说明: 绝大部分分栏布局只需要使用columns属性就行,因此这个属性显得十分重要,它是column-width和column-count属性的缩写形式,因此,关注columns属性本质上就是关注column-width和column-count这两个CSS属性

/* 栏目宽度 */
columns: 18em;

/* 栏目数目 */
columns: auto;
columns: 2;

/* 同时定义宽度和数目,顺序任意 */
columns: 2 auto;
columns: auto 2;
columns: auto 12em;
columns: auto auto;

<== column-width属性 ==>

说明: 它表示每一栏或者每一列的最佳宽度,这个和实际的渲染宽度存在差别,比如下面两种设定是无效的,在分栏布局中,column-width 更像是一个期望尺寸,浏览器会根据这个期望尺寸确定分栏数目,一旦分栏数目确定了,column-width属性的使命也就完成了,接下来根据分栏数目对容器进行的分栏布局就和column-width属性没有任何关系了,从而存在这样的结论就是几乎不存在分栏布局的栏目宽度就是column-width设置的宽度这样的场景

/* 容器里面的内容会无视column-width声明 */
.container {
    width: 300px;
    column-width: 200px;
}

.container {
    width: 200px;
    column-width: 300px;
}

注意: column-width属性不支持百分比值

<== column-count属性 ==>

说明: 它表示理想的分栏数目,也就是意味着最终的分栏数目可能不受column-count属性值的控制,在最终分栏的数目上它和column-width是相互制约的,在不同的场景下它们的优先级也不一样,一般来说,都会统一转换成column-count值,哪个值就使用哪一个,如果遇到小数就向下取整

.container-1 {
    width: 360px;
    column-count: 2;
    /* 转换后的值为3.6 */
    column-width: 100px;
}

.container-2 {
    margin-top: 20px;
    width: 360px;
    column-count: 4;
    /* 转换后的值为3.6 */
    column-width: 100px;
}
<div class="container-1">
    column-count与column-width都有可能有更高的优先级,要看具体场景。优先级计算诀窍就是统一转换column-count值,哪个值小就使用哪一个。
</div>

<div class="container-2">
    column-count与column-width都有可能有更高的优先级,要看具体场景。优先级计算诀窍就是统一转换column-count值,哪个值小就使用哪一个。
</div>

image.png

==> column-gap和gap属性 <==

说明: column-gap属性表示每一栏之间的空白间隙的大小,可以是长度值,也可以是百分比值,而gap属性实际上是column-gap属性和row-gap属性的缩写,现在规定行与列之间的间隙使用了gap属性统一管理

/* 关键字属性值 */
column-gap: normal;

/* 长度值 */
column-gap: 3px;
column-gap: 3em;

/* 百分比值 */
column-gap: 3%;

==> 辅助属性 <==

<== column-rule属性 ==>

说明: column-rule属性是column-rule-width、column-rule-style和column-rule-color这3个CSS属性的缩写,它的语法规则和border属性是一模一样的,只是column-rule是设置各个分栏的分隔线样式,border是设置元素的边框样式

<div class="container">
    column-rule属性是column-rule-width,column-rule-style和column-rule-color这3个CSS属性的缩写。
</div>
.container {
    width: 320px;
    border: solid deepskyblue;
    padding: 10px;
    column-count: 2;
    column-rule: dashed deepskyblue;
}

image.png

<== column-span属性 ==>

说明: 它作用在分栏布局的子元素上,表示这个子元素的内容是否跨多栏显示,它的默认值是none,表示不跨多栏,而all表示跨多栏

.container {
    width: 320px;
    border: solid deepskyblue;
    padding: 10px;
    column-count: 3;
}

.container p {
    background: deepskyblue;
}

.span-all {
    column-span: all;
    color: white;
}
<h4>不跨栏显示</h4>
<div class="container">
    <p>第1段</p>
    <p>第2段</p>
    <p>第3段</p>
    <p>第4段</p>
    <p>第5段</p>
</div>

<h4>跨栏显示</h4>
<div class="container">
    <p>第1段</p>
    <p>第2段</p>
    <p>第3段</p>
    <p class="span-all">第4段</p>
    <p>第5段</p>
</div>

image.png

<== column-fill属性 ==>

说明: 它的作用是当内容分栏的时候平衡每一栏填充的内容,常用的值有两个,一个是默认值balance,一个是auto

  • auto: 按顺序填充每一列,内容只占用它需要的空间

  • balance: 默认值,尽可能在列之间平衡内容。在分隔断开的上下文中,只有最后一个片段是平衡的。例如,有多个<p>元素,正好最后一个<p>换行了,那这个<p>元素的内容前后等分,保持平衡。这会造成最后一栏内容较少的问题

<h4>column-fill:auto</h4>
<div class="container auto">
    balance是默认值。auto属性值在Firefox中渲染正确,Chrome中需要固定高度才有效。balance-all没有浏览器支持。
</div>

<h4>column-fill:balance</h4>
<div class="container balance">
    balance是默认值。auto属性值在Firefox中渲染正确,Chrome中需要固定高度才有效。balance-all没有浏览器支持
</div>
.container {
    width: 400px;
    height: 80px;
    border: solid deepskyblue;
    padding: 10px;
    column-count: 2;
}

.auto {
    column-fill: auto;
}

.balance {
    column-fill: balance;
}

image.png 注意: 所有浏览器都能识别column-fill:auto,但是,需要容器有固定的高度才能准确渲染

==> 分栏布局的单行两端对齐 <==

<h4>分栏布局实现两端对齐</h4>
<div class="container">
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
</div>
.container {
    width: 300px;
    border: solid deepskyblue;
    /* 需要使用column-count属性和column-gap属性 */
    column-count: 3;
    column-gap: 5%;
}

.list {
    height: 100px;
    background-color: deeppink;
}

image.png

==> break-inside属性 <==

说明: 这个属性可以定义分栏布局发生中断时元素的表现形式,如果没有中断,则该属性不起作用,由于兼容性问题,只需要关注auto表示元素可以中断,avoid表示元素不可以中断这两个属性值就可以了

.container {
    width: 300px;
    padding: 10px;
    background-color: #ecf0f1;
    columns: 3;
}

.list {
    background: white;
    padding: 10px;
    margin: 0 0 1.3em;
}

.break-inside .list {
    /* Chrome, Safari, Opera */
    -webkit-column-break-inside: avoid;
    /* Firefox */
    page-break-inside: avoid;
    /* IE 10+, Chrome, Safari, Opera */
    break-inside: avoid;
}
<h4>默认</h4>
<div class="container">
    <div class="list">列表内容1</div>
    <div class="list">列表内容2,这个列表内容要比前后列表稍微多一点</div>
    <div class="list">列表内容3</div>
</div>

<h4>break-inside: avoid</h4>
<div class="container break-inside">
    <div class="list">列表内容1</div>
    <div class="list">列表内容2,这个列表内容要比前后列表稍微多一点</div>
    <div class="list">列表内容3</div>
</div>

image.png

==> box-decoration-break属性 <==

说明: 在默认情况下,元素片段在跨行、跨列或跨页时候的 样式是分割渲染的,比如下面这样的,如果希望因为分栏断开的文字在每一栏中都拥有独立完整的边框,则可以使用box-decoration-break属性实现,这个属性的默认值是slice,表示各个元素断开的部分如同被切开一般,它还支持clone,表示断开的各个元素的样式独自渲染

缺点: 兼容性不好,很多浏览器只有特定的版本才支持,恶心住

image.png

注意: IE不支持这个属性,Chrome不支持块级元素clone表现,只有Firefox的表现是正常的;其次这个属性只能影响部分属性的渲染,有background、border、border-image、box-shadow、border-radius、clip-path、margin、padding这几个

(2)弹性布局

约定:

  • 设置display:flex声明或者display:inline-flex声明的元素为flex容器,里面的子元素为flex子项

  • 弹性布局存在主轴交叉轴之分,默认情况这两个代表水平和垂直两个方向

==> 设置display:flex有啥用 <==

说明: 给任意元素设置display:flex声明或者display:inline-flex声明,弹性布局就会被创建,这两个声明的区别在于一个是创建块级flex容器,一个是创建内联级flex容器

<!-- 这个div设置了display:flex声明,这个div称为flex容器 -->
<div style="display: flex">
    <!-- 里面的img和span元素就称为flex子项 -->
    <img src="D:1.jpg" alt="" style="width: 100px" />
    <span>图片描述</span>
</div>
<span>下一行的内容</span>

image.png

image.png

<== flex子项块状化 ==>

display值的变化: 就是flex容器里面的flex子项的display的计算值是会发生改变的,常见的变化如下

原来的display值变成flex子项后的display值
inline/inline-block/blockblock
flow-rootflow-root
list-itemlist-item
inline-table/tabletable
table-*block
inline-flex/flexflex
inline-grid/gridgrid

理解: 从而得到flex子项都是块级水平元素,因此,在flex子项元素中使用vertial-align属性一定是没有任何效果的,这种块状化的特效对于没有嵌套标签的文本元素,也就是匿名内联元素也是有效的,但是对于空格元素无效

.container {
    display: flex;
}

content {
    border: 1px solid red;
    width: 20px;
    height: 20px;
}
<div class="container">
    <content>1</content>
    2
    <content>3</content>
</div>

image.png

<== flex子项浮动失效 ==>

说明: 也就是flex容器里面的元素设置浮动是没用的,因为控制flex子项左右对齐是有专门的CSS属性的

<!-- 无效设置 -->
<div class="container">
    <content style="float: left">1</content>
    <content>2</content>
    <content style="float: right">3</content>
</div>

<== flex子项支持z-index属性 ==>

说明: 即使flex子项的position属性的计算值是static,flex子项也是支持z-index属性的。如果z-index属性值不是auto,则会创建新的层叠上下文

<== flex子项的margin值不会合并 ==>

说明: flex子项的margin值是不会合并的,这一点和普通的块级元素不一样

<== flex子项是格式化的尺寸 ==>

说明: flex子项的尺寸是经过精确计算的,也就是隐式存在具体的计算值,因此,可以使用 margin:auto进行剩余空间的智能分配

<div class="container">
    <content>1</content>
    <content>2</content>
    <content>3</content>
</div>
.container {
    width: 450px;
    height: 100px;
    border: 1px dashed black;
    display: flex;
}

content {
    width: 100px;
    height: 100px;
    background: #abcdef;
}

content:nth-of-type(2) {
    /* 如果希望第二个<content>元素居中显示,其他<content>元素靠边显示, */
    /* 除了给flex容器设置justify-content:space-between,还有一个简单的方法,*/
    /* 就是设置第二个<content>的margin:auto */
    margin: auto;
}

image.png

<== flex子项的其它特性 ==>

  • flex子项如果被设置为绝对定位,则会脱离弹性布局

  • flex子项的尺寸默认表现为收缩,如果要设置建议的尺寸,可以给flex子项使用flex-basis属性,或者使用缩写的flex属性

  • flex子项默认是水平排列的,这个特性表现是由flex-direction属性决定的。而且就算flex子项的宽度之和超过flex容器,flex子项也不会换行,这个特性表现是由flex-wrap属性决定的。因此,如果我们想要改变flex子项的排版方向或者flex子项的换行规则,就需要用到flex-direction属性和flex-wrap属性

==> flex-direction属性 <==

作用: 用来控制flex子项整体布局方向,决定是从左往右排列还是从右往左排列,是从上往下排列还是从下往上排列

语法:

flex-direction: row | row-reverse | column | column-reverse;
  • row: 默认值,表示flex子项显示为水平排列。方向为当前文档水平流方向,默认情况下是从左往右排列;如果当前水平文档流方向是rtl,则从右往左排列

  • row-reverse: 表示flex子项显示为水平排列,但方向和row属性值相反

  • column: 表示flex子项显示为垂直排列。默认情况下的排列顺序是从上往下排列,使用writing-mode属性可以改变这个排列顺序

  • column-reverse: 表示flex子项显示为垂直排列,但方向和column属性值相反

<h4>默认值row</h4>
<div class="container">
    <div>内容1</div>
    <div>内容2</div>
    <div>内容3</div>
</div>

<h4>row-reverse</h4>
<div class="container row-reverse">
    <div>内容1</div>
    <div>内容2</div>
    <div>内容3</div>
</div>

<h4>column</h4>
<div class="container column">
    <div>内容1</div>
    <div>内容2</div>
    <div>内容3</div>
</div>

<h4>column-reverse</h4>
<div class="container column-reverse">
    <div>内容1</div>
    <div>内容2</div>
    <div>内容3</div>
</div>
.container {
    width: 300px;
    display: flex;
    outline: 1px dotted;
}

.row-reverse {
    flex-direction: row-reverse;
}

.column {
    flex-direction: column;
}

.column-reverse {
    flex-direction: column-reverse;
}

image.png

==> flex-wrap属性 <==

语法: 它用来控制flex子项是单行显示还是换行显示,以及在换行情况下,每一行内容是否在垂直方向的反方向显示

语法:

flex-wrap: nowrap | wrap | wrap-reverse;
  • nowrap: 默认值,表示flex子项是单行显示,且不换行。由于flex子项不换行,因此可能会出现子项宽度溢出,此时可以给子项max-width来解决这个问题,因为max-width属性的优先级大于width属性的优先级,能够使子项的尺寸从固定值变成相对值,从而使flex子项弹性收缩就,这样子项的宽度就不会溢出了

  • wrap: 表示flex容器宽度不足的时候,flex子项会换行显示

  • wrap-reverse: 表示宽度不足的时候,flex子项会换行显示,但是flex子项是从下往上开始排列的,也就是原本换行到下面一行的flex子项现在换行到上面一行

<h4>默认值nowrap</h4>
<div class="container">
    <div>内容1</div>
    <div>内容2</div>
    <div>内容3</div>
</div>

<h4>wrap</h4>
<div class="container wrap">
    <div>内容1</div>
    <div>内容2</div>
    <div>内容3</div>
</div>

<h4>wrap-reverse</h4>
<div class="container wrap-reverse">
    <div>内容1</div>
    <div>内容2</div>
    <div>内容3</div>
</div>
.container {
    width: 100px;
    display: flex;
    outline: 1px dotted;
}

.wrap {
    flex-wrap: wrap;
}

.wrap-reverse {
    flex-wrap: wrap-reverse;
}

image.png

==> flex-flow属性 <==

说明: 这个属性是flex-direction属性和flex-wrap属性的缩写,因此它支持这两个属性的所有属性值,当多属性值同时使用的时候,使用空格分隔,且不区分前后顺序,在日常开发的时候,没有必要使用flex-direction属性和flex-wrap属性,直接使用flex-flow这个缩写属性就好了

/* flex-flow: <'flex-direction'> */
flex-flow: row;
flex-flow: row-reverse;
flex-flow: column;
flex-flow: column-reverse;

/* flex-flow: <'flex-wrap'> */
flex-flow: nowrap;
flex-flow: wrap;
flex-flow: wrap-reverse;

/* <'flex-direction'> 和 <'flex-wrap'> */
flex-flow: row nowrap;
flex-flow: nowrap row;
flex-flow: column wrap;
flex-flow: column-reverse wrap-reverse;

==> justify-content属性 <==

说明: 表示flex子项的水平对齐设置

常用语法:

justify-content: normal | flex-start | flex-end | center | space-between | space-around | space-evenly;
  • normal: 初始值,表示根据环境不同,可以采用不同的对齐表现。如果有列的概念,normal的行为类似于stretch,例如网格布局和分栏布局;如果没有列的概念,例如,在flex容器中, normal的行为表现类似于flex-start

  • flex-start: 可以看成默认值,它是一个逻辑CSS属性值,与文档流方向相关,默认表现为整体布局左对齐。需要注意的是该值是flex-start,不是start,在网格布局中才是start,弹性布局的逻辑属性都是以flex-开头的,但是网格布局中没有这一特性

  • flex-end: 与文档流方向相关,默认表现为整体布局右对齐。注意,如果flex容器设置了overflow滚动, 同时应用justify-content:flex-end,滚动效果会失效

  • center: 表现为整体布局居中对齐。这个属性值多用在弹性布局有多行且个数不确定的场景下。为了让最后一行居中显示,需要设置justify-content:center

  • space-between: 表示多余的空白间距只在元素中间区域分配,视觉上表现为两端对齐的效果

  • space-around: 表示每个flex子项左右两个都存在看不见的间距,但是这个间距左右两侧是相等的,那么在两个子项之间,会存在两倍的间隙,因为一左一右嘛,从而间隙的比值就是1:2:2:1这种

  • space-evenly: 表示每个子项左右两侧的间距都是1:1:1:1

.container {
    width: 400px;
    height: 56.2px;
    display: flex;
    outline: 1px dotted;
}

img {
    width: 100px;
}

.flex-end {
    justify-content: flex-end;
}

.flex-center {
    justify-content: center;
}

.space-between {
    justify-content: space-between;
}

.space-around {
    justify-content: space-around;
}

.space-evenly {
    justify-content: space-evenly;
}
<h4>默认值 flex-start</h4>
<div class="container">
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
</div>

<h4>flex-end</h4>
<div class="container flex-end">
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
</div>

<h4>center</h4>
<div class="container flex-center">
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
</div>

<h4>space-between</h4>
<div class="container space-between">
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
</div>

<h4>space-around</h4>
<div class="container space-around">
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
</div>

<h4>space-evenly</h4>
<div class="container space-evenly">
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
    <div>
        <img src="D:1.jpg" alt="" />
    </div>
</div>

image.png

==> align-items与align-self属性 <==

说明: 这两个属性都是用来进行垂直对齐的,区别在于align-self属性是设置在具体的某一个flex子项上的,而align-items属性是设置在flex容器元素上的,控制所有flex子项的垂直对齐方 式;另一个区别是align-self属性的初始值是auto,其余的属性值align-items属性和align-self属性的是一样的,含义也是一样的

语法:

align-items: stretch | flex-start | flex-end | center | baseline; 
align-self: auto | stretch | flex-start | flex-end | center | baseline;
  • auto: 是align-self属性的默认值,表示flex子项的垂直对齐方式是由flex容器的align-items属性值决定的

  • stretch: 可以看成弹性布局中align-items属性的默认值,表示flex子项在垂直方向上拉伸,它可以让flex子项的高度拉伸到容器高度。如果flex子项设置了具体的高度值,则按照设置的高度值渲染,而非拉伸,也就是stretch值渲染尺寸的优先级小于height等属性

  • flex-start: 与文档流方向相关,默认表现为flex子项顶部对齐

  • flex-end: 与文档流方向相关,默认表现为flex子项底部对齐

  • center: 表示flex子项都是垂直居中对齐

  • baseline: 表示flex子项参与基线对齐,也就是让所有flex子项的内外基线都在一条水平线上,换句话说,就是给每个flex子项里里外外写上多个字母“x”,这些字母“x”的下边缘保持对齐,如果flex子项没有对应的基线,则沿着flex子项的边框盒子线对齐

image.png

image.png

.container {
    display: flex;
    width: 350px;
    height: 200px;
    flex-wrap: wrap;
    outline: 1px dotted;
}

img {
    width: 100px;
}

.flex-start {
    align-items: flex-start;
}

.flex-end {
    align-items: flex-end;
}

.flex-center {
    align-items: center;
}

.baseline {
    align-items: baseline;
}
<h4>默认值 stretch</h4>
<div class="container">
    <div><img src="D:1.jpg" alt="" /></div>
    <div><img src="D:1.jpg" alt="" /></div>
    <div><img src="D:1.jpg" alt="" /></div>
    <div><img src="D:1.jpg" alt="" /></div>
    <div><img src="D:1.jpg" alt="" /></div>
</div>

<h4>flex-start</h4>
<div class="container flex-start">
    <div><img src="D:1.jpg" alt="" /></div>
    <div><img src="D:1.jpg" alt="" /></div>
    <div><img src="D:1.jpg" alt="" /></div>
    <div><img src="D:1.jpg" alt="" /></div>
    <div><img src="D:1.jpg" alt="" /></div>
</div>

<h4>flex-end</h4>
<div class="container flex-end">
    <div><img src="D:1.jpg" alt="" /></div>
    <div><img src="D:1.jpg" alt="" /></div>
    <div><img src="D:1.jpg" alt="" /></div>
    <div><img src="D:1.jpg" alt="" /></div>
    <div><img src="D:1.jpg" alt="" /></div>
</div>

<h4>center</h4>
<div class="container flex-center">
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
</div>

<h4>baseline</h4>
<div class="container baseline">
    x
    <div><img src="D:1.jpg" alt="" /></div>
    <div class="large"><img src="D:1.jpg" alt="" /></div>
    <div><img src="D:1.jpg" alt="" /></div>
    <div><img src="D:1.jpg" alt="" /></div>
    <div><img src="D:1.jpg" alt="" /></div>
    x
</div>

注意: 如果flex-direction属性的值是column或是column-reverse,则flex子项的垂直对齐不应使用align-items属性控制,而是应该使用justify-content属性控制,并且其初始值是normal

==> align-content属性 <==

说明: align-content属性将所有flex子项作为一个整体进行垂直对齐

语法:

align-content: stretch | flex-start | flex-end | center | space-between | space-around | space-evenly;
  • stretch: 可以看成弹性布局中align-content属性的默认值,表示每一行flex子项都等比例拉伸

  • flex-start: 与文档流方向相关,默认表现 为顶部堆砌

  • flex-end: 与文档流方向相关,默认表现为 底部堆放

  • center: 表现为整体垂直居中对齐

  • space-between: 表现为上下两行两端对齐,剩下的每一行元素 等分剩余空间

  • space-around: 表现为每一行元素上下都享有独立不重叠的空白空间,其空间的比值类似1:2:2:1这种

  • space-evenly: 表现为每一行元素上下的空白空间的大小都是一致的,其空间比值为1:1:1:1

<section>
    <h4>默认值 stretch</h4>
    <div class="container">
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
    </div>
</section>

<section>
    <h4>flex-start</h4>
    <div class="container flex-start">
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
    </div>
</section>

<section>
    <h4>flex-end</h4>
    <div class="container flex-end">
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
    </div>
</section>

<section>
    <h4>center</h4>
    <div class="container flex-center">
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
    </div>
</section>

<section>
    <h4>space-between</h4>
    <div class="container space-between">
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
    </div>
</section>

<section>
    <h4>space-around</h4>
    <div class="container space-around">
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
    </div>
</section>

<section>
    <h4>space-evenly</h4>
    <div class="container space-evenly">
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
        <div><img src="D:1.jpg" alt="" /></div>
    </div>
</section>

image.png

image.png

image.png

==> order属性 <==

说明: 它可以改变某一个flex子项的排序位置,它的属性值是一个整数,默认是零,值越大,越靠后显示,比如水平方向,order属性的值越大越靠右显示,同理越向前值就越小

<h4>第2项设置order:-1</h4>
<div class="container">
    <div>第一项</div>
    <div>第二项</div>
    <div>第三项</div>
</div>
.container {
    display: flex;
    width: 300px;
    outline: 1px dotted;
}

.container > div:nth-child(2) {
    order: -1;
}

image.png

==> 理解flex属性 <==

说明: flex属性是flex-grow、flex-shrink和flex-basis这3个CSS属性的缩写,这几个属性的默认值是auto、0、1;这个属性还支持两个关键字,分别是auto和none

  • flex: auto 等同于设置flex: 1 1 auto,表示flex子项自动填满剩余空间或自动收缩

  • flex: none 等同于设置flex: 0 0 auto,表示flex子项没有弹性,适合固定尺寸元素

注意: 这个缩写属性在设置一个值或者两个值的时候剩下的属性值不一定是默认值,比如flex-basis不写则使用0%,flex-grow不写则使用1,这样优化的目的更符合日常开发需要的效果

<== 语法 ==>

多值语法:

/* 表示0个或1个的问号“?”在flex-shrink的后面,因此如果存在两个或者两个 */
/* 以上的值,第一个值都是flex-grow' */

/* ||表示或者的意思,也就是第一个值和第三个值的位置可以交换 */
flex: <'flex-grow'> <'flex-shrink'>? || <'flex-basis'>

理解: flex属性值的数量不同,其对应的含义也会不同

  • <== 一个值的情况 ==>
    • 数值: 如flex: 1,则这个1为flex-grow属性的值,此时flex-shrink属性和flex-basis属性的值分别是1和0%
    • 百分比值: 如flex:100px,则这个100px显然为flex-basis属性的值,因为3个缩写CSS属性中只有flex-basis的属性值支持长度值。此时flex-grow属性和flex- shrink属性的值都是1
  • <== 两个值的情况 ==>
    • 第二个值是数值: 例如flex: 1 2,则这个2是flex-shrink属性的值,此时flex-basis属性计算值是0%
    • 第二个值是长度值: 例如flex: 1 100px,则这个100px为flex-basis属性值

<== flex-grow属性 ==>

说明: 指定容器剩余空间多余时候的分配规则,默认值是0,表示多余空间不分配,支持小数,其剩余空间总量是1,空间分配遵循以下规则

  • 1个flex子项设置: 如果这个子项设置的flex-grow属性值小于1,则flex子项扩展的空间就是总剩余空间和这个比例的计算值;如果大于1,则flex子项独享所有剩余空间

  • 多个flex子项设置: 如果这些子项设置的flex-grow属性值之和小于1,则每个flex子项扩展 的空间就是总剩余空间和当前flex子项设置的flex-grow比例的乘积;如果大于1,则按照各个flex子项的flex-grow属性值的比例来进行分配,比如设置的flex-grow比例是1:2:1,则中间的flex子项占据一半的剩余空间,剩下另外一半的剩余空间由前后两个flex子项等分

<== flex-shrink属性 ==>

说明: 指定了容器剩余空间不足时候的分配规则,默认值是1,表示空间不足要分配,同样支持小数

  • 1个flex子项设置: 如果flex-shrink属性值小于1,则收缩不完全,会有一部分内容溢出flex容器;如果大于等于1,则收缩完全,元素正好填满flex容器

  • 多个flex子项设置: 如果flex-shrink属性值的总和小于1,则收缩不完全,每个元素收缩尺寸和完全收缩的尺寸的比例就是该元素的flex-shrink属性的值;如果大于1,则收缩完全,每个元素收缩尺寸的比例和flex-shrink属性值的比例一样

<== 了解flex-basis属性 ==>

说明: 用来设置元素的基础尺寸,其默认值是auto

举例: 一个家族有五个孩子分配遗产,分别是老大、老二、老三、老四和老五,遗产有500万,其中遗嘱是这样写的,老大、老二、老三分别得到遗产100万,剩下的给老四和老五平分,不过世事难料,遗产被偷窃200万,那么在分配遗产的时候,老大老二老三拿到自己的100万后,老四老五就没钱了,这就相当于遗产不足,也就是容器剩余空间不足,如果老四和老五能够拿到自己的遗产,哪怕是只有1块,也就是说遗产存在剩余的,这就对应了容器剩余空间充足的情况

理解: 也就是这几个属性值中,flex-basis表示得到固定的钱,如果有多余的钱和自己没关系;flex-grow表示固定的钱分完之后的钱,也就是多余的钱,通过上面例子可以看到你可以分到很多,也可以一块都分不到,这取决于剩了多少;至于flex-shrink就表示遗产不足需要通过之前设置的固定的钱的比例来分遗产了,也就是自己要亏一点

举一反一: 老大、老二、老三分配固定遗产100万,老四、老五有20万保底,规定在分配家产的时候如果有多的,老四老五按照3:2进行分配,如果老大老二老三分完钱100万之后,老四老五没钱分,则老四老五的保底钱由老大老二老三按照2:1:1拿钱来填补这个40万,此时该咋分呢

<div class="container">
    <item class="da">老大</item>
    <item class="er">老二</item>
    <item class="san">老三</item>
    <item class="si">老四</item>
    <item class="wu">老五</item>
</div>
.container {
width: 500px;
    /* 开始分家产 */
    display: flex;
    border: 2px dashed crimson;
}

.container item {
    border: 2px solid deepskyblue;
}

.da {
    /* 老大不会争夺多余家产,但是会在家产不足时分出2倍于老二和老三分出的家产 */
    flex: 0 2 100px;
}

.er,
.san {
    /* 老二和老三不会争夺多余家产,但是会在家产不足时分出部分家产,照应老四和老五 */
    flex: 0 1 100px;
}

.si {
    /* 老四会争夺多余家产,且会在家产不足时获得哥哥们分出的家产,确保能够活下去,感谢3位哥哥的照顾 */
    flex: 3 0 20px;
}

.wu {
    /* 老五会争夺多余家产,不过拿到的比哥哥少一点,且会在家产不足时获得哥哥们分出的家产,感谢哥哥们的照顾 */
    flex: 2 0 20px;
}

image.png

image.png

image.png

==> flex属性的单值语法 <==

单值语法等价语法
flex: initialflex: 0 1 auto
flex: 0flex: 0 1 auto
flex: noneflex: 0 1 auto
flex: 1flex: 0 1 auto
flex: autoflex: 0 1 auto

<== flex: initial ==>

说明: flex:initial等同于设置flex: 0 1 auto,可以理解为flex属性的默认值,其表现为应用flex:initial的元素在容器有剩余空间的时候不会参与空间分配,在容器尺寸不足的时候元素会自动收缩,最后元素的宽度是自适应内容的,通常用来还原已经设置的CSS属性

适用场景: 元素尺寸能够收缩,并且元素内容较多时又能自动换行的场景

<div class="container">
    <item>老大</item>
    <item>老二</item>
    <item>老三</item>
    <item>老四</item>
    <item>老五</item>
</div>
.container {
    display: flex;
    width: 300px;
    border: 2px dashed crimson;
}

.container item {
    border: 2px solid deepskyblue;
}

image.png

image.png

<== flex: 0 和 flex: none ==>

说明: flex:0等同于设置flex: 0 1 0%,flex:none等同于设置 flex: 0 0 auto,也就是前者会进行弹性收缩并且元素尺寸表现为最小内容宽度,而后者表现为元素没有弹性并且元素尺寸为最大内容宽度

.container {
    width: 400px;
    border: solid 2px blue;
    display: flex;
}

item {
    border: dashed 2px red;
}

.flex-0 item {
    flex: 0;
}

.flex-none item {
    flex: none;
}
<h4>flex:0</h4>
<div class="container flex-0">
    <item>老大老大老大</item>
    <item>老大老大老大</item>
    <item>老大老大老大</item>
    <item>老大老大老大</item>
    <item>老大老大老大</item>
</div>

<h4>flex:none</h4>
<div class="container flex-none">
    <item>老大老大老大</item>
    <item>老大老大老大</item>
    <item>老大老大老大</item>
    <item>老大老大老大</item>
    <item>老大老大老大</item>
</div>

image.png

<== flex: 1 ==>

说明: flex:1等同于设置flex: 1 1 0%,从而得到元素尺寸可以弹性增大,也可以弹性减小,但是在容器尺寸不足时会优先最小化内容尺寸

适用场景: 当希望元素充分利用剩余空间,同时不会侵占其他元素应有的宽度的时候,例如等分布局

<h4 class="fill">默认</h4>
<div class="container">
    <img src="D:1.jpg" style="width: 60px" />
    <p>右侧按钮没有设置flex:none,表现为最小内容宽度。</p>
    <button>按钮</button>
</div>

<!--按钮能够正常显示是因为flex:1可以进行弹性收缩的原因 -->
<h4 class="fill">&lt;p&gt;设置flex:1</h4>
<div class="container">
    <img src="D:1.jpg" style="width: 60px" />
    <p>描述信息元素使用了flex:1,按钮正常显示了。</p>
    <button>按钮</button>
</div>
.container {
    display: flex;
    width: 300px;
    padding: 0.5rem;
    border: 1px solid lightgray;
    background-color: #fff;
}

img {
    width: 3rem;
    height: 3rem;
    margin-right: 0.5rem;
    object-fit: cover;
}

button {
    align-self: center;
    padding: 5px;
    margin-left: 0.5rem;
}

.container ~ .container p {
    flex: 1;
}

image.png

<== flex: auto ==>

说明: flex:auto等同于设置flex: 1 1 auto,其表现为元素尺寸可以弹性增大,也可以弹性减小,但是容器尺寸不足时会优先最大化内容尺寸

适用场景: 元素充分利用剩余空间,但是元素各自的尺寸又需要按照各自内容进行分配的时候,例如导航数量不固定且每个导航文字数量也不固定的导航效果

<nav class="flex">
    <span>首页</span>
    <span>排行榜</span>
    <span>我的订单</span>
    <span>个人中心</span>
</nav>
nav span {
    flex: auto;
    line-height: 3rem;
    background: #444;
    color: #fff;
    text-align: center;
}

span + span {
    border-left: 1px solid #eee;
}

image.png

==> 理解尺寸计算规则 <==

<== flex-basis属性与盒模型 ==>

说明: flex-basis属性的尺寸是作用在content-box上的,在外在尺寸够大,内容尺寸够小的情况下,width属性和flex-basis属性的表现是一样的,同时flex-basis属性支持box-sizing属性改变元素的盒模型

注意: 在IE11浏览器中,使用box-sizing:border-box是没有任何效果的,因此如果项目需要兼容IE11浏览器,就需要避免改变flex子项默认的box-sizing属性值

<== flex-basis、width和基础尺寸那些事儿 ==>

说明: 弹性布局中的尺寸表现几乎都是围绕基础尺寸展开的。其中flex-basis属性和width属性都可以用来设置flex子项的基础尺寸,设置的时候遵循以下规则

  • 如果flex-basis属性和width属性同时设置了具体的数值,width属性值会被忽略,优先使用flex-basis的属性值作为基础尺寸

  • 如果flex-basis的属性值是初始值auto,则会使用width属性设置的长度值作为基础尺寸

  • 如果flex-basis和width的属性值都是auto,则会使用flex子项的最大内容宽度作为基础尺寸,此时称为内容尺寸,由于内容尺寸是flex子项的最大内容宽度,也就是文字内容全部一行显示的宽度,因此,往往都是配合flex-shrink属性使用的,通过弹性收缩让文字内容自然换行,这就是flex子项的默认布局表现。因此,要想暴露flex子项真实的内容尺寸,只需要设置flex-shrink属性值为0或者设置flex:none就可以了

.container {
    display: flex;
}

item-basis-width {
    padding: 1em;
    border: 1px solid deepskyblue;
    color: deepskyblue;
    box-sizing: border-box;
    /* 此时这里设置的200px会失效 */
    width: 200px;
    flex-basis: 100px;
}
<div class="container">
    <item-basis-width>项目1</item-basis-width>
    <item-basis-width>项目2</item-basis-width>
    <item-basis-width>项目3</item-basis-width>
    <item-basis-width>项目4</item-basis-width>
</div>

image.png

<== 最小尺寸 ==>

说明: flex-basis属性和width属性在最小尺寸这里存在明显的区别,flex-basis属性下的最小尺寸是由内容决定的,而width属性下的最小尺寸是由width属性的计算值决定的,这个最小尺寸是由最小内容宽度、width属性和min-width属性共同作用的结 果,计算期间遵循以下规则

  • 如果min-width属性值不是auto,则元素的最小尺寸就是min-width的属性值,此时width属性无法影响最小尺寸,哪怕width的属性值大于min-width的属性值

  • 比较width属性的计算值和最小内容宽度的大小,较小的值就是元素的最小尺寸

  • 如果width的属性值和min-width的属性值均为auto,则元素的最小尺寸就是最小内容宽度

  • 如果flex子项设置了overflow:hidden,且最小尺寸是由最小内容宽度决定的,则最小尺寸无效

<== flex-basis与min-width/max-width属性 ==>

说明: 在弹性布局中,大多数min-width/max-width属性能够完成的事情属性flex-basis、flex-grow和flex-shrink都可以完成,不过在单行文字溢出打点效果flex-basis帮不上什么忙

.container {
    width: 300px;
    display: flex;
}

.ellipsis {
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
}
<div class="container">
    <item>宽度不确定项</item>
    <item>
        <p class="ellipsis">
            文字内容文字内容文字内容文字内容文字内容文字内容文字内容
        </p>
    </item>
</div>

image.png

解释: 这里width属性和flex-basis属性都没有设置,因此基础尺寸就是内容尺寸,内容尺寸是最大内容宽度,也就是p元素里面内容在一行显示的宽度;其次flex-shrink属性值是1(默认值),且内容超出,因此弹性收缩是执行的。如果这里的弹性收缩可以顺利执行,则打点效果是可以出现的;width属性和min-width属性都没有设置,因此最小尺寸就是最小内容宽度。然后这里出现了问题,如果<item>里面的<p>元素没有设置white-space:nowrap,那么最小内容宽度就是1em,也就是一个中文字符的宽度(每个中文都是换行点),弹性收缩可以顺利执行。但是这里的<p>元素设置了white-space:nowrap,此时<p>元素就像一个不会换行的连续英文单词,于是<item>元素的最小尺寸就变成了<p>元素内容在一行显示的宽度,和基本尺寸一样,由于最终尺寸计算的优先级是最小尺寸>弹性收缩>基本尺寸,而最小尺寸和基本尺寸一样大,导致弹性收缩无效,最终尺寸就是内容的尺寸,单行打点效果需要内容尺寸大于容器尺寸,这里两者尺寸一样,因此没有打点效果,此时解决办法就是使item元素的最小尺寸变小或无效,让flex-shrink属性可以正常弹性收缩

.container item { 
    min-width: 0;
}

image.png

==> 弹性布局最后一行对齐处理 <==

说明: 在CSS弹性布局中,使用justify-content属性可以控制列表的水平对齐方式,例如属性值space-between可以实现两端对齐。但是,如果最后一行元素的个数不足以填满一行,那么最后一行元素的排列就显得很尴尬了,出现了尺寸明显不一致的间隙,这种情况左对齐才是yyds!!!

.container {
    width: 300px;
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
}

.list {
    width: 24%;
    height: 100px;
    background-color: skyblue;
    margin-top: 15px;
}
<div class="container">
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
</div>

image.png

<== 每一行列数固定 ==>

说明: 如果每一行列数是固定的,可以模拟space-between属性值和间隙大小,也就是 说,我们不使用justify-content: space-between声明模拟两端对齐效果,而使用margin对最后一行内容中出现的间隙进行控制,理论上最好的属性是gap,不过这个属性很多浏览器不支持,因此这个属性无法应用在生产环境

.container {
    width: 300px;
    display: flex;
    flex-wrap: wrap;
    gap: calc(4% / 3);
}

.list {
    width: 24%;
    height: 100px;
    background-color: skyblue;
    margin-top: 15px;
}

image.png

<== flex子项宽度不固定 ==>

说明: 可以给最后一项设置margin-right:auto

.container {
    width: 300px;
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
}

.list {
    background-color: skyblue;
    margin: 10px;
}

/* 最后一项margin-right:auto */
.list:last-child {
    margin-right: auto;
}
<div class="container">
    <div class="list">fre</div>
    <div class="list">wefewr</div>
    <div class="list">fer</div>
    <div class="list">gtrg</div>
    <div class="list">frwe</div>
    <div class="list">frefegt</div>
    <div class="list">fegwtt</div>
</div>

image.png

<== 每一行不列数固定 ==>

说明: 使用足够的空白标签进行填充占位,具体的占位数量是由最多列数的个数决定的。例如布局最多有7列,那我们可以使用7个空白标签进行填充占位;布局最多10 列,那我们需要使用10个空白标签进行填充占位,将占位的元素宽度和margin值设置得 与.list列表元素一样,由于元素高度为0,因此,如此设置并不会影响垂直方向上的 布局呈现

.container {
    width: 400px;
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    margin-right: -10px;
}

.list {
    width: 100px;
    height: 100px;
    background-color: skyblue;
    margin: 15px 10px 0 0;
}

/* 与列表元素一样的元素宽度和margin值 */
.container > i {
    width: 100px;
    margin-right: 10px;
}
<div class="container">
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <i></i><i></i><i></i><i></i><i></i>
</div>

image.png