Modern Css Experience
如果你问一个前端开发者三板斧中哪一项最让人头疼 不同阶段的人回答会有所不同
但无论是对于新手还是老师傅来说css
都是那个让人又爱又恨的存在
并且css
也陆续有新特性出现 许多备受期待的特性也受到了主流浏览器的支持让开发者可以安心使用
本文将对一些新的或者说平时不怎么关注的特性进行梳理
希望可以开阔一些想法 灵活运用更多知识
如果想要了解更多 也可以移步至大佬博客
视口单位
概念
视口单位vw vh
的概念直观地展示了视口的宽高
但是在移动设备上情况会有所不同 首先在移动设备上会分为大小两种视口
也就是图片中的svh lvh
100vh趋向于匹配lvh
如果想要达到动态切换svh/lvh
的效果 就需要使用dvh
兼容性
颜色相关
简写
/* 不用再写,啦 */
background-color: rgb(255 255 0)
background-color: lab(0% 0 0)
background-color: hwb(206 0% 42%)
lab()
lab函数可以从 CIELAB color space 获取整个色域范围
如今显示器可以显示比sRGB色彩空间更多的颜色 我们可以通过lab()来访问
接受三个值 lab(lightness a-axis b-axis)
lightness代表亮度 通常来说是0%~100% 也可能到达400%表示超级亮的白色
后两个参数表示色调 理论上无界 但实际上[-160,160]
hwb()
与前者类似
hwb(hue whitness blackness / alpha) => 色调 白度 灰度 / 透明度
conic-gradient()
可用该函数创建围绕中心点选中的颜色渐变
/*
1. 默认情况下 从0度开始顺时针旋转
2. 可设置旋转角度
3. 可以设置偏离原心的点(单位 百分比 关键字left/center等)
4. 控制渐变范围
*/
div {
background-image: conic-gradient(aqua, fuchsia, salmon, aqua);
}
div {
background-image: conic-gradient(from 90deg, aqua, fuchsia);
}
div {
background-image: conic-gradient(from 90deg at 4rem 4rem, aqua, fuchsia);
}
div {
background-image: conic-gradient(aqua 0deg 50deg, fuchsia 80deg 100deg, salmon 130deg 140deg, aqua 360deg)
}
color-scheme
使用该属性可以更改浏览器默认的配色方案
注意并非是像想的那样全部改变 而是有一定的作用范围
包括 表单控件 滚动条 CSS系统颜色
表单控件
单独对某个表单元素直接使用
select {
color-scheme: dark;
}
其它表单的深色模式对比
滚动条
MDN官网
系统颜色
以button为例 其默认样式中使用到了一些系统颜色
这些颜色会根据color-scheme
自动适应深色模式
button{
color: buttontext;
background-color: buttonface;
border-color: buttonborder;
}
并且这些元素可以在普通元素中使用 这样普通颜色也能使用这些值做到自适应
兼容性
自定义属性
使用
通过var来使用
:root {
--main-bg-color: pink;
}
body {
background-color: var(--main-bg-color);
}
var()
中还可以传入回退值 如果第一个值没有定义 会使用该回退值
.item1 {
background-color: var(--not-set, #000);
}
回退值中也可以使用var()
.item2 {
background-color: var(--not-set, var(--also-not-set, #00f));
}
值的忽略
.item3 {
background-color: #F00;
/* 无效值被忽略 */
background-color: blahaha;
}
如果第二个声明是不存在的自定义属性 此时不会被忽略 而是使用继承值
.item4 {
/*第二个声明是不存在的自定义属性 此时不会被忽略 使用继承值*/
background-color: #F00;
background-color: var(--not-set);
}
自定义属性中的优先级
normal vs custom
.example {
/*
自定义属性后面有!important的话 会被解析器移除该关键字 所以后面的属性就会覆写
*/
--color: red !important;
color: var(--color);
color: blue;
}
.example3 {
/* 最后还是blue */
--color: red !important;
--color: blue;
color: var(--color);
color: blue;
}
custom
.example1 {
/* 一样优先级的话会像普通属性那样后面覆盖前面 */
--color: red;
--color: blue;
color: var(--color);
}
.example2 {
/* 都是自定义属性的话 可以用!important来改变权重 */
--color: red !important;
--color: blue;
color: var(--color);
}
自定义url
场景: 点击按钮时切换背景图片
首先抛出一种错误写法 url()
的参数中没有"" or ''时 并非传入一个string 而是需要转义的url-token
button {
--background-image: "/not-pressed.svg";
background: url(var(--background-image));
}
button[aria-pressed="true"] {
--background-image: "/pressed.svg";
}
正确写法
button {
--background-image: url("/not-pressed.svg");
background: var(--background-image);
}
button[aria-pressed="true"] {
--background-image: url("/pressed.svg");
}
简写与逻辑属性
全局属性dir
可以用来指明元素中文本方向
其值为逻辑属性 ltr
rtl
auto
margin
margin-inline
margin-block
都为简写属性
分别代表水平方向与竖直方向的值
接收1-2个value 2个value时则表示(start - end)
此时回考虑direction 也就是dir定义的
padding
与margin一致
inset
它也是简写属性 代替定位时四个方向都要赋值的写法
同样具有逻辑属性 inset-inline
inset-block
在绝对定位中让子元素填充满父元素
.outer {
border: 10px solid hotpink;
position: relative;
width: 7rem;
height: 7rem;
}
.inner {
position: absolute;
inset: 0;
background-color: aqua;
z-index: 99;
}
在固定定位中填充视口
.inner_f {
position: fixed;
inset: 0;
background: #008c8c;
}
函数
min() and max()
接受以逗号分隔的一系列值 取最小/最大的那个
但是使用静态值意义不大 正确用法是配合相对单位使用
div {
/* 表示最大值为800px 小于800时自适应 */
width: min((100%, 800px))
}
.wrapper {
/* 宽度自适应的居中展示 最大宽度为64rem*/
height: 100px;
margin-inline: max(0px, ((100% - 64rem) / 2));
background-color: rgb(255 255 0);
}
clamp()
clamp(minmum, preferred, maxmum)
定义了三个值
clamp(300px, 90%, 700px)
=> max(300px, min(90%, 700px))
表示可以在[300px,700px]直接自适应
伪类
:has()
:has()目前来说仅在Firefox中缺失 但是它在一个标志后面 很快就能得到支持
检测父元素是否包含一个特定的子元素
/* 如果.form-item包含aria-invalid = "true"属性的子元素 */
.form-item:has([aria-invalid="true"]) {
--color: #caf;
}
/* 如果div包含p元素 */
div:has(p) {
margin-top: 10px;
border: 4px solid var(--color);
}
注意这样嵌套的写法是无效的
div:has(p:has(strong)) {
/* 无效 */
}
/* 正确写法 */
div:has(p strong){
border: 2px solid yellow;
}
权重
/* 这两个权重一样 */
div.child {
background-color: #caf;
}
div:has(.hh) {
background-color: green;
}
与组合器使用
/* 与 > 组合 */
fieldset:not(:has(> legend)) {
border: 10px solid red;
}
/* 与 + 组合 */
h2 {
margin-block-end: 0.7em;
}
h2:has(+ time){
margin-block-end: 0;
}
选中特定个数的子项 >= 3 / =3
ul:has(>:nth-child(3)){
border: 10px solid yellow;
}
ul:has(>:nth-child(3):last-child){
border: 10px solid blue;
}
:has(:not())
:not(:has())
/* 选中的元素不含img元素 */
.right:not(:has(img)) {
border-style: dotted;
}
/* 选中的元素含有除了img元素以外的任意元素 */
.wrong:has(:not(img)) {
border-style: dotted;
}
:is() :where()
这两个伪类用于以更紧凑的形式书写选择器
input:where([type="text"],
[type="email"],
[type="url"],
[type="tel"],
[type="password"],
[type="search"]) {
border: 2px solid;
}
两者区别
:where
不会增加权重 button:where(.button1) => button
:is()
则会 button:is(.button1) => button.button1
/* case */
.where input:where([type="text"], [type="email"], [type="url"]) {
background-color: #efefef;
border: 2px solid;
}
.where [aria-invalid="true"] {
border-color: red;
}
forgiving-selectors
当我们使用选择器列表时 其中一项无效或不存在或浏览器不支持
那这个列表所有选择器都会失效
这时候可以用 :has() :where() :is()
它们会自动忽略列表中无效的那个选择器
:modal
modal伪类用于控制showModal打开后的样式
::backdrop()
可控制背景样式
:modal {
border-style: dashed;
border-color: red;
padding: 4rem;
background-color: lab(62% 30 24);
}
::backdrop {
background-color: lab(62% 30 24/40%);
}
:placeholder-shown
选中还没改变placeholder的输入框
其它
scrollbar-gutter
该属性允许为滚动条保留空间 避免因内容增长引起的布局改变 避免不需要滚动时出现不必要的效果
stable
- 预留空间 这样文字也会更加紧凑 同时该元素必须是overflow
放在body无效 推荐放到html
stable both-edges
- 文字居中 两侧预留
font-variation-settings
用于调节可变字体的 weight width
p {
font-family: 'Saira', sans-serif;
font-size: 2rem;
font-variation-settings: 'wght' 736, 'wdth' 360;
}
可以去 这里 直观感受一下
aspect
aspect
用来定义宽高比 如果同时写了两个值 aspect-ratio: auto 3 / 1
可替换元素会使用固有的比例 其它元素会使用3 / 1
如果元素的高度超过了定义的高度 此时可以使用overflow:auto
overscroll-behavior
作用于这种嵌套滚动的场景
当内部滚动区域到底部以后 再滚动会影响外部的滚动区域
如果希望滚动不会像链式那样 可以使用overscroll-behavior: none
container queries
使用它可以让任何父元素达到媒体查询那样的功能
不止是宽度 还可以有高度 方向 自定义属性
但对于容器尺寸相关与容器样式相关的属性 有一个重要的区别
尺寸容器需要明确定义 才会发挥作用
container-type
有两个值 inline-size
和 size
没有block-size
需要注意的是 container中的width总是指代content-box
/* That's our size container. */
section {
width: 50%;
container-type: inline-size;
}
/* width超过500px时触发 */
@container (min-width: 500px) {
.card {
background-color: hotpink;
}
}
explicit property
- inherit: 从parent那继承定义好的属性值
- innitial: 将属性设置为初始值 注意初始值并不是默认值
- unset: 可继承属性继承自parent 否则使用初始值
- revert: 可继承属性继承自parent 否则用上一个级联层的值 如default值等 如果还是没有就initial值
transform
transform的值可独立存在 这样发生改变时不必所有都写
button {
translate: 20px 0;
rotate: 15deg;
scale: 1;
}
button:is(:hover, :focus) {
scale: 2;
}
backdrop-filter
将CSS过滤器应用于元素后面的区域 可以是元素或对话框的背景
并且不会影响文字 这是与filter的差异
.parent {
/**/
background-image: url("https://assets.codepen.io/144736/neue-donau+%281%29.webp");
}
.blur {
backdrop-filter: blur(5px);
}
.invert {
backdrop-filter: invert(1);
}
.hue {
backdrop-filter: hue-rotate(260deg);
}
.grayscale {
backdrop-filter: grayscale(100%);
}
@layer
@layer
声明了一个级联层 同一层内的规则将级联在一起
不同级联层之间的权重不会相互干扰 即优先级高的级联层 其权重永远大于优先级低的级联层
-
@layer X {} - 这种情况后面的优先级高于前者
/* red */ @layer A { .layer { background-color: blue; } } @layer B { div { background-color: red; } }
-
用@layer X, Y, Z提前声明 - 优先级 Z > Y > X 不看之后的书写顺序
- 如果一个layer被多次定义 只有第一次出现有效
/* blue */ @layer B,C,A @layer A { div { background: blue; } } @layer B { div { background: green; } } @layer C { div { background: orange; } }
-
非 @layer 包裹的样式 拥有比 @layer 包裹样式更高的优先级
/* green */ a { color: green; } @layer A { a { color: red; } } @layer B { a { color: orange; } }
-
嵌套层
- 无论是否存在嵌套 优先级都整体比优先级低的 @layer高
- 嵌套层 @layer A > @layer A.B
/* res => @layer C > @layer C.D > @layer A > @layer A.B */ @layer A { div { background: blue; } @layer B { div { background: red; } } } @layer C { div { background: yellow; } @layer D { div { background: green; } } }
-
revert-layer
- 在嵌套的layer中 revert-layer 可回滚样式到上一层layer
-
实际使用
我们需要引入第三方库的 CSS 为了便于管理 或者便于覆盖其中的一些样式
在之前 只能通过写优先级更高的class去覆盖 或者通过!important去覆盖
有了 @layer 之后 可以这样写:
@import(elementUI.css) layer(elementUI); @import(page.css) layer(page);
@layer A {
div {
background: blue;
}
@layer B {
div {
background: red;
}
}
}
@layer C {
div {
background: yellow;
}
@layer D {
div {
background: green;
}
}
}
- revert-layer
- 在嵌套的layer中 revert-layer 可回滚样式到上一层layer
- 实际使用
>我们需要引入第三方库的 CSS 为了便于管理 或者便于覆盖其中的一些样式
>
>在之前 只能通过写优先级更高的class去覆盖 或者通过!important去覆盖
有了 @layer 之后 可以这样写:
```css
@import(elementUI.css) layer(elementUI); @import(page.css) layer(page);
只要在page.css 里面写的样式 优先级都会比 elementUI.css 内的 CSS 优先级更高