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

一、前言

这是我学css的最后一本书了,css终于要了解完了,后面就看咋用了!!!这里由于掘金的字符限制,只能分成多篇来分享了

二、预知

解释: 也就是开始学的时候需要了解的一点点知识

(1)理解CSS数据类型

说明: 它定义CSS属性中具有代表性的值,其语法格式为<关键字>,例如数值类 型是<number>、色值类型是<color>

前提: 任何CSS属性值都会包含一个或者多个数据类型,在CSS2.1的时候,数据类型的概念不是很重要,因为常用的就几个,但是在CSS2.1后的情景下,由于CSS各个模块独立发展,没有一个规定去约束,导致出现的新属性很多、出现的速度很快,这样就导致学习的成本增大,因此就根据其特性将一些CSS总结成一个数据类型,然后在学习新属性的时候就只需要记住它支持的数据类型就可以了,不必去记忆所有的属性值名称

举例: 学习background-image这个属性,MDN是下面这样写的,那么它的语法可以写成下面这样:

css 复制代码
background-image: none | <image>

思路: 那上面语法中的<image>是啥呢,其实这就是一种数据类型,在MDN中可以看到下面这样的介绍,可以发现它支持这六个函数,那既然background-image支持这个数据类型,是不是它可以使用这六个函数呢,答案是可以的,在MDN中,你也能看见它支持这六个函数,到这相比你就理解了数据类型的作用了!

举一反一: 还是不理解,那再来一个,比如了解mask-image属性,这个好像平时没怎么看到过,不慌,直接去MDN上looklook,你会发现它同样支持<image>数据类型,不相信?你从它给出的实例就看到它是支持的,不然为什么这样写呢!这样看数据类型对你学习新属性的语法是很有用对吧!

标识: 了解所有的CSS数据类型可以参考这篇文章,这里分享只是将我学到的东西记录下来而已,没有别的,毕竟我不能生产知识!!!

(2)了解CSS属性值定义语法

==> 有啥用? <==

线性渐变语法:

css 复制代码
linear-gradient( [ <angle> | to <side-or-corner> ,]? <color-stop-list> )

说明: 上面这语法大家看得懂嘛,其实我也不懂,好,现在照葫芦画瓢,现在葫芦给你了,然你写一个渐变,不管你是咋写的,反正我真是下面这样写的,这样写有问题吗,语法、功能上没有一丢问题,但是存在瑕疵,就是to bottom可以省略,为啥,这个...学就完了,往下看!!!

css 复制代码
background: linear-gradient(to bottom, deepskyblue, deeppink);

==> 作用,学吧您勒! <==

说明: 语法包含三个部分,关键字、数据类型和符号,以上面线性渐变语法为例,像to这样的就是关键字,<angle>这样的就是数据类型,|这样的就是符号

<== 关键字 ==>

说明: 关键字有两种,一种是普通关键字、一种是全局关键字

  • 普通关键字: 比如auto、none这些,它们只能被部分属性支持

  • 全局关键字: 比如inherit、initial、unset和revert,它们被所有的CSS属性支持

<== 数据类型 ==>

说明: 前面提到过这个哈,这里就不总结了!!!

<== 符号分类 ==>

字面符号: 指CSS属性中原本就支持的合法符号,其数量很少,就两个,一个是,,一个是/

符号 名称 作用
, 并列分隔符 用来分隔几个并列值,或者分隔函数的参数值
/ 缩写分隔符 用来分隔一个值的多个部分,在CSS缩写中用于分离类型相同但属于 不同CSS属性的值,以及用在部分CSS函数中

组合符号: 用于表示数个基本元素之间的组合关系

符号 名称 作用 优先级
并列 符号为普通空格字符,表示各部分必须出现,同时需要按顺序出 现 很低
&& 与组合符 各部分必须出现,但可以不按顺序出现
|| 或组合符 各部分至少出现一个,可以不按顺序出现
| 互斥组合符 各部分恰好出现其中一个 很高
[] 方括号 将各部分进行分组以绕过上面几个符号的优先规则,因此方括号 的优先级最高 非常高

数量符号: 描述一个元素可以出现多少次,数量符号不能叠加出现并且优先级高于组合符号

符号 名称 作用
无数量符号 恰好出现一次
* 星号 可以出现任意次数
+ 加号 可以出现一次或多次
? 问号 可以出现零次或者一次,也就是该元素可有可无
(A,B) 花括号 出现最少A次,最多B次
# 井号 可以出现一次或多次,但多次出现时必须以逗号分隔
! 叹号 表示当前分组必须产生一个值,该符号多出现在组合符号方括 号的后面

<== 使用举例 ==>

举例: 那么上面线性渐变的语法按照符号分类解析后就成下面这样了

解析:

css 复制代码
/* 1标记处:只表示这里需要一个逗号,因此下面这种写法是不行的 */
/* 因为少一个逗号 */
background: linear-gradient(to bottom blue, pink);

/* 2标记处:空格表示要按照顺序来,因此颜色是不能放前面的 */
/* 那么下面这种写法也是不行的,因为顺序问题 */
background: linear-gradient(blue, pink, to bottom);

/* 3标记处:表示角度和方向只能出现一个,因此下面的写法有问题 */
background: linear-gradient(0deg to bottom, blue, pink);

/* 4和5标记处:[]把度数和方向当一个整体,用?限制其出现的次数, */
/* 最多只能出现一次,这也是为啥前面说可以省略的原因吧 */
background: linear-gradient(deepskyblue, deeppink);

(3)了解CSS全局关键字属性

==> inherit <==

说明: 它表示继承的意思,从IE8就开始支持这个关键字了,

适用场景: 它适用的场景比如子元素设置height:inherit实现高度继承,或者子元素设置background- image:inherit实现背景图像继承

==> initial <==

说明: 可以把当前的CSS属性的计算值还原成CSS语法规定的初始值

举例:

html 复制代码
<ul class="initial-ul">
    <li>#追梦人# <small>1亿</small></li>
    <li>#票房# <small>3亿</small></li>
    <li>#醉拳舞# <small>1亿</small></li>
    <li>#余年MV# <small>2亿</small></li>
    <!-- 因此这里会看起来字要大一些 -->
    <li>#熊出没# <small>666</small></li>
</ul>
css 复制代码
.initial-ul {
    font-size: 13px;
}

.initial-ul li:last-child {
    /* CSS规定默认的字体大小为16px */
    font-size: initial;
}

适用场景: 需要将某些CSS样式初始化为初始值但是不知道初始值是啥的时候可以使用,当然,它也能帮助了解某些CSS属性的初始值是啥

注意: 浏览器设置的初始值跟initial关键字是不一样的两个东西

==> unset <==

特性: 如果当前使用的CSS属性是具有继承特性的,如color属性,则等同于使用inherit关键字;如果当前使用的CSS属性是没有继承特性的,如background-color,则等同于使用initial关键字

作用范围: 当一个元素初始状态存在很多样式,然后想将这些样式全部重置但不想一个一个去设置的时候,就可以使用这个unset了,不过它都是和all属性一起使用的,因为单个属性使用就有画蛇添足之意

html 复制代码
<dialog open>举例</dialog>
css 复制代码
dialog {
    all: unset;
    /* 上面进行初始化,下面写自己的样式 */
}

==> revert <==

说明: 将当前元素的样式初始化为浏览器内置的样式

css 复制代码
ol {
    /* 每个li前面都有数字编号 */
    list-style: none;
    list-style-type: revert;
}
html 复制代码
<ol>
    <li>a</li>
    <li>b</li>
    <li>c</li>
</ol>

(4)all属性

作用: 可以重置除unicode-bidi、direction以及CSS自定义属性以外的所有CSS属性

取值: initial、inherit、unset、revert

说明: 它的前两个值没啥实用价值,第三个值可以让任意元素表现的和span元素一样,第四个值可以让元素恢复成浏览器默认的样式

注意: 之所以direction属性不受all影响,是因为direction属性设计将其初始值设为了ltr,而不是auto。现在为了照顾从右往左阅读的场景,direction属性就被设计成不受all属性影响,而unicode-bidi与decoration形影不离,因此两个一起双双不受all的影响

(5)CSS的渐进增强技巧

==> 使用CSS新特性 <==

说明: 比如CSS属性存在百分比的写法,但是有的浏览器支持,有的不支持,不支持就会保持原来的样子,因此不用在意兼容性问题,因为好的浏览器有更好的显示,糟糕的浏览器就只有普通的显示,直接用就好了

css 复制代码
/* 浏览器支持%图片就是圆的,否则就是方的 */
img { 
    border-radius: 50%;
}

==> 利用语法差异实现兼容 <==

举例: IE10+浏览器支持CSS动画属性animation,我们要 实现加载效果就可以使用一个很小的PNG图片,再借助旋转动画。这个方法的优点是资源占用少,动画效果细腻。于是,我们的需求来了,IE9及其以下版本浏览器还是使用传统的GIF动图作为背景, IE10+浏览器则使用PNG背景图外加animation属性实现加载效果

解释: 由于线性渐变函数 linear-gradient()需要IE10+浏览器支持,因此,在IE9浏览器中是无法识别渐变函数的,导致这行属性失效,那么IE9浏览器下的GIF背景图不会被PNG背景图覆盖,也就同样能够实现兼容的效果了

css 复制代码
.icon-loading {
    display: inline-block;
    width: 30px;
    height: 30px;
    /* 所有浏览器识别 */
    background: url(./loading.gif);
    /* IE10+浏览器识别,覆盖上一行background声明 */
    background: url(./loading.png),
                linear-gradient(transparent, transparent);
    animation: spin 1s linear infinite;
}

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

==> 伪类伪元素区分浏览器 <==

原理: CSS选择器语句中如果存在浏览器无法识别的伪类或者伪元素,整个CSS规则集都会被忽略

优点: 可以一次区分多个CSS属性,同时不会影响选择器的优先级

<== IE浏览器和其它浏览器 ==>

IE9+:

css 复制代码
/* 这里的_可以理解为标签选择器,理解为div都可以 */
_::before, .some-class {}

_::after, .some-class {}

_::selection, .some-class {}

_:checked, .some-class {}

_:disabled, .some-class {}

IE10+: 可以使用从IE10才开始支持的与表单验证相关的伪类如:required:optional:valid:invalid

IE11+: 区分IE11+浏览器可以使用::-ms-backdrop伪元 素。::backdrop是一个从IE11开始支持的伪元素,可以控制全屏元素或者元素全屏时候的背景层的样式。在IE11浏览器中使用该元素时需要加-ms-私有前缀

Edge12+: 使用@supports规则

Edge13+: 使用:in-range或者:out-of-range

<== 浏览器类型 ==>

Firefox浏览器: 可以使用一个带有-moz-私有前缀的伪类或伪元素

css 复制代码
_::-moz-progress-bar, .some-class {}

现代浏览器:

css 复制代码
_:default, .some-class {}

webkit内核的浏览器: 只能使用带有-webkit-前缀的伪类,而不能是伪元素,因为Firefox浏览器会认为带有这样前缀的伪元素是合法的

css 复制代码
:-webkit-any(_), .some-class {}

Chrome浏览器: 可以使用带有-ms-前缀的伪元素,因为它认为是合法的

css 复制代码
_::-ms-any, .some-class {}

==> @supports规则完成兼容 <==

作用: 可以用来检测当前浏览器是否支持某个CSS新特性

<== 基础语法 ==>

规则:

css 复制代码
/* 当浏览器支持display:flex的时候,就会匹配.text类名的元素 */
/* 然后为其设置color:red的样式 */
@supports (display: flex) {
    .text { 
        color: red;
    }
}

注意:

  • @supports规则支持操作符进行判断,这些操作符是not、and、or,分别表示否定、并且、或者的意思

  • 在连续判断几个CSS声明的时候,每个CSS声明都是放在()里面的,然后()的连接使用操作符完成

举例:

css 复制代码
/* 支持弹性布局 */
@supports (display: flex) {}

/* 不支持弹性布局 */
@supports not (display: flex) {}

/* 同时支持弹性布局和网格布局 */
@supports (display: flex) and (display: grid) {}

/* 支持弹性布局或者支持网格布局 */
@supports (display: flex) or (display: grid) {}

/* 判断多个CSS声明 */
@supports (display: flex) and (display: grid) and (gap: 0) {} 
css 复制代码
/* 假设写一个判断当前浏览器支持弹性布局,但不支持网格布局 */
/* 这个就不能根据语义写了,可能你会写成这样,下面这两种写法 */
/* 语法是无效的 */
@supports (display: flex) and not (display: grid) {}
@supports not (display: grid) and (display: flex) {}

/* 此时需要根据规则去写,CSS声明放()里面,中间用操作符链接,此时CSS声明 */
/* 就只有支持弹性布局和不支持网格布局两个,这两个放()里面,从语义上看,两 */
/* 者属于并列关系,那么操作符选择and连接就好,那么就得到下面这样的写法 */
/* 至于为啥是这样,等了解了var的语法就明白了 */
@supports (display: flex) and (not (display: grid)) {}

三、已有CSS属性的增强

(1)新的尺寸体系

==> width: fit-content <==

说明: fit-content的作用对应CSS2.1中的包裹性,也就是元素的宽度为这个关键字的时候元素的尺寸就是里面内容的尺寸

举例: 文字少的时候居中显示,文字多的时候居右显示

css 复制代码
.cw-box {
    width: 100px;
    padding: 1em;
    background-color: deepskyblue;
    color: #fff;
}

.cw-content-2 {
    /* 一般写法是这里不用width,而是改成display: table */
    /* 其目的是一样的,我的理解是让内容有一个具体的宽度,让margin */
    /* 生效 */
    width: fit-content;
    margin: auto;
}
html 复制代码
<div class="cw-box">
    <div class="cw-content-2">文字少</div>
</div>
<div class="cw-box">
    <div class="cw-content-2">文字多的时候!!!!!!</div>
</div>

注意: 内联元素实现包裹性可以使用display: inline-block,而块级元素实现包裹性可以使用display: table

优点:

  • 保护了元素原始的display的计算值,降低了维护的成本,比如li元素设置display:table之后,项目符号不会出现、::marker伪元素也会失效

  • 让元素的尺寸有了确定的值

<== 让元素有确定的尺寸 ==>

说明举例: 这个有啥用呢,在CSS里面,有些布局需要元素有明确的尺寸才能实现,比如绝对定位元素使用margin实现水平垂直居中的效果

css 复制代码
/* 弊端在于元素的尺寸是固定的,但很多时候元素的尺寸是未知的 */
/* 可能你会使用transform来实现 */
.cw-dialog {
    width: 300px;
    height: 200px;
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    margin: auto;
    border: solid;
}
css 复制代码
/* 这个的缺点在于占用了transform属性,这会导致元素会被使用包含 */
/* transform属性的动画效果影响,因为CSS动画关键帧中CSS语句的优先级 */
/* 很高,会干扰原来设置的transform的偏移值 */
.cw-dialog {
    position: absolute;
    left: 50%;
    top: 50%;
    border: solid;
    /* transform会被animation动画干扰,导致偏移的失效 */
    transform: translate(-50%, -50%);
    animation: tinyUp 0.2s;
}

@keyframes tinyUp {
    from {
        transform: translateY(5px);
    }
    to {
        transform: translateY(0);
    }
}
css 复制代码
/* 使用fit-content关键字才是最优解,它没有使用transform,因此不会被 */
/* 带有transform的动画影响 */
.cw-dialog {
    width: fit-content;
    height: fit-content;
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    margin: auto;
    border: solid;
    animation: tinyUp 0.2s;
}

@keyframes tinyUp {
    from {
        transform: translateY(5px);
    }
    to {
        transform: translateY(0);
    }
}

<== 对于宽高的兼容性 ==>

说明: 对于width: fit-content而言,新版本的浏览器都支持,为了兼容老版本的浏览器,可以浏览器私有前缀-webkit-和-moz-;而对于height: fit-content来说,只有Firefox浏览器不支持

css 复制代码
.example {
    /* 兼容谷歌 */
    width: -webkit-fit-content;
    /* 兼容火狐 */
    width: -moz-fit-content;
    width: fit-content;
}
css 复制代码
.example {
    height: -webkit-fit-content;
    height: fit-content;
}

注意: min-width属性和max-width属性可以正确渲染fit-content关键字,而max-height和min-height属性设置fit-content关键字虽然语法正确,但没有任何具体的样式表现

==> stretch关键字 <==

说明: 当页面上存在一个没有设置样式的div的时候,这个div的宽度会自动填满可用空间,这种自动填满的行为有三个关键字可以做到,分别是stretch、available和fill-available,它们的作用都是一样的,都可以让元素的尺寸自动填满某一个方向上的可用的空间,这里主要说stretch关键字!

  • stretch: 可以理解为后面两个关键字的结合

  • available: Firefox浏览器独有,需要结合-moz-前缀使用

  • fill-available: webkit浏览器独有,需要结合-webkit-前缀使用

css 复制代码
.element {
    /* 如果需要兼容多种浏览器可以这样写 */
    width: -webkit-fill-available;
    width: -moz-available;
    width: stretch;
}

<== 应用场景 ==>

说明: 在CSS2.1那里分享过宽度分离原则,也就是width不能和margin和padding写在一起,假设一个按钮距离容器左右边缘各15px的间距,但是按钮外层不方便嵌套标签,因此就可以使用stretch关键字了

css 复制代码
/* 由于宽度是自动占满的,因此按钮的宽度是会自动计算的 */
/* 这样就可以省略写box-sizing: border-box了 */
button {
    height: 40px;
    width: -webkit-fill-available;
    width: -moz-available;
    width: stretch;
    margin-left: 15px;
    margin-right: 15px;
}

注意: IE和Chrome浏览器不支持这个关键字,所以只能去使用calc()函数做兼容了

css 复制代码
/* 这个的缺点在于每次margin和padding的值改变都要去改calc的值 */
/* 也就是多一步手动计算 */
button {
    height: 40px;
    width: calc(100% - 30px);
    margin-left: 15px;
    margin-right: 15px;
    box-sizing: border-box;
}

<== Firefox中的兼容问题 ==>

场景: table元素默认尺寸表现为收缩,因此其宽度需要自适应外部容器,那么就很适合使用stretch关键字,然而在Firefox浏览器中,对tableinline-table水平的元素的渲染存在问题,这些元素设置width:-moz-available的效果和设置width:100%是一样的,因此在初始化table的CSS样式的时候可以像下面这样

css 复制代码
table {
    width: 100%;
    width: -webkit-fill-available;
    /* width: -moz-available; */
    width: stretch;
    table-layout: fixed;
    box-sizing: border-box;
}

==> min-content关键字 <==

说明: 这指的是CSS2.1中的首选最小宽度,哪里说到过元素的尺寸由content-box、padding-box、margin-box以及content-box所占据的尺寸决定,前三个盒尺寸的表现规则会因为元素的不同而不同,最后一个盒尺寸会因为内容的不同使其首选最小宽度也不同,这里说一下最后一个盒尺寸

<== 替换元素 ==>

特点: 替换元素的首选最小宽度是当前元素内容自身的宽度

html 复制代码
<!-- 如果图片的大小是是256 × 192px,那么section元素的首选 -->
<!-- 最小宽度就是256 x 192px -->
<section>
    <img src="1.jpg" alt="" />
</section>

<== 中文、日文、韩文 ==>

特点: 如果是一段没有标点的中文文字,则首选最小宽度是单个汉字的宽度

html 复制代码
<p>感谢您的支持</p>
css 复制代码
p {
    width: min-content;
    outline: 1px dotted;
}

注意: 如果这段中文文字包含避头标点或避尾标点,同时line-break的属性值不是anywhere,则最终的首选最小宽度需要包含标点字符的宽度

  • 避头标点: 指不能在开头显示的标点,例如逗号、句号、问号、顿号、叹号等

  • 避尾标点: 指不能放在尾部的标点,例如前引号、前括号等

html 复制代码
<p>感谢您的支持!</p>

了解: 中文破折号,在IE浏览器和Edge浏览器中它既是避头标点,又是避尾标点;在Firefox浏览器中它是避头标点,不是避尾标点;在Chrome等webkit浏览器中它既不是避头标点,也不是避尾标点。但是,无论在哪个浏览器中,连续的中文破折号都会被认为是一个字符单元

html 复制代码
<p>感谢------------比心</p>

<== 非中文、非日文、非韩文 ==>

特点: 由字符单元的宽度决定的,所有连续的英文字母、数字和标点都被认为是一个字符单元,直到遇到中断字符,对于中断字符的规定,不同的浏览器是不一样的

原则: 宽度尽可能小,行数尽可能少

  • 所有浏览器: 空格都是可以作为中断字符的

  • webkit浏览器: 短横线、英文问号和各种前括号都可以作为中断字符。其中,短横线和英文问号只有当后面是字母或数字的时候才会中断字符单元,前括号则只有当前面不是字母和数字的时候才会中断字符单元

  • Firefox浏览器: 英文问号不能作为中断字符,但短横线可以,不过后面的字符必须是字母而不能是数字,前括号的中断规则和webkit浏览器一致

  • IE浏览器: 英文问号不能作为中断字符,而短横线可以,但是要求短横线前后是由字母、数字或短横线组成的字符单元,且这个字符单元的长度要大于1,其次各种前括号也可以作为中断字符,%也是可以的

举一反一: 一般这个min-content是不会使用的,但是它能够帮助了解一些行为,比如连续英文字符不换行,那是不是寻找一下中断字符的位置,就明白了呢!

css 复制代码
/* content-box的宽度不会小于首选最小宽度 */
p {
    width: 100px;
    border: 1px solid deepskyblue;
}
html 复制代码
<p>https://ngabbs.com-1.1/</p>

<== 最终首选最小宽度 ==>

特点: 一个元素最终的首选最小宽度是所有内部子元素中最大的那个首选最小宽度值

html 复制代码
<section style="width: min-content">
    <img src="./1.jpg" />
    <p>感谢您的支持</p>
    <p>感谢您的支持!</p>
    <p>感谢------------比心</p>
</section>

==> max-content关键字 <==

作用: 让元素尽可能大,保证图文内容在一行显示,哪怕最终的宽度溢出外部容器元素一般在能够使用white-space:nowrap的地方都能够使用width: max-content

html 复制代码
<div class="container">
    <p>可以让元素尽可能的大,保证图文内容在一行显示。</p>
</div>
css 复制代码
.container {
    width: 100px;
    border: solid deepskyblue;
}

.container > p {
    width: max-content;
}

(2)CSS逻辑属性

说明: CSS2.1的时候,属性的定位是基于方向的,这个和文档流从左到右是不一样的,也就是当文档流的方向改变的时候,它还是基于某个方向作用的。看下面的例子

html 复制代码
<!-- 标准文档流的情况 -->
<p>
    <button>确定</button>
    <button>取消</button>
</p>

<!-- 改变文档流的情况 -->
<p style="direction: rtl">
    <button>确定</button>
    <button>取消</button>
</p>

<!-- 使用逻辑属性解决 -->
<p style="direction: rtl">
    <button class="test">确定</button>
    <button class="test">取消</button>
</p>
css 复制代码
button {
    margin-right: 10px;
}

p {
    width: 200px;
    border: 1px red solid;
}

.test {
    margin-right: 0;
    margin-inline-end: 10px;
}

解释: 改变文档流的方向后,margin-right属性的方向是不变的,还是表示距离右侧,此时右侧就会多出10px的间距,这不是想要的结果,应当是左侧出现间距才对,此时就可以使用逻辑属性margin-inline-end,表示内联元素文档流结束的方向,当文档流的方向是从左往右的时候,margin-inline-end属性的渲染表现就等同于margin-right属性;当文档流的方向是从右往左的时候,margin-inline-end属性的渲染表现就等同于margin-left属性,从而第三行的右侧间距就消失了

==> 使用场景 <==

说明: 逻辑属性需要结合writing-mode属性、direction属性或者text-orientation属性使用才有意义

作用: 对称布局

html 复制代码
<div class="msg-list">
    <header class="msg-header">XX群</header>
    <section class="msg-item">
        <img class="msg-avator" alt="桐须真冬" src="../images/bg-1.jpg" />
        <div class="msg-info">
            <span class="msg-user">桐须真冬</span>
            <div class="msg-txt">
                <p>内容</p>
            </div>
        </div>
    </section>

    <section class="msg-item" data-self>
        <img class="msg-avator" alt="唯我成幸" src="../images/bg-5.jpg" />
        <div class="msg-info">
            <span class="msg-user">唯我成幸</span>
            <div class="msg-txt">
                <p>回答</p>
            </div>
        </div>
    </section>
</div>
css 复制代码
.msg-header {
    line-height: 48px;
    color: #fff;
    font-weight: bold;
    text-align: center;
    background-color: #222;
    margin-bottom: 10px;
}

.msg-list {
    width: 414px;
    max-width: 100vw;
    margin-left: auto;
    margin-right: auto;
    background-color: #ebebeb;
    overflow: hidden;
}

.msg-item {
    display: flex;
    padding: 7px;
    margin-bottom: 15px;
    margin-inline-end: 44px;
}

.msg-avator {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    object-fit: cover;
}

.msg-info {
    flex: 1;
    text-align: start;
    padding: 0 10px;
    overflow: hidden;
}

.msg-user {
    font-size: 13px;
    color: #949ead;
}

.msg-txt {
    position: relative;
    width: -moz-fit-content;
    width: fit-content;
    background: #fff;
    border-color: #fff;
    font-size: 14px;
    line-height: 1.5;
    color: #000;
    padding: 0.6em 1em;
    margin: 5px 0 0;
    border-radius: 6px;
}

.msg-txt > p {
    unicode-bidi: plaintext;
}

.msg-user + .msg-txt::before {
    content: "";
    position: absolute;
    border: 0.5rem solid transparent;
    border-top-color: inherit;
    border-inline-end-color: inherit;
    margin-inline-start: calc(-0.45rem - 1em);
    top: 4px;
}

/* 自己 */
.msg-item[data-self] {
    direction: rtl;
}

.msg-item[data-self] .msg-txt {
    background: #9ce553;
    border-color: #9ce553;
}

注意: CSS中还有其他一些CSS属性值也可以改变DOM元素的呈现方向,例如flex-direction属性中的属性值row-reverse和column-reverse,但是请注意,这些属性值和CSS逻辑属性之间没有任何关系

css 复制代码
.flex {
    width: 300px;
    display: flex;
    /* 改变呈现位置后还是左边框 */
    flex-direction: row-reverse;
}

.item {
    flex: 1;
    padding: 40px;
    /* 左边框 */
    border-inline-start: 1rem solid deepskyblue;
    background-color: azure;
}
html 复制代码
<div class="flex">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
</div>

==> 逻辑属性方向表示 <==

说明: 方向不是分上右下左嘛,这里也一样存在,只不过是使用inline/block与start/end这两组来表示的,前者表示方向,后者表示起始方位,默认情况不是水平从左往右嘛,以margin为例,就会得到下面的转化

css 复制代码
margin-left     ↔   margin-inline-start
margin-top      ↔   margin-block-start
margin-right    ↔   margin-inline-end 
margin-bottom   ↔   margin-block-end

解释:

  • inline元素默认是从左往右水平排列的;block元素默认是从上往下垂直排列的。因此,margin-inline-start就表示内联元素排列方向的起始位置,即"左侧";margin-inline-end就表示内联元素排列方向的终止位置,即"右侧"。 如果设置direction:rtl,则水平文档流方向就是从右往左, 此时start对应的就是右侧,end对应的就是左侧

  • 如果设置 writing-mode:vertical-rl属性,把文档流改为垂直且从右往左排列,则此时内联元素是从上往下排列的。inline指的是垂直方向,block指的是水平方向

注意: margin、padding、border都是存在逻辑属性的,按照上面那样组合就好了

==> width / height相关的逻辑属性 <==

理解: 其实很好记忆,比如inline,就会想起inline元素,默认水平的嘛,那这不是宽度所需要的特性嘛,那么inline就可以理解为width,那么height也是一样的

css 复制代码
/* width相关 */
width <=> inline-size
min-width <=> min-inline-size
max-width <=> max-inline-size

/* height相关 */
height <=> block-size
min-height <=> min-block-size
max-height <=> max-block-size

==> text-align支持的逻辑属性 <==

说明: 它只有两个,分别是start和end,表示起始和结束

==> inset属性 <==

说明: 在CSS2.1中使用的left、top、right、bottom属性,在CSS2.1后可以使用inset属性代替,可以像下面这样理解inset属性的语法,也就是平时需要四个值都写0的情况直接使用inset: 0代替就可以了

css 复制代码
inset: top right bottom left

(3)高级的border

标识: 这个地方我也是懵的,只能按照理解来解释,所以可能存在些错误哈,欢迎大家的指正

==> border-image <==

<== 九宫格 ==>

css 复制代码
div {
    width: 80px;
    height: 80px;
    border: 40px solid deepskyblue;
}

解释: 假设一个div的样式是上面那样,沿着这个div的content-box的边缘划线,就可以看到这个div被划分为9个部分,也就是九宫格,因此使用这个属性注意两点就好,一是源图像的划分,二是九宫格尺寸的控制

举例: 假设有一张162px×162px的源图像如下,将它放在九宫格里面

css 复制代码
div {
    width: 80px;
    height: 80px;
    border: 40px solid deepskyblue;
    border-image: url(./grid-nine.svg) 54;
}

说明: 上面使用的url() 45其实是border-image-source属性和border-image-slice属性的缩写,border-image-source属性的值是一个<image>数据类型, 所以CSS中所有图像类型都可以作为边框图片,因此border-image属性可以实现渐变边框或者条纹边框效果,它的语法和background-image是类似的

<== border-image-slice ==>

语法: 支持1~4个数值或1~4个百分比值,后面可以带一个关键字fill

css 复制代码
border-image-slice: <number-percentage>{1,4} && fill?

作用: 对原始图像进行划分,遵循上右下左的顺序

说明: 它不是支持四个值嘛,这四个值表示四条裁剪线,分别表示举例上面多少,右面多少,下面多少和左面多少举例,线画完之后,默认情况将四条线围成的那个区域去掉,也就是9号位置是空白的;如果四条裁剪线没有围成一个区域,那么9号区域就是空白的,1、2、4、3此时所占的比例不变,是多少就是多少,然后5、6、7、8四处的区域进行拉伸,它不是有一个fill关键字嘛,这个关键字就是来显示9号区域的,也就是将围成的那个区域显示出来

举例: border-image-slice:20

注意: 如果上裁剪线在下裁剪线的下面,此时发生裁剪线的反向交叉会导致5、7区域的内容不可见,左右裁剪线也是同理,而这个属性的默认值是100%,因此只能看见四个角所显示的区域,也就是只能看见1、2、3、4

<== border-image-width ==>

说明: border-image-width与border-with属性支持的参数是一致的,区别在于支持的属性值类型存在区别,如下:

值类型 border-with border-image-with
初始值 medium 1
长度值
数值(作为系数) ×
百分比值 ×
关键字属性值 thin / medium / think auto
负值 × ×

数值: border-image-width属性支持使用数值作为属性值,这个数值会作为系数和border-width的宽度值相乘,最终的计算值作为边框图片宽度,也就是九宫格的宽度。如果宽高是固定的,那么系数越大,边框越大,这样得到中间可以看到的区域也就越来越小,因为会被边框占据,根据裁剪线的划分看,内容越来越小的时候,九宫格的1、2、3、4区域会很大,也就是四个角的地方会很大,而5、6、7、8四周的区域内容会越来越小

长度值: 如果是具体的长度值,则九宫格的宽度与border-with属性没有任何关系,但是如果border-with的宽度为0的时候,在Chrome浏览器中,边框会消失,但是在其它浏览器没有这个问题,因此,如果我们希望边框宽度为0,且border-image属性能生效,可以试试将border-width属性的值设置为0.02px

百分比值: 相对于元素自身的尺寸计算的,水平方位相对于宽度计算,垂直方位相对于高度计算

css 复制代码
div {
    border-image: url(./grid-nine.svg) 54;
    border-image-width: 50% 25%;
}

auto关键字: 把操作的权利交给border-image-slice属性,也就是使用border-image-slice属性划分的尺寸作为九宫格的宽度值

<== border-image-outset ==>

说明: 上面那个属性用于控制1-8号区域的大小,这个用于控制9号区域的大小,因此它们的语法是一致的,有一个区别在于border-image-outset是支持负值的,所以在使用上面下面的写法都是可以的

css 复制代码
/* 长度值 */
border-image-outset: 1rem;

/* 数值 */
border-image-outset: 1.5;

/* 垂直 | 水平 */
border-image-outset: 1 0.5;

/* 上 | 垂直 | 下 */
border-image-outset: 30px 2 40px;

/* 上 | 右 | 下 | 左 */
border-image-outset: 10px 15px 20px 25px;

<== border-image-repeat ==>

作用: 控制5-8号区域的内容的平铺规则

语法: 这里可以看到水平和垂直方向上面的两条边其规则是一样的

css 复制代码
  border-image-repeat: [ stretch | repeat | round | space ]{1,2}
  • stretch:默认值,让源图像拉伸以充满显示区域。

  • repeat:让源图像紧密相连平铺,保持原始比例,平铺单元在 边界位置处可能会被截断。

  • round:让源图像紧密相连平铺,适当伸缩,以确保平铺单元在 边界位置处不会被截断

  • space:让源图像保持原始尺寸,平铺时彼此保持适当的等宽间隙,以确保平铺单元在边界位置处不会被截断;如果区域的尺寸 不足以呈现至少一个源图像单元,则会以空白呈现。

<== 缩写语法 ==>

语法:

css 复制代码
border-image: url() slice / width / outset repeat

解释: 标准的语法太长了,大致就这三部分组成,如果每一部分值都写完整的话,那就像下面这样很长了,需要注意的是,第一部分必须有,后面两部分可有可无

css 复制代码
div {
    border-image: url(./grid-nine.svg) 54 33.33% 33.33% 54 / 10px 20px 30px 1 / 1 30px 20px 10px round space;
}

==> 渐变边框 <==

<== 圆角渐变边框 ==>

注意: border-radius属性无法改变border-image属性生成的图形效果

css 复制代码
.border-gradient {
    padding: 30px;
    border-style: solid;
    border-image: linear-gradient(deepskyblue, deeppink) 20 / 10px;
}

.father {
    border-radius: 10px;
    overflow: hidden;
}

.clip-path {
    -webkit-clip-path: inset(0 round 10px);
    clip-path: inset(0 round 10px);
}
html 复制代码
<div style="width: 200px">
    <h4>1. 父元素圆角</h4>
    <div class="father">
        <div class="border-gradient">圆角渐变边框</div>
    </div>

    <h4>2. clip-path剪裁</h4>
    <div class="border-gradient clip-path">圆角渐变边框</div>
</div>

<== 轮廓模拟 ==>

说明: CSS中有三个属性能产生不影响布局的轮廓扩展,分别是outline、box-shadow、border-image,它们的对比如下:

属性 支持渐变 支持模糊 支持圆角 间隙控制 方位控制
outline × × ×(Firefox) ×(Edge15+) ×
box-shadow × ×
border-image ×(渐变模拟) ×

结论:

  • 如果需要轮廓带有渐变效果,一定是使用border-image属性。

  • 如果需要轮廓效果是纯色,且4个角为直角,则优先使用 outline属性;

  • 如果outline属性不能使用,则使用box-shadow属性;

  • 如果box-shadow属性已经有 了其他样式,则使用border-image属性。

  • 如果需要轮廓有圆角效果,则一定是使用box-shadow属性。

  • 如果需要轮廓和元素之间还有一段间隙,则优先使用outline属 性;

  • 如果outline属性不能使用,则使用border-image属性。

  • 如果需要轮廓只有一个方向,则不考虑outline属性。

  • 如果需要兼容IE浏览器,则border-image属性不考虑。

注意: 由于border属性的缩写中包含了border-image相关属性的信息,因此border不能放在border-image下面

(4)position: sticky

说明: 假设作用在导航栏上面,那么当导航元素在屏幕内的时候,导航元素滚动跟随;当导航元素就要滚出屏幕的时候,导航元素固定定位,它属于相对定位的延伸,但是存在一定的区别

==> 与相对定位的区别 <==

<== 可滚动元素的影响 ==>

说明: 通常的Web页面都是窗体滚动的,而黏性定位偏移计算的元素是层级最近的那个滚动元素。因此,如果黏性定位元素的某个祖先元素的overflow属性值不是visible,那么窗体滚动的时候就不会有黏性定位效果

html 复制代码
<div>
    <nav></nav>
</div>
css 复制代码
/* 此时发现浏览器的窗口滚动的时候nav元素是没有粘性效果的,因为 */
/* 它的黏性定位的偏移计算是相对于父级div进行计算的,因此只有div */
/* 可以滚动的时候才能体现出nav元素的粘性效果 */
div {
    overflow: hidden;
}

nav {
    position: sticky;
    top: 0;
}

注意: 如果你的网页使用的是窗体滚动,又希望有黏性效果,那务必保证黏性定位元素的祖先元素中没有可滚动元素。

<== 黏性定位的计算规则 ==>

实质: 粘性定位效果是否能够实现是在于黏性约束矩形的高度是否大于黏性元素的高度,如果小于或者等于,你会发现黏性元素是没有黏性效果的,因为黏性定位元素已经完全没有了实现黏性效果的空间

  • 流盒: 指的是黏性定位元素最近的可滚动元素的尺寸盒子,如果没有可滚动元素,则表示浏览器视窗盒子

  • 黏性约束矩形: 简单来说就是黏性定位元素的包含块(通常是父元素)与流盒相交的那一个矩形,由于滚动的时候流盒是不变的,而黏性定位元素的包含块会跟着移动,因此这个矩形是会动态变化的

举例和现象: 看图

html 复制代码
<div>
    <nav>导航</nav>
</div>
css 复制代码
div {
    height: 100px;
    margin-top: 50px;
    border: solid deepskyblue;
}

nav {
    position: sticky;
    top: 20px;
    background: lightskyblue;
}

了解: 由于黏性元素设置了top: 20px,那么流盒的起始位置就是浏览器往下20px的那个地方,就是上面红色的;黏性元素的包含块也就是那个div;那么黏性约束矩形就是黑方框与红色背景色相交的地方

理解: 最开始设置的margin的值比top的值大,那么此时滚动的时候黏性元素nav是会跟着div往上移动的,也就是没有粘性效果,当div的上边框与红色的上边框重合的时候,就产生黏性效果了,此时nav元素会一直紧紧贴住红色的上边框,不过滚动还在继续,div也还会向上移动,这样得到的结果就是粘性约束矩形的高度越来越小,当高度与黏性元素的高度一样的时候,由于黏性定位元素不能超出黏性约束矩形范围的限制,已经没有空间来体现粘性元素的黏性效果了,也就是黏性会失效,之后就跟着div一起滚走了

  • 特性: 如果黏性定位元素的父元素的高度和黏性定位元素的高度相同, 则垂直滚动的时候,黏性定位效果是不会出现的

<== 堆叠规则 ==>

特性: 如果多个黏性定位元素在同一容器中,则这几个黏性定位元素会产生元素重叠的情况;如果黏性定位元素分布在不同容器中,同时这些容器在布局上是上下紧密相连的,则视觉上会表现为新的黏性定位元素挤开原来的黏性定位元素, 形成依次占位的效果

html 复制代码
<h4>同一个父元素,重叠覆盖</h4>
<h6>A</h6>
<ul>
    <li>Alice</li>
    <li>暗香</li>
    <li>Ares-徐舟</li>
</ul>
<h6>B</h6>
<ul>
    <li>贝贝王爷有点萌</li>
    <li>Blue含资</li>
    <li>不吵不闹</li>
    <li>不动的飞矢、大奔</li>
</ul>
<h6>C</h6>
<ul>
    <li>- Ccccccc张磊</li>
    <li>采蘑菇的小姑娘</li>
    <li>Cecilia_yu</li>
    <li>陈玲</li>
    <li>虫儿飞</li>
    <li>窗棂微风-高晨萱</li>
    <li>从此以后。。。</li>
    <li>CSS conf的好友</li>
</ul>
<h6>D</h6>
<ul>
    <li>大白鲨</li>
    <li>大猫猫</li>
    <li>大漠</li>
    <li>大嘴</li>
    <li>DARKEN</li>
    <li>Double宜-前端开发小萌新</li>
    <li>Dream</li>
</ul>

<h4>不同的父元素,依次推开</h4>
<dl>
    <dt>A</dt>
    <dd>Alice</dd>
    <dd>暗香</dd>
    <dd>Ares-徐舟</dd>
</dl>
<dl>
    <dt>B</dt>
    <dd>贝贝王爷有点萌</dd>
    <dd>Blue含资</dd>
    <dd>不吵不闹</dd>
    <dd>不动的飞矢、大奔</dd>
</dl>
<dl>
    <dt>C</dt>
    <dd>- Ccccccc张磊</dd>
    <dd>采蘑菇的小姑娘</dd>
    <dd>Cecilia_yu</dd>
    <dd>陈玲</dd>
    <dd>虫儿飞</dd>
    <dd>窗棂微风-高晨萱</dd>
    <dd>从此以后。。。</dd>
    <dd>CSS conf的好友</dd>
</dl>
<dl>
    <dt>D</dt>
    <dd>大白鲨</dd>
    <dd>大猫猫</dd>
    <dd>大漠</dd>
    <dd>大嘴</dd>
    <dd>DARKEN</dd>
    <dd>Double宜-前端开发小萌新</dd>
    <dd>Dream</dd>
</dl>
css 复制代码
h6, dt {
    position: -webkit-sticky;
    position: sticky;
    top: 0;
    background-color: #eee;
    color: #444;
    padding: 3px 1rem;
}

li, dd {
    padding: 5px 1rem;
    border-top: 1px solid #f5f5f5;
}

原因: 当我们的黏性定位元素分布在不同容器的时候,就会有多个不同的黏性约束矩形。这些黏性约束矩形正好一个一个排列得很整齐,于是在视觉上就表现为上一个黏性定位元素被滚走,下一个黏性定位元素正好开始有黏性效果。当我们的黏性定位元素都在一个容器里的时候,大家都共用一个巨大的黏性约束矩形,因此,滚动的时候元素会一个一个不断往上重叠

(5)字体新特性

==> 全新的通用字体族 <==

说明: 字体族表示一个系列字体,而非单指具体某一个字体。字体族又分为普通字体族和通用字体族,通用字体族数量有限,它包括以下几种,这些在CSS2.1中提到过,这里说一下全新的通用字体system-ui、emoji、math、fangsong

  • serif: 衬线字体,指笔画有粗有细,开始和结束带有装饰的字体

  • sans-serif: 无衬线字体,指笔画粗细均匀,没有额外装饰的字体

  • monospace: 等宽字体,指所有字形具有相同的固定宽度的字体

  • cursive: 手写字体,中文中的楷体就属于手写字体

  • fantasy: 奇幻字体,主要用来装饰和表现效果,字形和原本字符可以没有关系

<== system-ui ==>

说明: 这个表示系统UI字体,在过去,如果想要使用系统字体,只能使用font:menu、font:status-bar等CSS声明,这些属性值是包含字号的,不同操作系统的字号还不一样,因此会十分麻烦,而system-ui的出现就解决了这个问题,它避免了使用具体字体所产生的一些问题,比如下面这些:

  • 字体可能会相互冲突,比如有些用户给自己的Windows操作系统安装了苹方字体,但显示器密度并没有跟上,导致网页里显示 的字体效果很奇怪,文字瘦瘦的,边缘糊糊的,不利于阅读

  • 系统升级后可能有了更适合网页的字体

注意: 由于存在兼容问题,因此还需要其它字体族来进行辅助,如果需要设置系统字体,推荐下面这样

css 复制代码
/* 缺少emoji字体的设置,因此下面的设置是不完整的 */
body { 
    /* -apple-system:Firefox和Safari 9.1~ Safari 10.1 */
    /* Segoe UI:Windows操作系统上以最佳的西文字体显示 */
    /* Roboto:在Android操作系统上以最佳的西文字体显示 */
    /* Helvetica:macOS和iOS中很常用的一款无衬线字体 */
    /* Arial:较老版本的Windows操作系统 */
    font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
}

<== emoji ==>

说明: 主流的浏览器都内置了emoji字体,但是某些emoji字符不会显示为彩色图形,需要专门指定的emoji字体,由于每次都需要指定,因此可以专门定义一个emoji字体,由于emoji字体会影响普通的文本并且Unicode的字符范围也会影响emoji的颜色,因此如果需要设置为系统字体,可以设置成下面这样

css 复制代码
@font-face {
    font-family: Emoji;
    /* Apple Color Emoji用在Apple的产品中的 */
    /* Segoe UI Emoji是用在Windows操作系统中的emoji字体 */
    /* Segoe UI Symbol是在Windows 7操作系统中添加的一种新字体 */
    /* Noto Color Emoji是谷歌的emoji字体 */
    src: local("Apple Color Emoji"), local("Segoe UI Emoji"),
         local("Segoe UI Symbol"), local("Noto Color Emoji");
    unicode-range: U+1F000-1F644, U+203C-3299
}

body { 
    font-family: system-ui, -apple-system, Segoe UI, Roboto, Emoji, Helvetica, Arial, sans-serif; 
}

衬线字体和等宽字体初始化:

css 复制代码
.font-serif {
    font-family: Georgia, Cambria, "Times New Roman", Times, serif;
}
.font-mono {
    font-family: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}

<== math ==>

说明: 主要用于展现数学公式,一般使用MathML语言去进行书写就好了,某些浏览器不支持这种语言,此时需要对数学标签进 行CSS重定义,推荐下面这样写

css 复制代码
math { 
    /* Cambria Math是Windows操作系统中的数学字体,*/
    /* Latin Modern Math是macOS中的数学字体。 */
    font-family: Cambria Math, Latin Modern Math;
}

<== fangsong ==>

说明: 这个字体族来自中文字体仿宋,仿宋是介于宋体和楷体之间的一种字体。和宋体相比,仿宋笔画的水平线通常是倾斜的,端点修饰较少,笔画宽度变化较小。一般非常正式 的公告才会用到这个字体,平常开发项目中很少用到

css 复制代码
article { 
    font-family: fangsong;
}

==> local() 函数的好处 <==

作用: 这个函数用于调用系统安装的字体

简化字体调用: 就是不用写一长串字体名作为font-family的属性值了,直接通过local函数进行字体引入就好了

css 复制代码
@font-face {
    font-family: Mono;
    src: local("Menlo"), local("Monaco"), local("Consolas"),
         local("Liberation Mono"), local("Courier New"), local("monospace");
}

.code {
    font-family: Mono;
}

自定义字体场景下提高性能:

css 复制代码
@font-face {
    /* 可以让已经安装了Roboto字体的用户无须发 起额外的Roboto字体请求,*/
    /* 优化了这部分用户的使用体验 */
    font-family: Roboto;
    font-style: normal;
    font-weight: 400;
    src: local("Roboto"), local("Roboto-Regular"),
         url(./Roboto.woff2) format("woff2");
}

==> unicode-range 属性 <==

作用: 决定自定义的字体作用在哪些字符上

属性值写法: U+加上目标字符的Unicode编码或者Unicode范围。初始值为U+0-10FFFF,也就是所有字符集

css 复制代码
/* 单个字符编码 */
unicode-range: U+26;

/* 字符编码区间 */
unicode-range: U+0-7F;
unicode-range: U+0025-00FF;

/* 通配符区间 */
/* ?理解为占位符,表示0-F,因此,U+4??表示从U+400到U+4FF */
unicode-range: U+4??;

/* 多个值 */
unicode-range: U+0025-00FF, U+4??;

<== 常用Unicode编码值 ==>

  • 基本汉字:二进制为[0x4e00,0x9fa5],十进制为[19968,40869]
  • 数字:二进制为[0x30,0x39],十进制为[48, 57]
  • 小写字母:二进制为[0x61,0x7a],十进制为[97, 122]
  • 大写字母:二进制为[0x41,0x5a],十进制为[65, 90]

注意: 如果需要知道某一个字符的具体Unicode的值,可以使用JavaScript的codePointAt()方法

==> font-display属性 <==

前提: 假设存在一个自定义字体,那么浏览器加载字体的时候,会先将引用这个字体的文本隐藏,等自定义字体加载出来再显示,如果这个过程超过3秒,则会使用其它的字体来代替,这对于图标字体来说是可行的,不过对于普通文本来说,有利有弊,弊端在于会出现加载空白,此时font-display属性就出现了,它可以控制字体加载和文本渲染之间的时间线关系

<== 字体显示时间线 ==>

说明: 字体显示时间线开始于浏览器尝试下载字体的那一刻,整个时间线分为3个时段,浏览器会在这3个时段让元素表现出不同的字体渲染行为

  • 字体阻塞时段:如果未加载字体,任何试图使用它的元素都必须以不可见的方式渲染后备字体;如果在此期间字体成功加载,则正常使用它。

  • 字体交换时段:如果未加载字体,任何试图使用它的元素都必须 以可见的方式渲染后备字体;如果在此期间字体成功加载,则正常使用它。

  • 字体失败时段:如果未加载字体,则浏览器将其视为加载失败,并使用正常字体进行回退渲染

<== 语法 ==>

css 复制代码
font-display: [ auto | block | swap | fallback | optional ]

说明:

  • auto:字体显示策略由浏览器决定,大多数浏览器的字体显示策略类似block。 只

  • block:字体阻塞时段较短(推荐3s),字体交换时段无限。此值适合图标字体场景。

  • swap:字体阻塞时段极短(不超过100ms),字体交换时段无限。此值适合用在小段文本,同时文本内容对页面非常重要的场景。

  • fallback:字体阻塞时段极短(不超过100ms),字体交换时段较短(推荐3s)。此值适合用于大段文本,例如文章正文,同时对字体效果比较看重的场景,例如广告页面、个人网站等。

  • optional:字体阻塞时段极短(不超过100ms),没有字体交换时段。此值的作用可以描述为,如果字体可以瞬间被加载(例如已经被缓存了),则浏览器使用该字体,否则使用回退字体。 optional是日常Web产品开发更推荐的属性值,因为无论任何时候,网页内容在用户第一次访问时快速呈现是最重要的,不能让用户等待很长时间后再看到你认为的完美效果。

(6)中断与换行

默认换行规则:

  • Space普通空格、Enter(回车)空格和Tab(制表符)空格这3种空 格无论怎样组合都会合并为单个普通空格

  • 文字可以在CJK文本、普通空格和短横线连字符处换行,连续英 文单词和数字不换行

==> keep-all属性值 <==

说明: 这是word-break属性的一个属性值,它可以让CJK文本不换行排版,同时又不影响非CJK文本的排版行为

举例: 中文虽然是一个字一个字拼起来的,但是有些文字的组合是固定 的,不建议断开,如人的姓名、一些固定的词组等。然而默认的排版规则会断开这些姓名和词组,keep-all属性值可以用来优化这个排版细节

html 复制代码
<h4>排版优化</h4>
<table class="keep-all">
    <thead>
        <tr>
            <th>会议时间</th>
            <th>会议地点</th>
            <th>会议人员(3)</th>
            <th>会议内容</th>
        </tr>
    </thead>
    
    <tbody>
        <tr>
            <td>2021年2月28日</td>
            <td>6号楼3楼伏羲会议室</td>
            <td class="keep-all">张三 李四 王二麻子</td>
            <td>讨论字符单元的中断与换行,以及如何组织内容让表达效果最好</td>
        </tr>
    </tbody>
</table>
css 复制代码
.keep-all th,
td.keep-all {
    word-break: keep-all;
}

==> break-all属性值 <==

说明: 这同样是word-break的属性值,用来让连续的英文和数字可以换行

css 复制代码
p {
    width: 150px;
    padding: 10px;
    border: solid deepskyblue;
}
.break-all {
    word-break: break-all;
}
html 复制代码
<p>本节会大量出现"CJK文本"这个词。</p>
<p class="break-all">本节会大量出现"CJK文本"这个词。</p>

注意: 连续的破折号、连续的点字符,以及避首标点在设置word-break:break-all声明后无法换行

html 复制代码
<p>本节会大量出现"CJK文本"这个词。---------------------------------------------</p>
<p class="break-all">本节会大量出现"CJK文本"这个词。---------------------------------------------</p>

解决: 如果希望上面所说的三种不换行的情况能够换行的话,可以使用break-word属性值,有三个属性支持这个属性值分别是word-break: break-wordword-wrap: break-wordoverflow-wrap: break-word,它们的作用都是一样的,不过IE和Edge不支持overflow-wrap,也不支持word-break:break-word声明,因此换行控制可以这样写

css 复制代码
p {
    /* 字符换行主力 */
    word-break: break-all;
    /* 兼容IE浏览器和Edge浏览器的破折号换行 */
    word-wrap: break-word;
}

了解: 如果希望中文标点也可以换行,可以使用line-break属性

==> hyphens: manual <==

说明: 表示单词在有换行机会的时候才换行,其中一个常见的换行机会就是连字符,连字符分为硬连字符和软连字符,前者称为可见的换行机会,也就是键盘上面的-,后者是默认是隐藏的,只有在换行的地方才会显示出来,一般使用shy;表示

html 复制代码
<p>大家好,我-叫zhang&shy;sanqiren,感谢大家。</p>
css 复制代码
p {
    width: 100px;
    padding: 10px;
    border: solid deepskyblue;
    text-align: justify;
    text-justify: inter-ideograph;
}

注意: 由于软连字符需要提前手动插入,因此,这种排版优化只适合文本内容固定的静态场景

==> <wbr>元素 <==

说明: 它可以让连续的英文和数字实现精准换行,其表现为如果宽度够就不换行,如果不够则在<wbr>元素所在的位置换行,之所以能够产生这样的效果是因为创建了一个带有换行特性的宽度为0px的空格

html 复制代码
<p>hdeuwihfeiowhfeiofhifwhio<wbr />ehfoiwh</p>
css 复制代码
p {
    width: 100px;
}

==> overflow-wrap: anywhere <==

  • 硬换行: 在文本的换行处插入实际的换行符

  • 软换行: 换行的文本实际上仍处于同一行,但看上去被分成了多行一样

说明: 它的作用是如果行中没有其他可接受的断点,则可以在任何点断开原本不可断开的字符串,并且在断点处不插入连字符,在换行的过程中会保留标点符号的避首规则和避尾规则

css 复制代码
p {
    display: inline-block;
    width: min-content;
    padding: 10px;
    border: solid deepskyblue;
    vertical-align: top;
}

.anywhere {
    overflow-wrap: anywhere;
}
html 复制代码
<p class="anywhere">I'm zhangsan.</p>

(7)text-align的新特性

==> match-parent属性值 <==

作用: match-parent的计算值是视觉上的left或者right,这样有助于在JavaScript应用中知道元素对齐的视觉方位,也就是元素是左对齐呢还是右对齐呢

css 复制代码
section {
    direction: rtl;
    text-align: start;
}

#p2 {
    text-align: -webkit-match-parent;
    text-align: match-parent;
}
html 复制代码
<section>
    <p id="p1"></p>
</section>
<section>
    <p id="p2"></p>
</section>

==> 字符对齐特性 <==

说明: 这个字符属性值必须是单个字符,否则会被忽略,同时只能作用在单元格中,让单元格基于这个指定的字符对齐。字符可以和关键字属性值一起使用,如果没有关键字属性值,字符会显示在右侧,也就是类似下面图片这种

(8)text-decoration的新特性

说明: 文本装饰线嘛,一般用来制作链接元素的下划线或者普通元素的贯穿线

html 复制代码
<a href="">链接元素</a>
<div>删除元素</div>
css 复制代码
a {
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

div {
    text-decoration: line-through;
}

==> 缩写形式 <==

说明: 完整的text-decoration属性由text-decoration-linetext-decoration-styletext-decoration-colortext-decoration-thickness组合而成的,每个属性可以选择出现和不出现,并且出现的位置可以是随意的,但是尽量按照顺序来,这样便于理解和记忆

text-decoration-line: 装饰线的类型,这个支持多个值同时使用

css 复制代码
/* 没有装饰线 */
text-decoration-line: none;
/* 下划线装饰 */
text-decoration-line: underline;
/* 上划线装饰 */
text-decoration-line: overline;
/* 贯穿线装饰 */
text-decoration-line: line-through;

text-decoration-style: 装饰线的风格样式

css 复制代码
/* 实线 */
text-decoration-style: solid;
/* 双实线 */
text-decoration-style: double;
/* 点线 */
text-decoration-style: dotted;
/* 虚线 */
text-decoration-style: dashed;
/* 波浪线 */
text-decoration-style: wavy;

text-decoration-color: 表示装饰线的颜色。

text-decoration-thickness: 表示装饰线的粗细。

==> 累加特性 <==

说明: 当父元素和子元素同时设置text-decoration效果的时候,文字的装饰线效果是累加的,而不是覆盖的。

html 复制代码
<section>
    <p>父元素设置了text-decoration:dashed underline</p>
    <p>子元素设置了text-decoration:wavy overline。</p>
</section>
css 复制代码
section {
    text-decoration: dashed underline;
}

p {
    text-decoration: wavy overline;
}

==> 实用的wavy波浪线 <==

举例: 绘制一个宽度100%的波浪线效果

css 复制代码
wavy {
    display: block;
    height: 0.5em;
    white-space: nowrap;
    letter-spacing: 100vw;
    padding-top: 0.5em;
    overflow: hidden;
}

wavy::before {
    content: "\2000\2000";
    /* IE浏览器用实线代替*/
    text-decoration: overline;
    /* 现代浏览器,Safari浏览器不支持text-decoration:overline wavy缩写 */
    text-decoration-style: wavy;
}
html 复制代码
<wavy />

原理: 伪元素生成两个空格,使用letter-spacing属性控制两个空格占据足够的宽度,这样空格字符的装饰线的尺寸一定可以充满整个容器,此时只要设置装饰线的类型是波浪线,宽度100%自适应的波浪线效果就实现了

==> text-underline-position: under <==

说明: 默认情况下下划线在基线位置附近,于是下划线就会与g、q这些下方存在小尾巴的字符和字重偏下的中文字体的下边缘发生重叠,这样体验感觉不是很好,因此如果使用了文字下划线的效果,就需要text-underline-position:under来优化下划线的位置,看下面的例子

html 复制代码
<p>如果不设置,看看字母g和q</p>
<p class="under">看看下划线的位置在哪里?</p>
css 复制代码
p {
    text-decoration: underline;
}

.under {
    text-underline-position: under;
}

==> text-underline-offset属性 <==

说明: 上面那一对属性值不能设置下划线的位置,这个属性可以,它的偏移量支持带单位数值和百分比,百分比是相对于1em的,因此设置100%等价于1em,最后它还接受负值,正值往下偏移那么负值就是往上了

css 复制代码
/* 比如上面的p元素设置10px的偏移量 */
.under {
    text-underline-position: under;
    text-underline-offset: 10px
}

==> text-decoration-skip-ink属性 <==

说明: 可以用来设置下划线是贯穿还是避让,它是text-decoration-skip属性演变而来的,默认值是auto,表现为避让的状态,而none则体现出贯穿的姿色

html 复制代码
<p class="under" style="text-decoration-skip-ink: auto">auto下的字母g和q</p>

<p class="under" style="text-decoration-skip-ink: none">none下的字母g和q</p>
css 复制代码
p {
    text-decoration: underline;
}

(9)颜色相关

了解: color属性支持的颜色关键字存在四个阶段

  • 第一阶段: VGA图形卡上的16种可显示的颜色

  • 第二阶段: 支持了orange颜色关键字和RGB颜色值

  • 第三阶段: 新增了130个源自X11颜色列表的颜色关键字,同时支持HSL颜色、Alpha透明通道,以及transparent和currentColor这两个关键字

  • 第四阶段: 增加了对名为rebeccapurple的颜色关 键字的支持,同时扩展了RGB颜色和HSL颜色的语法

==> 148个颜色关键字 <==

说明: color属性支持的148个颜色关键字可以看《CSS新世界》张大大总结的,这个太多不好弄就只好贴一个网址了

注意:

  • 对于HTML中的color属性来说,如果无法识别颜色关键字,就会直接替换成另一个颜色,而对于CSS来说,则会直接忽略这个颜色关键字

  • 颜色关键字设置的颜色都是实色的,没有带透明度的

  • 颜色关键字不区分大小写

  • 带deep前缀的颜色关键字只有deepskyblue和deeppink

  • 并不是所有带dark前缀的颜色关键字就颜色更深,比如darkgray比gray更浅

  • 第四阶段的rebeccapurple这个颜色关键字是为了纪念Eric Meyer的女儿设置的

==> transparent关键字 <==

说明: 在CSS2.1的时候,这只是一个特殊的关键字,其作用是重置border-color和background-color的颜色为纯色,在CSS3的时候,才被定义为颜色,一般在颜色渐变和过渡动画中使用,颜色在转换的过程中是会转换成rgba来计算的,但是其使用的算法很特殊

==> RGB颜色和HSL颜色 <==

<== HSL颜色 ==>

说明: 这个颜色是由色调饱和度亮度三部分组成,对于色调,其单位是deg,范围在0-360deg,所以无论什么颜色值,都会落在这个范围中,常见的三个色调色是红绿蓝,分别是0、120deg、240deg;而对于饱和度和亮度而言,其值是任意的,其取值范围在0-100%,这个百分号是不可以省略的,省略会导致整条语句无效

场景: 这种颜色兼容性很好,很适合在颜色变化的场合,比如设计师只给了默认的按钮颜色,没有给按下或者其它状态的按钮颜色,这样就很适合HSL颜色了,之后只需要改变亮度和饱和度就可以,无需计算,也无需取色,如果使用传统的16进制颜色,用其它的颜色还需要求助设计师,就太麻烦了

注意: 这三个数值可以是小数

<== RGBA颜色和HSLA颜色 ==>

说明: 也就是颜色支持透明度,取值范围是任意的,但是渲染范围是0-1,也就是小于0的会当做0渲染,大于1的当做1渲染

注意: 还存在#RRGGBBAA这样的颜色,也就是把rgba颜色的每一项都转换为16进制,RR、GG、BB的取值范围是00-FF,透明度的16进制AA则需要进行换算一下,公式如下:

js 复制代码
AA = (透明度 * 255).toString(16);

(10)background新特性

==> background-size属性 <==

说明: 如果需要把一张大图限制在一个小的区域里面就需要用到background-size,假设一个按钮的尺寸是20px20px,这个按钮元素需要使用一个2000px2000px的svg图标作为背景,此时可以这样使用来进行图标限制

css 复制代码
/* 任意一种都可以,这也是常规用法 */
background-size: cover;
background-size: contain;
background-size: 100%;
background-size: 20px;
background-size: auto 100%;
background-size: auto 20px;
background-size: 100% 100%;
background-size: 20px 20px;

<== cover和contain关键字 ==>

说明: cover是覆盖的意思,表示背景图尽可能把当前元素完全覆盖,不留任何空白。contain是包含的意思,表示背景图尽可能包含在当前元素区域内,同时没有任何剪裁,两者都不会改变背景图的原始比例,非常适合背景图像高宽不确定的场景

css 复制代码
.bg-cover,
.bg-contain {
    width: 128px;
    height: 128px;
    border: solid deepskyblue;
    background: url(D:1.jpg) no-repeat center;
}

.bg-cover {
    background-size: cover;
}

.bg-contain {
    background-size: contain;
}
html 复制代码
<h4>cover</h4>
<div class="bg-cover"></div>

<h4>contain</h4>
<div class="bg-contain"></div>

理解: 如果显示区域的比例和原始图像的比例不一致,那么cover属性值最终的表现效果就是有一部分图像被剪裁掉,而contain属性值的表现效果是图片有一部分的区域会留白。但是无论是cover属性值还是contain属性值,都至少有一个方向的元素边界和图像边界是重合的。

<== auto关键字渲染规则 ==>

了解: 先了解一下常见图像的内在尺寸和内在比例

  • 位图:例如JPG或者PNG图片都属于位图,这些图像总是有自己 的内在尺寸(原始图像大小)和内在比例(原始图像比例)。

  • 矢量图:例如SVG图像就属于矢量图,这些图像不一定具有内在 尺寸。如果水平尺寸和垂直尺寸都设置了,那么它就具有内在的比例;如果没有设置尺寸,或者只设置了一个方向的尺寸,它可能有比例,也可能没有比例,要视SVG内部代码而定,如有些SVG元素内部只有元素,此时矢量图就没有比例。

  • 渐变图像:就是使用CSS渐变语法绘制的图像,这些图像是没有内在尺寸和内在比例的。

  • 元素图像:例如使用element()函数把DOM元素作为背景图,此时的内在尺寸就是这个DOM元素的尺寸。

前提情况一: background-size的属性值是auto或者auto auto或者没有设置background-size属性的时候,就会存在以下渲染规则

  • 如果图像水平和垂直方向同时具有内在尺寸,则按照图像原始大小进行渲染。例如一个PNG图片尺寸是800px * 600px,那么背景图 的尺寸就是800px * 600px,这就是多倍图一定要设置background-size属性的原因,否则只能显示部分图像内容

  • 如果图像没有内在尺寸,也没有内在比例,则按照背景定位区域的大小进行渲染,等同于设置属性值为100%,例如渐变区域的大小是100px * 100px,那么此时渐变背景的大小就是100px * 100px

  • 如果图像没有内在尺寸,但具有内在比例,则渲染效果等同于设置属性值为contain。

  • 如果图像只有一个方向有内在尺寸,但又具有内在比例,则图像会拉伸到该内在尺寸的大小,同时宽高比符合内在比例。例如,某个SVG图像的内在比例是1:1,但是SVG图像源码中的<svg>元素只设置了width属性,没有设置height属性,则最终的SVG图像会按照width属性设置的宽度渲染,高度和宽度保持1:1的比例进行渲染

  • 如果图像只有一个方向有内在尺寸而没有内在比例,则图像 有内在尺寸的一侧会拉伸到该内在尺寸大小,没有设置内在尺寸的一 侧会拉伸到背景定位区域大小

前提情况二: background-size只有一个值是auto,另一个值不是auto

  • 如果图像有内在比例,则图像会拉伸到指定的尺寸,高宽依然保持原始的比例。假设PNG背景图片的尺寸是800px×600px,则background-size:40px的效果是将图片宽度拉伸到40px,高度和宽度的比例保持原始的4:3,所以高度值是30px。类似的,background- size: auto 30px表示宽度auto,高度拉伸到30px,由于图片内在比例是 4:3,因此最终的背景尺寸是40px×30px。

  • 如果图像没有内在比例,则图像会拉伸到指定的尺寸。同时,如果图像有内在尺寸,则auto的计算尺寸就是图像的尺寸;如果图像没有内在尺寸,则auto的计算尺寸就是背景定位区域的尺寸

<== 数值或百分比值 ==>

说明: 这两种值都不能是负值,其中百分比值是相对于元素的背景定位区域进行计算的,这个区域由background-origin属性来决定,默认是padding-box

html 复制代码
<h4>默认 padding-box</h4>
<div class="bg-percent"></div>

<h4>background-origin:content-box</h4>
<div class="bg-percent content-box"></div>
css 复制代码
.bg-percent {
    width: 100px;
    height: 75px;
    border: 20px solid rgba(0, 192, 255, 0.5);
    padding: 20px;
    background: url(D:1.jpg) no-repeat;
    background-size: 100% 100%;
}

.content-box {
    background-origin: content-box;
}

解释: 100%是相对于padding box计算的,需要把设置的padding:20px的大小计算在内,因此,此时背景图的尺寸是140px×115px,如果我们设置background-origin:content-box,则100%是相对于content-box计算的,这里content-box的尺寸是100px×75px,因此,此时背景图的尺寸是100px×75px

==> 多背景 <==

说明: 这个指的是一个background属性可以同时定位多个独立的背景图像,语法上用逗号分隔每一个背景图像就好了,一般是结合CSS渐变一起使用的,由于CSS渐变可以实现纯色效果并且background-size属性也支持多背景,可以任意控制尺寸大小,因此利用渐变可以很容易在元素中心描绘图像,也可以实现很多复杂的纹理效果,这个复杂效果可以参考这个网站

举例: PNG透明背景的灰白网格效果

css 复制代码
.square {
    /* 利用线性渐变和元素的边角绘制两个等腰直角三角形,再利用backgroundposition属性让两个三角单元视觉错位重合,以此实现方格效果 */
    display: inline-block;
    width: 304px;
    height: 160px;
    background-color: #fff;
    background-image: linear-gradient(
                            45deg,
                            #eee 25%,
                            transparent 25%,
                            transparent 75%,
                            #eee 75%
                       ),
                       linear-gradient(
                            45deg,
                            #eee 25%,
                            transparent 25%,
                            transparent 75%,
                            #eee 75%
                       );
    background-size: 16px 16px;
    background-position: 0 0, 8px 8px;
}
html 复制代码
<div class="square"></div>

==> background-clip属性 <==

说明; 这个属性的默认值是border-box,表示背景图像或者背景颜色的显示区域是整个border-box,也就是边框的下方也会显示背景内容,也就是下面这样的,它还支持padding-box、content-box和text这几个属性值

html 复制代码
<div class="example"></div>
css 复制代码
.example {
    width: 180px;
    height: 80px;
    border: 10px dashed deeppink;
    background-color: deepskyblue;
    background-clip: border-box;
}

作用: 一般在移动端的时候,复选框可能为了美观会设计的很小,但是用户在点击的时候可能点不到,一般通过增加边框来增大可点击的范围,但是默认情况边框是存在背景色的,即使不存在背景色,也会看到增大的边框哪里会存在背景色,因为background-clip的默认值,此时就可以将这个值设置为content-box或者padding-box来让边框没有颜色,优化其美观的程度

==> 文字纹理效果 <==

说明: 这个使用background-clip: text就可以,它可以让背景图像按照字符形状进行剪裁,之后将字体隐藏起来,就可以得到字符形状的背景效果了

html 复制代码
<p class="text-gradient">我是渐变文字</p>
css 复制代码
.text-gradient {
    background: linear-gradient(deepskyblue, deeppink);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

==> background-origin属性 <==

说明: 它用于背景定位原点控制,其中padding-box是默认值,表示背景图像定位的左上角位置 是从padding-box开始的,默认的背景定位区域大小也是padding-box大小。因此,若希望渐变背景从边框位置开始就是一个完整的自上而下的渐变效果,只要设置background-origin属性值为border-box即可

html 复制代码
<div class="example"></div>
css 复制代码
.example {
    width: 180px;
    height: 70px;
    border: 20px dashed;
    background: linear-gradient(deepskyblue, deeppink);
    background-origin: border-box;
}

==> 图像平铺 <==

说明: 这里说的是background-repeat的两个属性值space和round

<== space ==>

说明: 让背景图像尽可能地重复,而不进行剪裁,每个重复单元的尺寸不会变化。其中第一张和最后一张图像固定在元素的两边,然后通过拉伸空白区域让剩余的图像均匀分布,就是类似flex布局那样

css 复制代码
.space {
    width: 200px;
    height: 100px;
    background: url(D:1.jpg) center / auto 100%;
    background-size: 50px;
    background-repeat: space;
    outline: 1px dotted;
}
css 复制代码
<div class="space"></div>

注意: 如果背景显示区域只能显示一张图像的情况下,应该使用background- position属性来控制这张图像的定位

<== space ==>

说明: 这个就简单了,就是背景图像会被拉伸,并保证不留间隙。随着定位区域空间的增加,如果剩余空间大于图像宽度的一半,则添加另外一张图像。在添加下一张图像时,当前的所有图像都会压缩以留出空间放下这个新添加的图像

注意: background-repeat属性可以同时设置这两个值,也就是分别设置水平和垂直方向上的背景平铺效果

==> 注意background-position属性 <==

说明 这里需要注意的是它属性值为1、2、3/4个时候的区别

<== 1个 ==>

注意: 如果只有1个值,无论是具体的数值、百分比值,还是关键字属性值,则另外一个值一定是center

css 复制代码
/* 等于设置20px center */
background-position: 20px 

<== 2个 ==>

  • 2个值都是关键字属性值。left关键字和right关键字表示水平方向,top关键字和bottom关键字表示垂直方向,因此top right和right top的效果是一样的。需要注意的是,不能包含对立的方位,也就是说left right和top bottom这样的语法是无效的。

  • 1个值是关键字属性值,另外一个值是数值或百分比值。如果数值或百分比值是第一个值,则表示水平方向,另外一个关键字属性值就表示垂直方向。如果数值或百分比值是第二个值,则表示垂直方向,另外一个关键字属性值就表示水平方向。因此属性值20px left是非法的,因为20px是数值且是第一个值,此时第二个值应该 表示垂直方向,但是left显然是水平方向关键字属性值,出现了对立方位,所以为无效语法。

  • 2个值都是数值或百分比值。第一个值表示水平方向,第二个值表示垂直方向。因此20px 20%表示在距离默认定位原点(左上角)水平方向20px、垂直方向20%的位置开始定位。

<== 3个 / 4个 ==>

注意: 数值和百分比值表示偏移量,第一个值一定要是关键字属性值, 这个关键字属性值用来表示偏移是从哪个方向开始的。如果是3个值, 则认为缺少的偏移量是0。因此,20px left top一定是不合法的, 其第一个值不是关键字属性值。left 20px right也是不合法的, 因为left和right方位对立。left 20px top就是合法的,其等同 于left 20px top 0px,表示距离左侧20px,距离顶部0。由于 background-position默认的定位就是left top,因此left 20px top 0也等同于20px 0px

css 复制代码
background-position: left 10px top 15px; /* 10px, 15px */
background-position: left top; /* 0px, 0px */
background-position: 10px 15px; /* 10px, 15px */
background-position: left 15px; /* 0px, 15px */
background-position: 10px top; /* 10px, 0px */
background-position: left top 15px; /* 0px, 15px */
background-position: left 10px top; /* 10px, 0px */

==> outline-offset属性 <==

说明: 用于改变outline属性设置的轮廓的偏移位置,默认情况下,给元素设置的outline轮廓都是紧贴元素外边缘的,但是,如果多个元素紧密相连,那么outline轮廓就会出现互相覆盖遮挡的情况,此时可以使用这个属性来进行体验的优化

html 复制代码
<h4>有问题的</h4>
<p>
    <img src="D:1.jpg" />
    <img src="D:1.jpg" />
    <img src="D:1.jpg" />
</p>

<h4>优化后的</h4>
<p class="outline-offset">
    <img src="D:1.jpg" />
    <img src="D:1.jpg" />
    <img src="D:1.jpg" />
</p>
css 复制代码
p img {
    width: 100px;
    height: 136px;
}

p img:hover,
p img:active {
    outline: solid deepskyblue;
}

.outline-offset img {
    outline-offset: -3px;
}

四、更细致的样式

(1)透明度opacity属性

初始: 这个属性可以让元素半透明,取值范围是0-1,初始值是1,表示不透明,此外这个属性没有继承性

==> opacity属性的叠加 <==

说明: 如果父、子元素同时设置半透明,那么半透明效果是叠加的

css 复制代码
.father {
    width: 120px;
}

.son {
    height: 120px;
    background: deepskyblue;
}

.opacity1,
.opacity1 .son {
    opacity: 0.5;
}

.opacity2 {
    opacity: 0.25;
}
html 复制代码
<!-- 此时这两个p元素的透明度都是0.5 * 0.5 = 0.25 -->
<div class="father opacity1">
    <p class="son"></p>
</div>

<div class="father opacity2">
    <p class="son"></p>
</div>

==> opacity属性的边界性 <==

性质: 值小于0按照0计算,大于1按照1计算,对RGBA颜色或者HSLA颜色都生效

css 复制代码
.example {
    opacity: -999; /* 解析为 0, 完全透明 */
    opacity: -1; /* 解析为 0, 完全透明 */
    opacity: 2; /* 解析为 1, 完全不透明 */
    opacity: 999; /* 解析为 1, 完全不透明 */
    color: hsl(0, 0%, -100%); /* 解析为 hsl(0, 0%, 0%), 黑色 */
    color: hsl(0, 0%, 200%); /* 解析为 hsl(0, 0%, 100%), 白色 */
}

<== 自动配色按钮 ==>

举例: 如果按钮背景颜色比较浅,则按钮的文字颜色自动变成黑色,同时显示边框;如果按钮的背景颜色比较深,则按钮的文字颜色自动变成白色

html 复制代码
<div class="demo">
    <button class="btn">我是按钮</button>
    <p class="c-r">
        R:<input type="range" min="0" max="255" value="44" name="red" />
    </p>
    
    <p class="c-g">
        G:<input type="range" min="0" max="255" value="135" name="green" />
    </p>
    
    <p class="c-b">
        B:<input type="range" min="0" max="255" value="255" name="blue" />
    </p>
</div>
css 复制代码
.demo {
    width: 300px;
    width: -moz-fit-content;
    width: fit-content;
    margin: auto;
    text-align: left;
}

:root {
    /* 定义RGB变量 */
    --red: 44;
    --green: 135;
    --blue: 255;

    /**
    * 使用sRGB Luma方法计算灰度(可以看成亮度)
    * 算法为:
    * lightness = (red * 0.2126 + green * 0.7152 + blue * 0.0722) / 255
    */
    --lightness: calc(
        (var(--red) * 0.2126 + var(--green) * 0.7152 + var(--blue) * 0.0722) /
        255
    );
}

.btn {
    font-size: 150%;
    padding: 0.5em 2em;
    border: 0.2em solid;
}

.btn {
    /* 按钮背景色就是基本背景色 */
    background: rgb(var(--red), var(--green), var(--blue));
    
    /**
    * --lightness亮度和0.5对比
    * 大于,则正数,和-999999%相乘,会得到一个巨大负数,浏览器会按照边界0%渲染,也就是亮度为0,于是颜色是黑色;
    * 小于,则和-999999%相乘,会得到一个巨大的正数,以最大合法值100%渲染,于是颜色是白色;
    */
    color: hsl(0, 0%, calc((var(--lightness) - 0.5) * -999999%));
    
    /**
    * 深色颜色加一点浅一点颜色的阴影
    */
    text-shadow: 1px 1px
    rgba(
        calc(var(--red) + 50),
        calc(var(--green) + 50),
        calc(var(--blue) + 50),
        calc((var(--lightness) - 0.5) * 9999)
    );

    /**
    * 确定边框透明度。
    * 如果亮度比0.8大,在说明按钮背景色比较淡,我们出现一个深色边框;
    * 如果亮度比较小,说明按钮背景色较深,没有必要出现边框。
    此时,计算后为负值,透明度小于0的时候,浏览器会按照0渲染,因此,边框透明。
    */
    /* 设置边框相关样式 */
    border-color: rgba(
        calc(var(--red) - 50),
        calc(var(--green) - 50),
        calc(var(--blue) - 50),
        calc((var(--lightness) - 0.8) * 100)
    );
}

input {
    vertical-align: middle;
    margin-right: 10px;
}

.c-r::after {
    counter-reset: red var(--red);
    content: counter(red);
}

.c-g::after {
    counter-reset: green var(--green);
    content: counter(green);
}

.c-b::after {
    counter-reset: blue var(--blue);
    content: counter(blue);
}
js 复制代码
var eleRanges = document.querySelectorAll('input[type="range"]');
Array.from(eleRanges).forEach(function (range) {
    range.addEventListener("input", function () {
        document.documentElement.style.setProperty(
            "--" + this.name,
            this.value
        );
    });
});

<== 静态饼图 ==>

html 复制代码
<h4>10%大小</h4>
<div class="pie-simple" style="--percent: 10">
    <div class="pie-left"></div>
    <div class="pie-right"></div>
</div>
css 复制代码
.pie-simple {
    width: 128px;
    height: 128px;
    background-color: #eee;
    border-radius: 50%;
    text-align: left;
    overflow: hidden;
}

.pie-left,
.pie-right {
    width: 50%;
    height: 100%;
    float: left;
    position: relative;
    overflow: hidden;
}

.pie-left::before,
.pie-right::before,
.pie-right::after {
    content: "";
    position: absolute;
    width: 100%;
    height: 100%;
    background-color: deepskyblue;
}

.pie-left::before {
    left: 100%;
    transform-origin: left;
    transform: rotate(calc(3.6deg * (var(--percent) - 50)));
    /* 比例小于或等于50%的时候左半圆隐藏 */
    opacity: calc(99999 * (var(--percent) - 50));
}

.pie-right::before {
    right: 100%;
    transform-origin: right;
    transform: rotate(calc(3.6deg * var(--percent)));
}

.pie-right::after {
    /* 比例大于50%的时候左半圆一直显示 */
    opacity: calc(99999 * (var(--percent) - 50));
}

(2)圆角属性border-radius

==> 语法 <==

说明: 完整的语法包括四个值,分别对应左上、右上、右下、左下这四个方位的圆角设置,不过对应的属性跟中文有一点点区别,如图

<== 理解四个方位 ==>

规则:

  • 如果只有1个值,则表示圆角效果作用在全部4个角

  • 如果有2个值,则第一个值作用于左上角和右下角,第二个值作用于右上角和左下角

  • 如果有3个值,则第一个值作用于左上角,第二个值作用于 右上角和左下角,第三个值作用于右下角

  • 如果有4个值,则4个值按照顺时针方向依次作用于左上角、 右上角、右下角和左下角

<== 水平半径和垂直半径 ==>

说明; 圆角值其实分为水平和垂直两个方向的,称为水平半径和垂直半径

css 复制代码
/* 这两个是等价的 */
border-top-left-radius: 10px
border-top-left-radius: 10px 10px

注意: 如果是使用border-radius的话,则使用/分开,而不是使用空格,其/的前后分别表示四个方向的水平半径和四个方向的垂直半径

css 复制代码
/* border-radius的完整写法 */
border-radius: 左上水平、右上水平、右下水平、左下水平 / 左上垂直、右上垂直、右下垂直、左下垂直

==> 圆角效果的产生 <==

<== 基础认识 ==>

说明: 圆角效果的产生主要与水平半径和垂直半径共同作用下产生的圆或者椭圆有关

举例: border-top-left-radius: 30px 60px;

css 复制代码
div {
    width: 100px;
    height: 100px;
    background: red;
    border-top-left-radius: 30px 60px;
}
html 复制代码
<div />

<== f计算值 ==>

说明: 当元素的高度并不足以放下两个半轴为尺寸的椭圆时,则曲线可能会发生重叠,而且曲线的交叉点一定不是平滑的,此时CSS规范使用f计算值对其进行一定的约束

计算公式: f计算值 = min(元素的宽 / 水平半径的和, 元素的高 / 垂直半径的和)

解释: 也就是将元素的宽度与当前方位的水平半径和垂直半径的和相除取最小值,如果这个值小于1,则所有的圆角半径都乘以这个f计算值

css 复制代码
/* f计算值 = min(100 / 50 + 50, 100 / 100 + 100) = 0.5 */
div {
    width: 100px;
    height: 100px;
    background: red;
    /* 实际上这里设置的值都会去乘以0.5,可以看见下面是一样的效果 */
    border-top-left-radius: 50px 100%;
    border-bottom-left-radius: 50px 100%;
}

==> 与边框一起作用的细节 <==

说明: 如果元素设置了边框,则圆角半径会被分为内半径和外半径

<== 细节一 ==>

说明: padding边缘的圆角大小为设置的border-radius大小减去边框的厚度,如果结果为负,则内半径为0

css 复制代码
.radius {
    /* 圆角半径大小和边框的大小均是40px,此时内半径大小为0, */
    /* 因此,padding边缘是直角,没有弧度 */
    width: 100px;
    height: 100px;
    border-top: 40px solid deepskyblue;
    border-left: 40px solid deepskyblue;
    border-radius: 40px 0 0;
}

<== 细节二 ==>

说明: 如果相邻两侧边框的厚度不同,则圆角大小将在较厚和较薄边界之间显示平滑过渡

css 复制代码
.radius {
    width: 100px;
    height: 100px;
    border-top: 40px solid deepskyblue;
    border-left: 20px solid deepskyblue;
    border-radius: 40px 0 0 / 60px 0 0;
}

<== 细节三 ==>

说明: 圆角边框的连接线和直角边框连接线位置一致,但是角度会有所不同

css 复制代码
.radius {
    width: 100px;
    height: 100px;
    border-top: 40px solid deepskyblue;
    border-left: 20px solid deeppink;
    border-right: 20px solid deeppink;
    border-radius: 40px 0 0 / 60px 0 0;
}

==> 应用举例 <==

<== 不规则的圆角头像 ==>

css 复制代码
.radius {
    width: 150px;
    height: 150px;
    border-radius: 70% 30% 30% 70% / 60% 40% 60% 40%;
    object-fit: cover;
    object-position: right;
}
html 复制代码
<img class="radius" src="D:1.jpg" />

<== 1/4圆 ==>

css 复制代码
.corner-marker {
    width: 100px;
    height: 100px;
    background: #abcdef;
    border-bottom-right-radius: 100%;
}

<== 尖角的对话框小尾巴 ==>

css 复制代码
.corner-marker {
    border-bottom-right-radius: 100%;
}

.talk-dialog {
    padding: 10px;
    background: deepskyblue;
    border-radius: 0.5em;
    color: #fff;
    position: relative;
    z-index: 0;
}

.talk-dialog::before {
    content: "";
    position: absolute;
    width: 15px;
    height: 10px;
    color: deepskyblue;
    border-top: 10px solid;
    border-top-left-radius: 80%;
    left: 0;
    bottom: 0;
    margin-left: -12px;
    -ms-transform: skewX(-30deg) scaleY(1.3);
    transform: skewX(-30deg) scaleY(1.3);
    z-index: -1;
}
html 复制代码
<div class="talk-dialog">使用border边框配合border-radius圆角效果实现。</div>

(3)盒阴影box-shadow

说明: 常规的投影效果就是偏移+模糊+颜色,这里的偏移分为水平偏移和垂直偏移,也就是普通语法的四个值对应的就是按顺序的四部分

注意: 投影的光源默认在页面的左上角。因此水平偏移的值如果是正数则表示投影偏右,如果是负数则表示投影 偏左,垂直偏移也是类似效果。这种偏移方位与文档流的方向没有任何关系

==> inset关键字与内阴影 <==

说明: inset关键字,表示阴影朝向元素内部

<== 内阴影和外阴影的对比 ==>

说明: 内阴影效果适合实现内嵌效果,表现更低一层级的视觉效果,其次其投影光源都是默认左上角的,跟外阴影是一致的

css 复制代码
.inset {
    width: 180px;
    height: 100px;
    background-color: deepskyblue;
    box-shadow: inset 2px 2px 4px rgba(0, 0, 0, 0.5);
}

.normal {
    width: 180px;
    height: 100px;
    background-color: deepskyblue;
    box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}
html 复制代码
<div class="inset">内阴影</div>
<div class="normal">外阴影</div>

<== 模拟边框 ==>

说明: 在border边框被占用,或者不方便使用border属性的情况下, 我们可以借助box-shadow内阴影来模拟边框效果

css 复制代码
button {
    height: 40px;
    min-width: 80px;
    border: 0;
    border-radius: 4px;
    padding-left: 10px;
    padding-right: 10px;
}

.normal {
    background-color: #fff;
    box-shadow: inset 1px 0 #a2a9b6, inset -1px 0 #a2a9b6,
                inset 0 1px #a2a9b6, inset 0 -1px #a2a9b6;
}

.primary {
    color: #fff;
    background-color: #2a80eb;
}

.warning {
    color: #fff;
    background-color: #eb4646;
}
html 复制代码
<button class="normal">正常</button>
<button class="primary">主要</button>
<button class="warning">警示</button>

<== 颜色覆盖 ==>

说明: 生成的阴影会位于文字内容的下面,背景颜色的上面。于是可以使用box-shadow属性在元素上面再覆盖一层颜色

css 复制代码
/* 上面的按钮在按下的时候其背景颜色加深,这个可以通过内阴影来解决 */
button:active {
    box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.1);
}

注意: 这个内阴影的颜色覆盖效果对于某些替换元素是无效的,比如img元素,因为替换元素的内容在盒阴影之上。此时可以使用outline属性进行模拟

==> 第四个长度值 <==

说明: box-shadow属性支持2~4个长度值,这四个长度值分别指水平偏移、垂直偏移、模糊半径和扩展半径,扩展半径大多数用来模拟大范围的色块效果,比如蒙版之类的,除此之外,扩展半径还支持负值,可以用来实现单侧阴影效果

注意: 理论上,实现单侧阴影效果只要设置一侧阴影的偏移大小为0即可,但是,如果模糊半径设置得较大,就会看到有部分阴影显示在左右两侧了,并不是单侧阴影效果,此时可以设置扩展半径为负值,让阴影只在一侧显示

html 复制代码
<div class="header">模糊半径过大</div>
<div class="header clear">设置扩展半径为负来解决</div>
css 复制代码
.header {
    width: 150px;
    padding: 10px;
    background-color: white;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
}

.clear {
    box-shadow: 0 7px 5px -5px rgba(0, 0, 0, 0.5);
}

==> 多阴影与图形绘制 <==

说明: box-shadow属性支持无限多个阴影效果不断累加

<== 多边框和渐变边框效果 ==>

说明: 可以使用box-shadow属性模拟多边框效果,该属性也支持圆角效果,如果多边框的过渡颜色足够细腻,还可以使用box-shadow属性实现由内往外但并不是径向渐变的渐变效果

css 复制代码
.gradient-border {
    height: 100px;
    width: 100px;
    margin: 30px;
    border-radius: 10px;
    background-color: deepskyblue;
    box-shadow: 0 0 0 1px #07b9fb, 0 0 0 2px #17aef4, 0 0 0 3px #27a4ee,
                0 0 0 4px #3799e7, 0 0 0 5px #478ee0, 0 0 0 6px #5784d9,
                0 0 0 7px #6779d3, 0 0 0 8px #776ecc, 0 0 0 9px #8764c5,
                0 0 0 10px #9759be, 0 0 0 11px #a74eb8, 0 0 0 12px #b744b1,
                0 0 0 13px #c739aa, 0 0 0 14px #d72ea3, 0 0 0 15px #e7249d,
                0 0 0 16px #f71996;
}
html 复制代码
<div class="gradient-border">渐变边框</div>

<== 加载效果 ==>

css 复制代码
.loading {
    width: 4px;
    height: 4px;
    margin: 20px;
    border-radius: 100%;
    color: rgba(0, 0, 0, 0.4);
    box-shadow: 0 -10px rgba(0, 0, 0, 0.9), 10px 0px, 0 10px,
                -10px 0 rgba(0, 0, 0, 0.7), -7px -7px rgba(0, 0, 0, 0.8),
                7px -7px rgba(0, 0, 0, 1), 7px 7px, -7px 7px;
    animation: spin 1s steps(8) infinite;
}

@keyframes spin {
    0% {
        transform: rotate(0deg);
    }
    100% {
        transform: rotate(360deg);
    }
}

<== 云朵效果 ==>

说明: 使用box-shadow属性克隆多个圆,然后让圆不断交错重叠。

html 复制代码
<div class="cloud-x">
    <div class="cloud"></div>
</div>
css 复制代码
.cloud-x {
    height: 150px;
    background-color: deepskyblue;
    overflow: hidden;
}
.cloud {
    width: 60px;
    height: 50px;
    margin: 60px 0 0 70px;
    color: white;
    background-color: currentColor;
    border-radius: 50%;
    box-shadow: 100px 0px 0 -10px, 40px 0px, 70px 15px, 30px 20px 0 -10px,
    70px -15px, 30px -30px;
}

<== 3D投影效果 ==>

举例: 给按钮设置一个3D投影效果,按下按钮的时候按钮的位置发生偏移,同时投影高度降低,这可以实现非常有立体感的按钮效果

css 复制代码
.shadow-3d button {
    width: 100px;
    height: 36px;
    border: 1px solid #a0b3d6;
    background-color: #f0f3f9;
    color: #333;
    overflow: visible;
    cursor: pointer;
    box-shadow: 1px 1px #afc4ea, 2px 2px #afc4ea, 3px 3px #afc4ea;
    outline: 0;
}

.shadow-3d button:active {
    transform: translate(1px, 1px);
    box-shadow: 1px 1px #afc4ea, 2px 2px #afc4ea;
}
html 复制代码
<div class="shadow-3d">
    <button>按钮</button>
</div>

(4)CSS的2D变换

==> 了解基本的变换 <==

<== translate() ==>

作用: 以自身坐标为基准,进行水平方向或垂直方向的位移,如果是正值就表示往右或往下,负值就是往左或者往上

css 复制代码
/* 往右偏移10px,往下偏移20px */
transform: translate(10px, 20px);
/* 往右偏移10px */
transform: translateX(10px);
/* 往下偏移20px */
transform: translateY(20px);

注意: translate()函数中的第二个值可以省略,省略后表示垂直方向的偏移大小是0,此外,这个函数的百分比值是相对于自身尺寸进行计算的

css 复制代码
/* 这两种写法是等价的 */
translate(10px)
translate(10px, 0)

/* 往左偏移自身宽度的一半,往上偏移自身高度的一半 */ 
transform: translate(-50%, -50%);

<== rotate() ==>

说明: 正值表示顺时针旋转,负值表示逆时针旋转,这里了解一下它的单位,单位有四种,分别是deggradradturn,分别表示角度、百分度、弧度和圈数,一般情况使用deg就好了

  • 角度:角度范围为0~360度,角度为负值可以理解为逆时针旋转。例如,−45deg可以理解为逆时针旋转45度

  • 百分度:一个梯度,或者说一个百分度表示1/400个整圆。因此100gads相当于90deg,它和deg单位一样支持负值,负值可以理解为逆时针方向旋转

  • 弧度:1弧度等于180/π度,或者大致等于57.3度。 1.5708rad相当于100gads或是90deg

  • 圈数:1圈表示360度,平时体操或跳水中出现的"后空翻720度",也就是后空翻两圈的意思。于是有等式 1turn=360deg、2turn=720deg等。

css 复制代码
/* 顺时针旋转45度的各种单位表示情况 */
transform: rotate(45deg); 
transform: rotate(50gads); 
transform: rotate(0.7854rad); 
transform: rotate(.25turn);

<== scale() ==>

说明: 缩放变换也支持水平和垂直两个方向,与translate()不同的地方在于它不支持百分比值,并且如果只写一个方向的话,那么另一个方向也和这个方向是一样的

css 复制代码
/* 水平放大2倍,垂直缩小1/2*/
transform: scale(2, .5);
/* 水平放大2倍 */
transform: scaleX(2);
/* 垂直缩小1/2*/
transform: scaleY(.5);

/* 这两种写法是等价的,因此两个方向缩放的值是一样的话则可以省略垂直方向的值 */
transform: scale(1)
transform: scale(1,1)

注意: 如果某一个方向设置的存在负值则表示水平翻转之后再缩放

<== skew() ==>

说明: 斜切支持水平和垂直两个方向,如果垂直方向的值不写则默认为0

css 复制代码
/* 水平切斜10度,垂直切斜20度 */
transform: skew(10deg, 20deg);
/* 水平切斜10度 */
transform: skewX(10deg);
/* 垂直切斜20度 */
transform: skewY(20deg);

/* 这两种写法是等价的 */
skew(10px)
skew(10px, 0)

注意: 旋转是360度一个轮回,斜切则是180度一个轮回。元素处于90度或者270度斜切的时候是看不见的,因为此时元素的尺寸在理论上是无限的。对浏览器而言,尺寸不可能是无限的,因为没办法表现出来!于是这种情况下的尺寸为0,所以元素在90度或者270度斜切的时候是不会影响祖先元素的滚动状态的。

==> transform属性的特性 <==

  • 不会变化的盒模型: 就是元素应用的transform属性值不管是什么,元素盒模型的尺寸和位置是不会发生变化的,也就是对其它元素不会产生影响,只是存在视觉上的重叠而已

  • 内联元素无效: 内联元素(不包括替换元素)是无法应用transform变换的,且不支持所有变换特性,如果需要实现位移效果,可以先给元素增加块状特性然后再去使用transform属性或者使用相对定位来解决

  • 锯齿或虚化的问题: 在应用旋转或者斜切变换的时候,元素边缘会表现出明显的锯齿,文字会明显虚化,其主要原因是显示器的密度跟不上,目前大部分桌面显示器还都是1倍屏,显示的最小单元是1px × 1px,你可以理解为显示器屏幕是由一个个1px×1px大小的格子组成的。如果像素点旋转45度,那么这个正方形像素点的端点和边必然就会穿过其他的格子,由于显示器没有能力显示小于1px × 1px的图形,于是,要么裁剪像素点(锯齿),要么使用算法进行边缘模糊计算(虚化),解决这种问题,直接换成高清屏就可以了

  • 不同顺序不同效果: 可以一次性应用多个不同的变换函数,但需要注意的是,即使变换内容一样,如果顺序不同,最终的效果也会不一样,因为这些函数是从左往右依次执行的

  • 与clip/clip-path一起作用: 此时会先裁剪,后变换

==> transform属性应用后的表现 <==

<== 创建层叠上下文 ==>

说明: 和opacity属性值不是1的元素类似,如果元素的transform属性值不是none,则会创建一个新的层叠上下文,一般用于覆盖其他元素和限制z-index:-1的层级表现这两个场景中,看下面的两个例子

举例1: 覆盖其他元素

css 复制代码
img {
    width: 200px;
    height: 150px;
}

img + img {
    margin-left: -60px;
}

img:hover {
    /* 这就是我们实现鼠标悬停图片放大效果的时候无须指定层级的原因 */
    transform: scale(1);
}
html 复制代码
<img src="D:1.jpg" />
<img src="D:1.jpg" />

举例2: 限制z-index:-1的层级表现

css 复制代码
.container {
    padding: 40px 0;
    background-color: #666;
}

.page {
    width: 300px;
    height: 200px;
    margin: 0 auto;
    padding: 1em 0 2em;
    background-color: #f4f39e;
    box-shadow: 0 2px 10px 1px rgba(0, 0, 0, 0.2);
    border-bottom-right-radius: 50% 10px;
    position: relative;
}

.page::before {
    transform: skew(-15deg) rotate(-5deg);
    left: 15px;
    bottom: 10px;
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
}

.page::after {
    transform: skew(15deg) rotate(8deg);
    right: 15px;
    bottom: 25px;
    box-shadow: 8px 8px 10px rgba(0, 0, 0, 0.4);
}

.page:before,
.page:after {
    content: "";
    width: 90%;
    height: 30%;
    position: absolute;
    /* 使用::before和::after伪元素创建了模拟卷角投影的效果, */
    /* 由于投影效果需要放在纸张元素后面,因此z-index设为了负值 */
    z-index: -1;
}

/* 容器设置这个 */
.transform {
    transform: scale(1);
}
html 复制代码
<!-- z-index:-1是定位在第一个层叠上下文祖先元素的背景层上的, -->
<!-- 而网页在默认状态下的层叠上下文元素就是<html>根元素,-->
<!-- 也就是伪元素创建的阴影效果其实是在页面根元素的上面  -->
<!-- 在.container元素的下面,而.container元素设置了背景颜色, -->
<!-- 挡住了伪元素,因此阴影效果在视觉上不可见 -->
<h4>默认(纸张底角阴影不可见)</h4>
<div class="container">
    <div class="page"></div>
</div>

<h4>容器设置transform:scale(1)</h4>
<div class="container transform">
    <div class="page"></div>
</div>

<== 固定定位失效 ==>

说明: 如果应用了position:fixed的元素的父元素设置了transform变换,则固定定位会失效,其样式会表现为绝对定位

注意: 如果需要变换和固定定位共存,则需要外层元素负责定位,内层元素负责变换这种嵌套的方式来解决

<== 改变overflow对绝对定位元素的限制 ==>

  • CSS2.1规定: 如果绝对定位元素含有overflow属性值不为visible的祖先元素,同时,该祖先元素以及到该绝对定位元素之间的任何嵌套元素都没有position:static的声明,则overflow对该absolute元素不起作用。

说明: 在CSS2.1之后,这个规定不再准确了,因为transform属性值不为none的元素也可以影响绝对定位在 overflow元素中的表现,让overflow对该absolute元素生效

原因: transform属性值不为none的元素也可以作为绝对定位元素的包含块

css 复制代码
p {
    border: solid deepskyblue;
    width: 150px;
    height: 150px;
    overflow: hidden;
}

img {
    height: 150px;
    position: absolute;
}

.transform {
    transform: scale(1);
}
html 复制代码
<p>
    <img src="D:1.jpg" />
</p>
<p class="transform">
    <img src="D:1.jpg" />
</p>

==> 2D变换中的矩阵函数matrix() <==

语法: transform: matrix(a, b, c, d, e, f)

注意: 参数的单位是可以省略的

理解: 无论是位移、旋转、缩放还是斜切,其变换的本质都是应用矩阵函数matrix()进行矩阵变换。所谓矩阵变换,就是套用矩阵公式,把原先的坐标点转换成另外一个坐标点的过程,由于矩阵深入很难,所以只介绍2D变换中的矩阵

矩阵间的计算公式:

解释: 这里矩阵中a-f的值是matrix()函数中的六个参数,在写的时候注意从上往下写,而后面的x和y就是需要变换的坐标点的横纵坐标,在进行矩阵计算的时候,3×3矩阵每一行的第一个值与后面1×3矩阵的第一个值相乘,3×3矩阵每一行的第二个值与1×3矩阵的第二个值相乘,3×3矩阵每一行的第三个值与1×3矩阵的第三个值相乘,然后将3个乘积结果相加,所得到的ax + cy + e就是转换后的横坐标,bx + dy + f就是转换后的纵坐标

举例:

css 复制代码
/* 使用下面的矩阵函数计算坐标为(0,0)转换后的坐标 */
transform: matrix(1, 0, 0, 1, 30, 30); 

/* 根据公式可以得到结果 */
(ax + cy + e, bx + dy + f) = (1 * 0 + 0 * 0 +30, 0 * 0 + 1 * 0 + 30) = (30,30)

说明: 发现计算后的坐标相比原坐标同样是往右方和下方各偏移了30px,实际上transform:matrix(1, 0, 0, 1, 30, 30)等同于transform:translate (30px, 30px)。

<== translate() ==>

说明: 位移变换函数translate(x, y)中的x和y分别对应matrix()函数中的e和f两个参数,如果只需要元素进行位移,则只关心最后两个参数就可以了

css 复制代码
transform: matrix(a, b, c, d, 水平偏移距离x, 垂直偏移距离y);

<== scale() ==>

说明: 缩放只需要关注a和d两个参数,其中a表示x轴的缩放大小,d表示y轴的缩放大小

css 复制代码
transform: matrix(x轴的缩放大小, b, c, y轴的缩放大小, e, f);

<== rotate() ==>

前提: 假设旋转的角度为θ

公式: 按照三角函数进行转化

css 复制代码
matrix(cosθ, sinθ, -sinθ, cosθ, 0, 0)

/* 转换后的坐标(x,y)为 */
(x,y) = (xcosθ - ysinθ, xsinθ + ycosθ )

特殊三角函数值:

角度θ 弧度r sinθ cosθ tanθ
0 0 1 0
30° π / 6 1 / 2 √3 / 2 √3 / 3
45° π / 4 √2 / 2 √2 / 2 1
60° π / 3 √3 / 2 1 / 2 √3
90° π / 2 1 0 不存在
120° 2π / 3 √3 / 2 - 1 / 2 -√3
135° 3π / 4 √2 / 2 - √2 / 2 -1
150° 5π / 6 1 / 2 - √3 / 2 -√3 / 3
180° π 0 -1 0
270° 3π / 2 -1 0 不存在
360° 0 1 0

<== skew() ==>

说明: 斜切用到了三角函数tan,对应的是b和c两个参数,需要注意的是 b参数表示的是轴的斜切,而后面的参数c才是轴的斜切

css 复制代码
matrix(1, tan(θy), tan(θx), 1, 0, 0)

/* 转换后的坐标(x,y)为 */
(x,y) = (x + ytan(θx), xtan(θy) + y)

==> transform-origin属性 <==

作用: 变换默认是相对于元素的中心点进行的,这个中心点是由transform-origin属性决定的,因此这个属性作用的本质在于改变transform变换的中心点坐标

说明: 在IE10+浏览器中则支持3个属性值,分别表示x轴、y轴和z轴的变换中心点,初始值是50%、50%和0

  • z轴只能是数值

  • x轴和y轴支持百分比、数值和关键字属性值,关键字属性值是自带方位的,就是left和right表示x轴,top和bottom表示y轴,对于center关键字,是可以省略的,如果看到单个值语法,则另外一个省略的值就是50%

css 复制代码
/* x轴 | y轴 */
transform-origin: right top;
/* y轴 | x轴 */
transform-origin: top right;


/* 这两种写法一致 */
transform-origin: bottom center;
transform-origin: bottom;


/* 这两种写法等价 */
transform-origin: 20px;
transform-origin: 20px 50%;

==> zoom属性缩放 <==

语法:

css 复制代码
zoom: normal | reset | <number> | <percentage>

说明:

  • 百分比值:zoom:50%,表示缩小到原来的一半

  • 数值:zoom:0.5,表示缩小到原来的一半

  • normal关键字:zoom:normal等同于zoom:1,是默认值

  • reset关键字:zoom:reset,表示用户按Ctrl和−或Ctrl和+进行文档缩放的时候,元素不跟着缩小与放大。不过,这个关键字兼 容性很糟糕,仅被Safari浏览器支持。

与scale()函数缩放的区别:

  • zoom属性是一个非标准属性

  • zoom属性缩放的中心坐标是相对于元素的左上角,且不能修改。transform变换中的scale()函数缩放默认的中心坐标是元素的中心点

  • zoom属性缩放会实时改变元素 占据的尺寸空间,因此会触发大量的重绘和重排,导致其性能比scale()函数差

  • 元素应用zoom属性不会出现transform属性后的那几个表现的效果

(5)实用的calc()函数

说明: 这个函数支持加减乘除四种运算,其支持使用的数据类型有<length>、<frequency>、<angle>、<time>、<percentage>、<number>或者<integer>,在使用的时候,有以下注意点,同时,min()、max()和clamp()这几个函数使用的时候也是支持这几个数据类型的

  • 不能使用当前CSS属性不支持的数据类型

  • 运算符前后带单位或者带百分号的值只能进行加减运算,不能进行乘除运算

  • 除法运算斜杠右侧必须是不为0的数值类型

  • 加号和减号左右两边一定要有空格,因为浏览器无法区分−2rem和+2px是表示正负还是表示计算

  • 乘法和除法符号两侧无须空格,但是为了格式一致、便于阅读,建议也要设置空格。

举例: 模拟进度条效果

html 复制代码
<label>图片1:</label>
<div class="bar" style="--percent: 60"></div>

<label>图片2:</label>
<div class="bar" style="--percent: 40"></div>

<label>图片3:</label>
<div class="bar" style="--percent: 20"></div>
css 复制代码
.bar {
    line-height: 20px;
    background-color: #eee;
    width: 200px;
}

.bar::before {
    counter-reset: progress var(--percent);
    content: counter(progress) "%\2002";
    display: block;
    width: calc(100% * var(--percent) / 100);
    font-size: 12px;
    color: #fff;
    background-color: deepskyblue;
    text-align: right;
    white-space: nowrap;
    overflow: hidden;
}

==> min() <==

说明: 支持一个或多个表达式,每个表达式之间使用逗号分隔,然后将最小的表达式的值作为返回值

举例: 希望网页在桌面端浏览器中的宽度为1024px,在移动端的宽度为100%

css 复制代码
/* 在网页端的时候,一般屏幕的大小是大于1024的,所以和100%相比1024就是最小值 */
/* 从而设置的就是1024的宽度,而在移动端,那个手机的宽度能够达到1024,从而100% */
/* 就是最小值从而返回了 */
width: min(1024px, 100%);

==> max() <==

说明; 这个跟min()是类似的,只不过这个是选择最大值,而min是选择最小值,其它的都是一致的

==> clamp() <==

语法:

css 复制代码
clamp(MIN, VAL, MAX)

解释; 这里,MIN表示最小值,VAL表示首选值,MAX表示最大值。这段语句的意思是:如果VAL在MIN~MAX范围内,则使用VAL作为函数返回值;如果VAL大于MAX,则使用MAX作为返回值;如果VAL小于MIN,则使用MIN作为返回值。

相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60615 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅6 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment6 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端
爱敲代码的小鱼6 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax