大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。
随着 Chrome 139 对 if() 函数的支持,开发者可以编写更具条理、更动态的 CSS 了。
自定义属性允许存储通过 var() 访问的动态值,而自定义函数则可以执行逻辑,其接受传递给它的参数,并返回一个新值。开发者可以使用基于指定的函数语法(例如 --my-custom-function())来调用,而不是使用 var() 语法。
取反函数
下面的 CSS 自定义函数对一个值取反并返回负数:
@function --negate(--value) {
result: calc(-1 * var(--value));
}
接着可以在 CSS 声明中使用 --negate() 函数:
html {
--gap: 1em;
padding: --negate(var(--gap));
}
不透明度函数
下面函数可以将任何颜色转换为该颜色的不透明度变体,并接受两个值,即颜色值和不透明度值。
// 返回半透明值,rgb 函数的签名为:rgb(from <color> R G B[ / A])
// 定义相对颜色时始终包含关键字 from,后跟表示原始颜色的 <color> 值,后面的颜色基于原始颜色
@function --opacity(--color, --opacity) {
result: rgb(from var(--color) r g b / var(--opacity));
}
// 使用示例
div {
background-color: --opacity(red, 80%);
}
// 使用自定义属性,假设有主题变量
.card {
border-color: --opacity(var(--color-secondary), var(--mostly-opaque));
}
流畅排版函数
CSS 函数的另一个绝佳用途是用于字体大小调整方法 clip() ,从而确保文本在任何屏幕尺寸下始终清晰易读且显示良好。
clip() 函数会将中间值限制在定义的最小值和最大值之间的某个范围内,该函数接受三个参数:最小值、首选值和允许的最大值。
例如:下面的函数用于创建流畅排版,其可以随视口宽度缩放,但也有最小和最大尺寸限制。同时,还提供了一些选项,可以以不同的速率缩放字体,例如:标题的缩放速度比文本的缩放速度快:
@function --fluid-type(--font-min, --font-max, --type: 'header') {
--scalar: if(style(--type: 'header'): 4vw;
style(--type: 'copy'): 0.5vw);
// 结合 if 判断 type 的值类型,并将其放在 --scalar 上
result: clamp(var(--font-min), var(--scalar) + var(--font-min), var(--font-max));
}
// 使用 --fluid-type 函数,使用默认 header 类型
h1 {
--header-min: 24px;
--header-max: 36px;
font-size: --fluid-type(var(--header-min), var(--header-max));
}
// 使用 --fluid-type 函数,类型为 copy
p {
--copy-min: 16px;
--copy-max: 24px;
font-size: --fluid-type(var(--copy-min), var(--copy-max), 'copy');
}
有条件地圆角边框
这是一个有意思的 CSS 技巧,即当元素接近视口边缘时,有条件地移除圆角边框,从而避免布局异常,因为其会变成全宽,而且完全不需要任何媒体查询!
下面函数中,当框的边缘到达视口边缘(由 --edge-dist 插入,默认设置为 4px)时,移除 border-radius。否则,将其设置为 --radius。此函数使用默认值,因此可以仅使用一个参数来设置半径大小,或者使用两个参数来覆盖默认的 4px 边缘距离。
// --edge-dist: 20px; /* 页面边缘距离 */
// --radius: 16px; /* 最大圆角值 */
// 100vw - var(--edge-dist) /* 视口宽度减去边缘距离 */
// (100vw - var(--edge-dist)) - 100% /* 差值部分 */
// ((100vw - var(--edge-dist)) - 100%) * 1e5 /* 放大 100000 倍 */
// 乘以一个很大的数(100000)是为了确保中间值足够大,让 clamp 的中间参数能够达到最大值实现 "开关" 效果
@function --conditional-radius(--radius, --edge-dist: 4px) {
result: clamp(0px, ((100vw - var(--edge-dist)) - 100%) * 1e5, var(--radius));
}
.box {
// 1rem 的圆角,--edge-dist 默认 4px
border-radius: --conditional-radius(1rem);
}
.box-2 {
// 1rem 边框半径,--edge-dist 位于边缘(0px 距离)
border-radius: --conditional-radius(1rem, 0px);
}
布局侧边栏函数
开发者还可以将自定义函数与媒体查询结合使用,根据特定条件返回不同的结果。此函数会创建一个响应式侧边栏布局,因此只需调用 --layout-sidebar() 即可。在较小的屏幕上,其将占据整个宽度。但在较大的屏幕上,其会创建一个指定宽度的侧边栏和一个占据剩余空间的主内容区域。
下面的示例依然使用默认值,即 --sidebar-width 默认值为 20ch,如果提供了新值则使用新值。
@function --layout-sidebar(--sidebar-width: 20ch) {
result: 1fr;
// fr 是 fraction unit(分数单位),是 CSS Grid 布局中的专用单位
@media (width> 640px) {
result: var(--sidebar-width) auto;
}
}
.layout {
display: grid;
// 使用默认值
grid-template-columns: --layout-sidebar();
}
亮暗主题函数
使用 light-dark() 来根据用户偏好设置主题样式仅适用于颜色值,如果想将其用于其他用途,例如:背景图片或调整边框宽度则无能为力。
下面的自定义函数 --light-dark() 结合使用了 if()、:scope、style() 查询和 @function 函数,使 light-dark() 更具可扩展性。
@function --light-dark(--light, --dark) {
result: if(
style(--scheme: dark): var(--dark);
else: var(--light)
);
}
首先, --root-scheme 是根据 :root 级别的 prefers-color-scheme 媒体查询设置的,其会捕获操作系统设置:
:root {
--root-scheme: light;
--scheme: light;
@media (prefers-color-scheme: dark) {
--root-scheme: dark;
--scheme: dark;
}
}
然后,使用 @scope 和内联 if() 函数检查 [data-scheme] 属性。如果该属性的值为 system,则将 --root-scheme 的值应用于元素的 --scheme。否则,使用属性中提供的值(例如 “light” 或 “dark”):
@scope ([data-scheme]) {
:scope {
// 获取 HTML 中属性的值
--scheme-from-attr: attr(data-scheme type());
// 综合设置 --schema 变量的值,考虑了 HTML 属性和 --root-schema 的值
--scheme: if(
style(--scheme-from-attr: system): var(--root-scheme);
else: var(--scheme-from-attr)
);
color-scheme: var(--scheme);
/* To make the native light-dark() work */
}
}
下面是使用的方式:
[data-scheme] {
color: light-dark(#333, #e4e4e4);
background-color: light-dark(aliceblue, #333);
border: 4px --light-dark(dashed, dotted) currentcolor;
font-weight: --light-dark(500, 300);
font-size: --light-dark(16px, 18px);
}
<div class="stylable-thing" data-scheme="light">
…
</div>
参考资料
https://una.im/5-css-functions/
https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb
https://developer.mozilla.org/en-US/docs/Web/CSS/clamp