☰
Sabaki 用户样式(userstyle)完全指南:用 styles.css 定制棋盘与棋子外观
2026/10/14 23:06:12 网站建设 项目流程
  • 桌面应用

【免费下载链接】Sabaki

An elegant Go board and SGF editor for a more civilized age.

项目地址:https://gitcode.com/gh_mirrors/sa/Sabaki
点击查看免费下载

本篇基于 Sabaki 仓库内的 Userstyle Tutorial 展开,讲解如何在不替换任何程序文件、且升级后不会被覆盖的前提下,通过一个名为styles.css的自定义样式文件改变 Sabaki 的棋盘、棋子与整体外观。读完本篇,你将能够定位各平台下的styles.css实际路径,理解它在渲染进程中的注入位置与 CSS 层叠优先级,并利用开发者工具(DevTools)结合 Shudan 组件的选择器完成纹理定制。

什么是 userstyle,它为什么比改文件更可靠

Sabaki 的界面基于 HTML、CSS 与 JavaScript 构建(Electron 应用)。官方默认的棋盘与棋子纹理是内置样式的一部分,但并非不可更改。原文档给出的核心观点是:

  • userstyle 是改变 Sabaki 外观的最简单方式:你只需维护一个纯 CSS 文件,无需替换任何重要文件(important files);
  • 由于样式文件存放在用户数据目录而非程序安装目录,Sabaki 下一次更新(更新只替换程序本体)不会回滚你的修改。

从源码结构看,这个“不被覆盖”的承诺有明确的机制支撑:styles.css由主进程在首次启动时于用户数据目录中自动创建,程序自带的样式(见 index.html 中加载的 style/app.css、style/index.css、style/comments.css)全部位于打包后的应用内部,两者物理隔离。

第一步:确定 styles.css 的位置

原文档列出了三个平台下的配置(设置)目录:

平台目录
Windows%APPDATA%\Sabaki
Linux$XDG_CONFIG_HOME/Sabaki,未设置该环境变量时为~/.config/Sabaki
macOS~/Library/Application Support/Sabaki

该目录内存在一个名为styles.css的文件,其中任何 CSS 声明都会在 Sabaki 启动时被加载。

源码印证:路径如何被计算

上述路径并非文档凭空约定,而是主进程启动时确定的。见 src/setting.js:

exports.userDataDirectory = portableDir ? path.join(portableDir, 'Sabaki') : app.getPath('userData') // ... exports.stylesPath = path.join(exports.userDataDirectory, 'styles.css')

这里有两个值得注意的实现细节:

  1. 默认情况:app.getPath('userData')是 Electron API,返回的就是文档中列出的三个平台标准目录。
  2. 便携模式(可从源码看出的补充信息):当环境变量PORTABLE_EXECUTABLE_DIR存在时(即从压缩包直接运行的便携版构建),userDataDirectory会变为便携版根目录/Sabaki,styles.css也随之落在该目录内。也就是说,便携版用户的 userstyle 文件不在上述三个位置,而在便携版文件夹里的Sabaki/子目录中。

启动时自动创建 styles.css

src/setting.js 在模块加载阶段就检查并创建该文件:

if (!fs.existsSync(exports.stylesPath)) { fs.writeFileSync( exports.stylesPath, `/* This stylesheet is loaded when ${app.name} starts up. */`, ) }

因此即使你从未手动创建过它,第一次启动 Sabaki 后该文件就已经存在,内容是一条自述注释。你可以直接用任意文本编辑器打开它开始写 CSS。

渲染进程如何拿到 stylesPath

Electron 主进程与渲染进程之间的路径传递链路如下(均可在源码中验证):

  1. 主进程通过 IPC 同步接口暴露路径,见 src/main.js:
ipcMain.on('setting:getPathsSync', (e) => { try { e.returnValue = { themesDirectory: setting.themesDirectory, stylesPath: setting.stylesPath, userDataDirectory: setting.userDataDirectory, themes: setting.getThemes(), } } catch (err) { // 出错时回退为空字符串,避免渲染进程崩溃 } })
  1. 预加载脚本在渲染进程加载之前同步取回并缓存,见 src/preload.js:
let pathsCache try { pathsCache = ipcRenderer.sendSync('setting:getPathsSync') } catch (e) { pathsCache = { themesDirectory: '', stylesPath: '', /* ... */ } }

并在 src/preload.js 中挂到window.sabaki.setting上:stylesPath、themesDirectory、userDataDirectory三者一并暴露给渲染层。

CSS 的注入顺序与优先级

这是理解 userstyle 生效方式的关键。渲染入口 index.html 先加载三张内置样式表:

<link rel="stylesheet" type="text/css" href="./style/app.css" /> <link rel="stylesheet" type="text/css" href="./style/index.css" /> <link rel="stylesheet" type="text/css" href="./style/comments.css" />

之后,React(此处为 Preact)应用启动,src/components/App.js 挂载了ThemeManager组件。src/components/ThemeManager.js 的render按以下顺序插入<link>标签:

  1. 当前主题(theme)的样式表:currentTheme.main || 'styles.css',指向<themes 目录>/<主题名>/package.json中声明的主 CSS;
  2. 用户自定义样式:href: setting.stylesPath,即你编辑的那个styles.css。
// Theme stylesheet currentTheme != null && h('link', { rel: 'stylesheet', type: 'text/css', href: join(currentTheme.path, currentTheme.main || 'styles.css'), }), // ... // Userstyles h('link', { rel: 'stylesheet', type: 'text/css', href: setting.stylesPath, }),

由注入顺序可以推断出实际优先级:userstyle 始终排在主题样式之后(同源、同优先级时后声明者胜出),因此你可以用styles.css覆盖已安装主题的任意规则,而不必重新打包主题。反过来,主题的 CSS 也会覆盖内置的app.css等样式表。

主题本身的发现逻辑在 src/setting.js 的loadThemes:主进程扫描<userData>/themes目录(见 src/setting.js 中themesDirectory的定义),把每个子目录当作一个主题候选并读取其package.json;在 src/components/drawers/PreferencesDrawer.js 中,偏好设置页选择主题时使用的文件过滤器正是extensions: ['asar'],即安装主题 = 把一个.asar包放入themes目录。userstyle 与 theme 的关系可概括为:theme 是一个 userstyle 加资源文件的再分发打包格式,详见 Create Themes。

如何修改棋盘与棋子:Shudan 的选择器钩子

Sabaki 的棋盘 UI 并非自绘 DOM,而是复用了 Shudan 组件库。从源码看,棋盘组件直接引入自该库(src/components/Goban.js):

import {BoundedGoban} from '@sabaki/shudan'

Sabaki 自身在 src/components/ThemeManager.js 中给出的自定义图片样式就是典型的 Shudan 选择器用法,你可以把这些类名与 CSS 变量当作 userstyle 的主要攻击面:

/* 替换黑子/白子图片(sign_1 黑子、sign_-1 白子) */ .shudan-stone-image.shudan-sign_1 { background-image: url('...'); } .shudan-stone-image.shudan-sign_-1 { background-image: url('...'); } /* 棋盘图片 */ .shudan-goban-image { background-image: url('...'); } /* 相关 CSS 变量(Sabaki 在启用自定义图片时会自动写入) */ .shudan-goban { --shudan-board-background-color: ...; --shudan-black-background-color: ...; --shudan-white-foreground-color: ...; }

原文档建议:若要系统地了解如何更换 board/stone 图片,应阅读 Shudan 项目的 styling 文档(Shudan 是该组件的维护者仓库,可查阅其 Styling 章节)。此外,Sabaki 自身的通用样式(如字体、#busy遮罩、#main布局等)可以在 style/app.css 中查阅选择器与默认值,为你的 userstyle 提供参考——注意它是打包进应用的,你只应阅读它而不是修改它。

用开发者工具检查 DOM

原文档提示:排查选择器时,打开开发者工具查看 DOM 会有帮助。具体步骤参照仓库内的 Debugging 指南:

  1. 必要时先关闭 Sabaki;
  2. 打开上节所述的设置目录中的settings.json;
  3. 找到键debug.dev_tools(其默认值为false,可在 src/setting.js 的默认设置表中确认);
  4. 将其改为true并保存;
  5. 重新启动 Sabaki,主菜单会多出 'Developer' 项;
  6. 点击 'Toggle Developer Tools'。

在 Elements 面板中定位.shudan-goban、.shudan-stone-image等节点,在 Console/Styles 面板验证你的styles.css规则是否命中、是否被更高优先级的规则压制(例如是否需要!important或更具体的选择器)。

实战示例:一段可复用的 userstyle 骨架

将以下内容写入styles.css(路径见前文)并重启 Sabaki,可看到自定义生效。图片文件建议放在用户数据目录下的子目录中,CSS 中引用相对路径即可(渲染页从file://加载,绝对路径亦可):

/* 1. 更换棋盘纹理(图片与 sabaki 用户目录同级或任意可达位置) */ .shudan-goban-image { background-image: url('my-theme/board.png'); } /* 2. 更换黑白棋子纹理 */ .shudan-stone-image.shudan-sign_1 { background-image: url('my-theme/black.png'); } .shudan-stone-image.shudan-sign_-1 { background-image: url('my-theme/white.png'); } /* 3. 通过 Shudan 的 CSS 变量微调棋盘背景/前景色 */ .shudan-goban { --shudan-board-background-color: #e8c882; }

注意事项:

  • 需要重启生效:styles.css是以<link>静态注入的(见 ThemeManager 实现),Sabaki 启动时加载该文件,编辑后请重启应用验证;
  • 不要修改settings.json以外的程序内部文件:userstyle 的全部意义就在于只维护这一个 CSS 文件;
  • 版本兼容性:Sabaki 在不同大版本中调整过 DOM 结构,旧版主题/userstyle 的选择器可能失效——同仓库的 theme-directory.md 就明确指出,v0.40.0 对 DOM 结构做过变更,v0.30.x 时代的主题在 v0.40.0 及以后可能不再适用。升级 Sabaki 后若 userstyle 失效,优先用 DevTools 重新核对类名。

进阶:从 userstyle 到可分发的 theme

当你的 userstyle 稳定后,可以按 Create Themes 的流程把它和素材打包成.asar主题:目录内放styles.css与图片资源,另加一个仅含name、version、main等字段的package.json,用asar pack打包,即可在 Sabaki 偏好设置中安装并分发给他人。此时它会被 src/setting.js 的loadThemes扫描到,并由 src/components/ThemeManager.js 以main字段指定的样式表加载。

小结

  • styles.css位于各平台的 Sabaki 用户数据目录(Windows%APPDATA%\Sabaki、Linux~/.config/Sabaki、macOS~/Library/Application Support/Sabaki;便携版则位于便携目录下的Sabaki/子目录),由主进程在首次启动时自动创建(src/setting.js);
  • 它经 IPC 路径缓存传入渲染进程(src/main.js、src/preload.js),由 src/components/ThemeManager.js 以<link>形式注入,且位于主题样式之后,因而拥有最高的覆盖优先级;
  • 定制棋盘/棋子的核心是 Shudan 组件的选择器(.shudan-goban-image、.shudan-stone-image.shudan-sign_±1及一组--shudan-*CSS 变量),必要时按 Debugging 打开开发者工具核对 DOM;
  • 想分享给他人时,按 create-themes.md 用asar将 userstyle 打包为正式 theme 即可。
  • 桌面应用

【免费下载链接】Sabaki

An elegant Go board and SGF editor for a more civilized age.

项目地址:https://gitcode.com/gh_mirrors/sa/Sabaki
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询