0
点赞
收藏
分享

微信扫一扫

#yyds干货盘点#具有自定义属性的 CSS Paint API 中的 Honors prefers-color-scheme

在过去的几年里,我一直在搞砸的最酷的事情之一就是​​CSS Paint API​​​。我喜欢它。​​我就此进行了一次演讲​​​,并制作​​了一个我自己的绘画作品的小画廊​​​。另一个很酷的事情是​​prefers-color-scheme媒体查询​​以及如何使用它来适应用户对亮或暗模式的偏好。

最近,我发现我可以将这两个​非常酷的东西​与 CSS 自定义属性结合起来,这样就可以定制绘制工作集的外观以适应用户首选的配色方案!

设置舞台

我已经逾期进行网站大修,我决定使用​​最终幻想 II​​​主题。我的首要任务是制作一个随机生成的最终幻想风格景观的绘画作品,我将其命名为​​overworld.js​​:

#yyds干货盘点#具有自定义属性的 CSS Paint API 中的 Honors prefers-color-scheme_自定义属性由 CSS Paint API 实现的随机生成的 8 位样式景观!

它可以使用更多的装扮——这肯定在议程上——但这是一个该死的好开始!

完成paint worklet 后,我继续在网站的其他部分工作,例如用于明暗模式的主题切换器。就在那时,我意识到paint worklet 并没有适应这些偏好。这通常可能是一个巨大的痛苦,但使用 CSS 自定义属性,我意识到我可以相对轻松地将paint worklet 的渲染逻辑调整为用户首选的配色方案!

为绘制工作集设置自定义属性

这些天 CSS 的状态非常糟糕,CSS 自定义属性就是前面提到的愚蠢的例子之一。为确保同时支持 Paint API 和自定义属性功能,您需要进行如下的功能检查:

const paintAPISupported = "registerProperty" in window.CSS && "paintWorklet" in window.CSS`

第一步是定义您的自定义属性,其中涉及​​CSS.registerProperty​​方法。看起来像这样:

CSS.registerProperty({
name, // The name of the property
syntax, // The syntax (e.g., <number>, <color>, etc.)
inherits, // Whether the value can be inherited by other properties
initialValue // The default value
});

自定义属性是使用 Paint API 的最佳部分,因为这些值是在 CSS 中指定的,但在paint worklet 上下文中是可读的。这为开发人员提供了一种超级方便的方式来控制绘制工作集的渲染方式——​完全在 CSS 中​。

对于​​overworld.js​​paint worklet,自定义属性用于定义随机生成的景观的各个部分的颜色——草和树、河流、河岸等等。这些颜色默认值适用于灯光模式配色方案。

我注册这些属性的方法是在我调用的对象中设置所有内容,​​Object.entries​​​然后遍历这些条目。在我的​​overworld.js​​油漆工作中,看起来像这样:

// Specify the paint worklet's custom properties
const properties = {
"--overworld-grass-green-color": {
syntax: "<color>",
initialValue: "#58ab1d"
},
"--overworld-dark-rock-color": {
syntax: "<color>",
initialValue: "#a15d14"
},
"--overworld-light-rock-color": {
syntax: "<color>",
initialValue: "#eba640"
},
"--overworld-river-blue-color": {
syntax: "<color>",
initialValue: "#75b9fd"
},
"--overworld-light-river-blue-color": {
syntax: "<color>",
initialValue: "#c8e3fe"
}
};

// Register the properties
Object.entries(properties).forEach(([name, { syntax, initialValue }]) => {
CSS.registerProperty({
name,
syntax,
inherits: false,
initialValue
});
});

// Register the paint worklet
CSS.paintWorklet.addModule("/worklets/overworld.js");

因为每个属性都设置了一个初始值,所以以后调用绘制工作集时不必指定任何自定义属性。但是,由于这些属性的默认值可以被覆盖,因此可以在用户表达对配色方案的偏好时对其进行调整。

适应用户的首选配色方案

我正在处理的网站刷新有一个设置菜单,可以从网站的主导航访问。从那里,用户可以调整一些偏好,包括他们喜欢的配色方案:


配色方案设置循环通过三个选项:

  • 系统
  • 黑暗的

“系统”默认为用户在其操作系统设置中指定的任何内容。​​light​​​最后两个选项通过在元素上设置一个或​​dark​​​类来覆盖用户的操作系统级别设置​​<html>​​​,但是在没有明确的情况下,“系统”设置依赖于​​prefers-color-scheme​​媒体查询中指定的任何内容。

此覆盖的铰链取决于 CSS 变量:

/* Kicks in if the user's site-level setting is dark mode */
html.dark {
/* (I'm so good at naming colors) */
--pink: #cb86fc;
--firion-red: #bb4135;
--firion-blue: #5357fb;
--grass-green: #3a6b1a;
--light-rock: #ce9141;
--dark-rock: #784517;
--river-blue: #69a3dc;
--light-river-blue: #b1c7dd;
--menu-blue: #1c1f82;
--black: #000;
--white: #dedede;
--true-black: #000;
--grey: #959595;
}

/* Kicks in if the user's system setting is dark mode */
@media screen and (prefers-color-scheme: dark) {
html {
--pink: #cb86fc;
--firion-red: #bb4135;
--firion-blue: #5357fb;
--grass-green: #3a6b1a;
--light-rock: #ce9141;
--dark-rock: #784517;
--river-blue: #69a3dc;
--light-river-blue: #b1c7dd;
--menu-blue: #1c1f82;
--black: #000;
--white: #dedede;
--true-black: #000;
--grey: #959595;
}
}

/* Kicks in if the user's site-level setting is light mode */
html.light {
--pink: #fd7ed0;
--firion-red: #bb4135;
--firion-blue: #5357fb;
--grass-green: #58ab1d;
--dark-rock: #a15d14;
--light-rock: #eba640;
--river-blue: #75b9fd;
--light-river-blue: #c8e3fe;
--menu-blue: #252aad;
--black: #0d1b2a;
--white: #fff;
--true-black: #000;
--grey: #959595;
}

/* Kicks in if the user's system setting is light mode */
@media screen and (prefers-color-scheme: light) {
html {
--pink: #fd7ed0;
--firion-red: #bb4135;
--firion-blue: #5357fb;
--grass-green: #58ab1d;
--dark-rock: #a15d14;
--light-rock: #eba640;
--river-blue: #75b9fd;
--light-river-blue: #c8e3fe;
--menu-blue: #252aad;
--black: #0d1b2a;
--white: #fff;
--true-black: #000;
--grey: #959595;
}
}

这是重复的——我敢肯定有人知道更好的方法——但它可以完成工作。无论用户明确的站点级别偏好或他们的底层系统偏好如何,页面最终都会以适当的配色方案可靠地呈现。

在绘制工作集上设置自定义属性

如果支持 Paint API,文档中的一个小内联脚本​​<head>​​​将一个​​paint-api​​​类应用于​​<html>​​元素。

/* The main content backdrop rendered at a max-width of 64rem.
We don't want to waste CPU time if users can't see the
background behind the content area, so we only allow it to
render when the screen is 64rem (1024px) or wider. */
@media screen and (min-width: 64rem) {
.paint-api .backdrop {
background-image: paint(overworld);
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;

/* These oh-so-well-chosen property names refer to the
theme-driven CSS variables that vary according to
the user's preferred color scheme! */
--overworld-grass-green-color: var(--grass-green);
--overworld-dark-rock-color: var(--dark-rock);
--overworld-light-rock-color: var(--light-rock);
--overworld-river-blue-color: var(--river-blue);
--overworld-light-river-blue-color: var(--light-river-blue);
}
}

这里肯定有一些奇怪之处。出于某种原因,以后可能会或可能不会出现这种情况——但至少在我写这篇文章时是这样——你不能直接在​​<body>​​元素上渲染绘制工作集的输出。

另外,由于某些页面可能非常高,我不希望​整个​页面的背景都被随机生成(因此可能很昂贵)的艺术品填充。为了解决这个问题,我在一个使用固定定位的元素中渲染绘制工作集,该元素在用户向下滚动时跟随用户并占据整个视口。

除了所有的怪癖之外,这里的神奇之处在于,paint worklet 的自定义属性基于用户的系统(或站点级别)配色方案偏好,因为 CSS 变量与该偏好保持一致。对于​​overworld​​paint worklet,这意味着我可以调整其输出以与用户首选的配色方案保持一致!


不错!但这甚至不是控制paint worklet 渲染方式的创新方法。如果我愿意,我可以添加一些只会出现在特定配色方案中的额外细节,或者做其他事情来彻底改变渲染或添加一些小彩蛋。虽然今年我学到了很多东西,但我认为这种 API 的交叉点是我的最爱之一。

举报

相关推荐

0 条评论