- 前端
- CMS
【免费下载链接】wp-calypso
The JavaScript and API powered WordPress.com
导读
本文基于 wp-calypso 仓库中 client/my-sites/themes/AGENTS.md 文档,深入剖析 Calypso(WordPress.com 的 JavaScript/API 前端)中 Themes 主题市场(Theme Showcase,路由/themes)深色模式的完整实现链路:从登录态与 Dashboard 偏好决定是否启用深色主题的路由门控逻辑,到共享 CSS 自定义属性(design tokens)与 Themes 专属覆盖层的分层设计,再到新增组件时应遵循的验证规范。读完本文,你将掌握 Calypso 深色模式的分层架构、开关判定函数及其测试用例,以及"优先覆盖 CSS 变量而非硬编码颜色"这一核心开发准则的具体落地方式。
Themes 表面:它渲染什么、服务于哪些流程
在 AGENTS.md 开头即明确了 Themes 表面的职责:渲染/themes路由下的 Theme Showcase(主题市场)及相关视图。这份开发指引面向的并非单个组件,而是一整套覆盖多种业务场景的 UI 表面:
- 已登录用户(logged-in)与未登录访客(logged-out)都能访问;
- 支持单站点(single-site)视图与 Jetpack 站点(Jetpack-site)流程。
从目录结构看,client/my-sites/themes 下的实现分为若干模块:入口与控制器(index.web.js、controller.jsx、controller-logged-in.jsx)、核心展示组件(theme-showcase.jsx、themes-selection.jsx、theme-preview.jsx、single-site.jsx及其 wpcom/jetpack 分支)、筛选与搜索(filter-bar-modern/、search-results-modern/、validate-filters.js、search-themes-tracks.js)、主题集合(collections/)、以及上传与 FAQ 等附属能力(theme-upload/、themes-faq/)。深色模式正是在这样一套横跨登录态、站点类型与路由形态的表面上展开的。
深色模式的路由门控:shouldEnableThemesColorScheme()
AGENTS.md 明确指出,Themes 深色模式仅对已登录且已选择 Dashboard(新版控制台)体验的用户开放,当前的路由开关位于shouldEnableThemesColorScheme(),适用于"非站点级 Themes 路由",且要求isLoggedIn与dashboardOptIn同时为真。
函数实现
源码位于 client/my-sites/themes/helpers.js:
export function shouldEnableThemesColorScheme( { isSiteRoute, isLoggedIn, dashboardOptIn } ) { return ! isSiteRoute && isLoggedIn && dashboardOptIn; }三个输入参数的含义与取值:
| 参数 | 含义 | 说明 |
|---|---|---|
isSiteRoute | 当前是否为站点级主题路由(如/themes/{site}) | 为true时直接关闭深色模式 |
isLoggedIn | 用户是否已登录 | 未登录(logged-out)流程不启用深色模式 |
dashboardOptIn | 用户是否已选择 Dashboard 体验 | 由hasDashboardOptIn( state )从全局状态读取 |
消费方与调用链
在 client/my-sites/themes/theme-showcase.jsx 中,mapStateToProps将判定结果注入组件:
isThemesColorSchemeEnabled: shouldEnableThemesColorScheme( { isSiteRoute, isLoggedIn, dashboardOptIn: hasDashboardOptIn( state ), } ),随后在渲染入口(theme-showcase.jsx)通过withColorScheme包装整个 showcase,为深色模式挂载bodyClass: 'is-themes-dark-mode',并使用ClassicColorSchemeProvider提供上下文:
return withColorScheme( showcase, { bodyClass: 'is-themes-dark-mode', enabled: this.props.isThemesColorSchemeEnabled, Provider: ClassicColorSchemeProvider, } );也就是说,启用深色模式的最终效果是在body上添加is-themes-dark-mode类,配合既有颜色方案类(如is-classic-dark)或data-theme属性,驱动后续的样式覆盖层生效。
测试用例:判定规则的四种边界
client/my-sites/themes/test/helpers.js 用四组用例完整锁定了该函数的语义:
- 已登录 + 已 opt-in + 非站点路由→ 启用(
true); - 已登录 + 未 opt-in + 非站点路由→ 不启用(
false),证明dashboardOptIn是硬性前置条件; - 未登录 + 已 opt-in + 非站点路由→ 不启用(
false),证明isLoggedIn同样是硬性前置条件; - 已登录 + 已 opt-in + 站点路由→ 不启用(
false),证明isSiteRoute拥有最高优先级。
这四组用例实际上就是该功能的验收标准,任何改动都必须维持这一行为矩阵。
分层一:共享深色 Token(client/lib/color-scheme/dark-theme.scss)
AGENTS.md 强调:跨多个 Calypso 表面使用的共享组件所依赖的深色 token 与全局覆盖,统一放在client/lib/color-scheme/dark-theme.scss。当样式属于 Themes 之外、或影响多个区域的共享组件时,优先在这里新增或复用取值。
client/lib/color-scheme/dark-theme.scss 是一个约 900 行的共享样式库,核心机制是基于 CSS 自定义属性重新生成整套颜色体系。其中两个关键的 mixin 定义了深色调色板的生成规则:
@mixin color-scheme-dark-theme-color-palette($variable-name, $base-color) { --dashboard-#{$variable-name}-base: #{$base-color}; @each $index, $surface-percentage in (0: 98%, 5: 95%, 10: 91%, 20: 85%, 30: 76%, 40: 64%) { --#{$variable-name}-#{$index}: color-mix( in srgb, var( --dashboard-surface__background-color ) #{$surface-percentage}, var( --dashboard-#{$variable-name}-base ) ); } --#{$variable-name}-50: var( --dashboard-#{$variable-name}-base ); @each $index, $base-percentage in (60: 85%, 70: 70%, 80: 55%, 90: 38%, 100: 22%) { --#{$variable-name}-#{$index}: color-mix( in srgb, var( --dashboard-#{$variable-name}-base ) #{$base-percentage}, #fff ); } --#{$variable-name}: var( --#{$variable-name}-50 ); }这段代码揭示了深色调色板的设计思想(文件头部注释有明确说明):
- 低索引(0–40)是"深色背景上微着色表面"——由
dashboard-surface__background-color按 98%→64% 比例混入基色,越接近 0 越接近页面背景,用于卡片、面板等表面; - 50 索引等于基色本身;
- 高索引(60–100)保持足够亮度——按 85%→22% 比例将基色混入白色,用于前景文本、强调色、hover/active 状态等需要可读性的场景。
同时还有别名机制color-scheme-dark-theme-color-palette-alias(dark-theme.scss),例如--studio-wordpress-blue与--color-neutral分别别名到--studio-blue、--studio-gray,从而让共享组件无需感知具体来源即可引用统一的 token 名。
此外该文件还提供了color-scheme-dark-theme-tokens(将--wp-components-*系列映射到深色值,保证依赖 WordPress 组件变量的控件自适应)、color-scheme-dark-theme-calypso-properties(--color-text、--color-surface、--color-border-subtle)等基础设施,共同构成"共享深色基线"。
分层二:Themes 专属覆盖(client/my-sites/themes/_dark-mode.scss)
AGENTS.md 规定:仅属于 Theme Showcase 的深色例外规则,集中在client/my-sites/themes/_dark-mode.scss,避免把局部样式塞进全局共享文件。
client/my-sites/themes/_dark-mode.scss 正是 Themes 的深色覆盖层,其结构分为两级 mixin:
1.themes-dark-mode-color-scheme:颜色方案重映射
@mixin themes-dark-mode-color-scheme { @include color-scheme-dark-theme-calypso-overrides; @include color-scheme-dark-theme-color-palette-alias( 'theme-highlight-color', 'color-accent' ); --color-success-dark: var( --color-success-70 ); --color-success-light: var( --color-success-30 ); --color-warning-dark: var( --color-warning-70 ); --color-warning-light: var( --color-warning-30 ); --color-error-dark: var( --color-error-70 ); --color-error-light: var( --color-error-30 ); --theme-text-color: var( --dashboard__text-color ); --theme-base-color: var( --dashboard__background-color ); --theme-submenu-text-color: var( --dashboard__text-muted-color ); --theme-submenu-background-color: var( --dashboard-surface__background-color ); --theme-icon-color: var( --dashboard__text-muted-color ); --theme-notification-color: var( --wp-admin-theme-color ); // ... }可以看到 Themes 层完全没有硬编码颜色,而是把--theme-*系列内部变量逐一映射到 Dashboard 深色体系提供的--dashboard-*与--color-*变量上,形成"Themes 专属 token → 共享 token"的取值链。
2.themes-dark-mode-root:组件级覆盖
@mixin themes-dark-mode-root { @include themes-dark-mode-color-scheme; @include color-scheme-dark-theme-wpnc-panel; @include color-scheme-dark-theme-community-translator; @include color-scheme-dark-theme-masterbar; // 组件级覆盖,例如: .iframe-preview-card { /* 边框、focus、选中态的深色调整 */ } .themes-list__options { /* 列表下拉面板的深色表面 */ } .theme__sheet-web-preview, .theme__sheet-screenshot { /* 预览区域的深色表面 */ } .theme-collection__carousel-controls { /* 主题集合轮播按钮的 hover/focus 态 */ } // ... }其中值得关注的点:
- iframe 预览卡(
.iframe-preview-card):因为 iframe 内永远是浅色站点页面,所以覆盖时使用稳定的 Dashboard 页面背景--dashboard__background-color作为入口按钮底色,而非任何被深色 mixin 重映射过的中性色——这是"局部覆盖必须基于语义而非直觉"的典型范例; - 激活弹窗(
.themes__activation-modal):Dashboard 深色主题会重新生成 studio-blue 色阶(60+ 混入白色),因此弹窗里的 tertiary 按钮改用更高索引的--studio-blue-70以保证可读性,文件注释明确说明了这一取舍; - badge 反转:
theme-tier-badge中的 premium/信息 badge 在深色下把--studio-black/--studio-white映射到 Dashboard 表面与文本色,保证层级反转后依然对比清晰。
3. 挂载条件:theme-showcase.scss
覆盖层真正生效的挂载点位于 client/my-sites/themes/theme-showcase.scss:
body.color-scheme.is-themes-dark-mode.is-classic-dark, :root[data-theme='dark'] body.color-scheme.is-themes-dark-mode { @include themes-dark-mode-root; } @media ( prefers-color-scheme: dark ) { :root[data-theme='system'] body.color-scheme.is-themes-dark-mode { @include themes-dark-mode-root; } }三种触发场景一目了然:
- 经典深色(classic dark):
body同时带有is-classic-dark与is-themes-dark-mode类; - 跟随系统(system)且系统为深色:
:root[data-theme='dark']生效; prefers-color-scheme: dark:data-theme='system'且系统偏好深色时,通过媒体查询动态套用。
换句话说:shouldEnableThemesColorScheme()决定"要不要开"(body上是否出现is-themes-dark-mode),而 SCSS 选择器决定"在哪种颜色方案语境下以何种方式开"。
开发规范:新增组件时的深色模式检查清单
AGENTS.md 对开发者给出了三条可执行的规范,这也是本模块最容易被忽略、却最影响深色体验的部分:
新增一个尚未在深色支持的表面上使用过的组件时,必须在深色模式下实际验证,并视需要新增或复用覆盖规则。也就是说"能用共享基线"与"验证过"是两件事,后者是硬性要求。
如果组件已被现有深色基线覆盖,可以假定共享样式依然成立——除非新用法引入了新的变体(variants)、状态(states)、包装器(wrappers)或局部 CSS。例如同一组件从"纯展示"变为"带 hover 状态的下拉",就需要重新评估其深色表现。
优先覆盖已有的 CSS 自定义属性,而不是硬编码颜色。这是贯穿整个体系的第一原则:所有覆盖都应该写成
var( --dashboard-* )、var( --color-* )或var( --theme-* )的重新赋值,而不是写入#1e1e1e、#fff之类的字面值。这样既保证语义统一,也能在颜色方案切换时自动跟随,避免"局部漂移"。
从 client/my-sites/themes/_dark-mode.scss 的每一个规则都可以验证这一点:从卡片 placeholder 背景到空搜索文案颜色,全部通过var( --dashboard-surface__border-color )、var( --dashboard__text-muted-color )等变量表达,甚至盒阴影也使用color-mix( in srgb, var( --dashboard__text-color ) 12%, transparent )动态生成。
小结:一条完整的深色模式决策链
将整个机制串联起来,Themes 深色模式的完整决策与渲染链路为:
- 判定:
shouldEnableThemesColorScheme({ isSiteRoute, isLoggedIn, dashboardOptIn })(helpers.js)对三条件取与,规则由四组测试锁定(test/helpers.js); - 注入:
mapStateToProps经hasDashboardOptIn( state )取 opt-in 状态,把结果传入ThemeShowcase(theme-showcase.jsx); - 挂载:
withColorScheme在body上添加is-themes-dark-mode类(theme-showcase.jsx); - 着色:SCSS 在 classic-dark / system-dark / prefers-color-scheme 三种语境下套用
themes-dark-mode-root(theme-showcase.scss); - 取值:Themes 专属 token(
--theme-*)→ 共享 Dashboard 深色 token(--dashboard-*、--color-*、--studio-*)→ 由 dark-theme.scss 的调色板 mixin 动态生成的颜色。
对任何要在 Calypso 中新增或修改深色样式的人来说,这条链路就是"往哪个文件加、用什么变量、在什么条件下生效"的完整答案:共享的进dark-theme.scss,Themes 局部的进_dark-mode.scss,判定逻辑改动必须同步更新test/helpers.js的边界用例,而一切颜色都必须通过 CSS 自定义属性表达。
- 前端
- CMS
【免费下载链接】wp-calypso
The JavaScript and API powered WordPress.com
相关推荐
wp-calypso Themes 模块暗色模式支持:路由门控、样式分层与开发实践
wp calypso Themes 模块暗色模式支持:路由门控、样式分层与开发实践 本文基于 wp calypso 仓库中 client/my sites/th
前端CMSArk UI 主题系统构建:从CSS变量到暗色模式的完整实现
Ark UI 主题系统构建:从CSS变量到暗色模式的完整实现 Ark UI 作为一款无样式组件库,其强大的主题系统让开发者能够轻松构建可扩展的设计系统。无论你是
前端UI组件设计系统Piskel主题开发指南:CSS变量与深色模式实现
Piskel主题开发指南:CSS变量与深色模式实现 引言 Piskel作为一款基于Web的像素艺术创作工具,提供了丰富的主题定制功能。本文将详细介绍如何通过CS
前端图像处理
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考