默认情况下,选择器跟随操作系统的设置。一旦你的应用有了自己的主题切换,问题就来了:两者会不一致。比如有人在浅色的桌面系统上以深色模式浏览你的网站,打开选择器看到的却是一个白色面板。把应用最终生效的主题交给选择器,这个问题就解决了。
"use client";
import { ColorInput } from "chroma-panel";
import "chroma-panel/style.css";
import { useTheme } from "next-themes";
function panelTheme(value: string | undefined) {
if (value === "dark") return "dark" as const;
if (value === "light") return "light" as const;
return undefined;
}
export function ThemedColorInput() {
const { resolvedTheme } = useTheme();
return (
<ColorInput
name="brand"
defaultValue="#3366cc"
theme={panelTheme(resolvedTheme)}
/>
);
}theme 只接受 "dark" 和 "light",而 resolvedTheme 的类型是 string | undefined,所以上面的类型收窄并不是多此一举。返回 undefined 也是有意义的:不传 theme 时,面板会回到跟随系统偏好的状态。在 provider 还没解析出主题之前,这就是最合理的选择。
ChromaPanel 上也有同一个 prop,两者用法完全相同。它和面板的其他 prop 放在一起的情况,请参阅 ChromaPanel 参考文档。
跟随系统
这是默认行为。面板的背景、边框、文字和强调色都以 light-dark() 成对声明,面板根元素上声明了 color-scheme: light dark,浏览器会根据用户的偏好选择对应的一侧。不用传任何参数,不涉及水合,首次绘制也不会闪烁,因为这个选择是在 CSS 中完成的,而不是在 JavaScript 中。
固定为一种主题
如果周围的界面不会变,就直接传入 theme。比如在深色编辑器外框中的选择器,即使整个应用是浅色的,也应该保持深色:
<ChromaPanel theme="dark" defaultValue="#3366cc" />样式表如何决定主题
theme 会以 data-cp-theme 属性的形式出现在面板根元素上,值为 dark 或 light。样式表随后把这个根元素的 color-scheme 设为对应的单一值,于是每个 light-dark() 令牌都会取这一侧的值。如果什么都不传,就不会有这个属性,color-scheme: light dark 保持不变,由用户偏好决定。
宽度小于 640px 时,选择器会变成底部面板,它的样式是单独匹配的,所以遮罩和面板背景会跟随其中的面板,而不会各行其是。
由于这个属性就在面板根元素上,面板进入弹出层时它也会跟着走。弹出层渲染在 document.body 中,而不在你的布局里,因此作用于某个外层元素的深色样式影响不到它,而针对 .cp-root 的选择器可以。
修改深色配色
这个包的样式规则都放在 @layer chroma-panel 级联层中,而不在任何层中的 CSS 优先级高于层内的规则。所以你自己的样式表可以替换任意令牌,不必和选择器优先级较劲:
.cp-root {
--cp-surface: light-dark(#ffffff, #0b0b0f);
--cp-accent: light-dark(#2d7ff9, #7aa2ff);
}把覆盖值也写成 light-dark() 对,就能在一条规则里同时写好两侧,自动切换也能照常工作。完整的令牌列表见主题页面;在 Next.js App Router 中使用选择器的方法,见 Next.js 页面。
两种变深色的方式
theme 只作用于面板本身。--cp- 自定义属性决定面板具体用哪些颜色。用 theme
选择深浅;如果内置的深色不是你想要的深色,就用这些自定义属性。