作品外观

theme.css 与可视化编辑器、四套内置主题、作品自带的 CSS 与字体,以及正文里的 font 与 class 标签。

Kiny 作品最终渲染成网页,所以外观就是 CSS。.css 或字体文件放进项目就生效——不需要在任何地方声明。

换外观分两级:改一组变量,或者直接写选择器。

第一级:改 theme.css 里的变量

新建项目自带一个 theme.css(项目根),改它就换掉整个阅读页的外观:

.player {
  --kiny-page-bg: #14110e;
  --kiny-text: #efe6d8;
  --kiny-prose-font: "楷体", serif;
  --kiny-content-max-width: 720px;
}

在编辑器里点开 theme.css,看到的是一个可视化编辑器——配色、字体、字号行高、阅读栏宽直接拖着调,改完预览立刻换肤。想手写 CSS 就切到「原文」页,同一个文件两个视图。调整只改动对应的那几个值,你写的注释与自定义样式原样保留。

已有的老项目在编辑器里新建一个名为 theme.css 的文件,就得到同一份模板;另建的其它 .css 只给一个注释空壳,用来写选择器。

可改的变量

变量 含义 默认值
--kiny-page-bg 页面底色 #0d1117
--kiny-text 正文文字色 #e8e8e8
--kiny-prose-font 正文字体族 system-ui, "Noto Sans SC", sans-serif
--kiny-prose-size 正文字号 1.05rem
--kiny-prose-line-height 行高 1.9
--kiny-content-max-width 阅读栏宽 680px
--kiny-bg-overlay 氛围底图的压暗遮罩(没设底图时不生效) rgba(10, 14, 20, .55)
--kiny-control-bg 选项按钮 / 输入框底色 rgba(255, 255, 255, .06)
--kiny-control-bg-hover 同上,悬停态 rgba(255, 255, 255, .14)
--kiny-control-text 控件文字色 #fff
--kiny-control-border 控件描边色 rgba(255, 255, 255, .35)
--kiny-accent 强调色(推进提示等) rgba(255, 255, 255, .8)
--kiny-error 错误文字色 #ff8585
--kiny-panel-bg 固定区域底色 transparent(不遮氛围底图)
--kiny-panel-text 固定区域文字色 由正文色降一档推导
--kiny-panel-border 固定区域发丝线色 由正文色推导

赋值即生效,不需要了解阅读页的 DOM 结构。

.player 为根写,不要用 :root 声明直接落在阅读区元素本身,优先于从根元素继承下来的宿主(阅读器 / 网页书库 / 编辑器)皮肤取值;而且不会漏到编辑器界面上。

默认值就是播放层的原生外观。各个宿主会先用自己的皮肤覆盖同名变量,作品的 CSS 再覆盖之——作品说了算

变量赋值集中在一个文件里

同一个变量在多个 .css 里都赋值时,路径字典序靠后的那个生效——分散着写很容易互相盖掉。所以 token 赋值都放 theme.css,另建的 .css 只写选择器。

内置主题

编辑器里备了四套:石墨夜暖纸午夜蓝素白。一键换整体风格,换完就是往 theme.css 里写了一组值——之后照样可以接着微调。

第二级:直接写选择器

作品 CSS 不限属性、不限选择器:媒体查询、伪类、动画都能用。

几个稳定的钩子:

选择器 对应
.panel-left / .panel-right / .panel-bottom / .panel-after @panel 的四个固定区域
.kin-illustration @img 插图(每张都带)
.kin-divider @divider 分割线(每条都带)
.kin-<名> 正文里 <class=名> 挂的类(渲染时加 kin- 前缀)
.player .panel-bottom { background: rgba(0, 0, 0, .3); }
.player .kin-illustration { border-radius: 8px; }
.player .kin-whisper { opacity: .7; font-style: italic; }

务必带 .player 前缀。 不带会漏到宿主界面上,编辑器预览里尤其明显。

项目里的 CSS 与字体

.css:项目内任意位置.css 都会自动加载,按路径字典序注入。需要控制先后就用 10- / 20- 文件名前缀;不想让某个文件生效,把扩展名改掉(如 skin.css.bak)。

字体文件.woff2 / .woff / .ttf / .otf):自动注册 @font-face族名 = 文件名去掉扩展名。把 楷体.woff2 丢进项目任意位置,直接就能用:

.player { --kiny-prose-font: "楷体", serif; }
信纸上写着:<font=楷体>见字如晤。</font>

不需要写 @font-face。一个文件一个族;族名非法(含 ; ( ) " ' 等)会被忽略;同名族按路径序后者覆盖。

发现规则:跳过以 . 开头的路径段与 node_modules。图片、音频不参与自动加载——被 CSS 的 url()演出命令引用即可。CSS 里的相对 url()该 CSS 文件所在目录为基准解析。

只有 .css 与字体自动加载。 .js / .json / .md / .txt / .html 同样能放在项目里、也能在编辑器里编辑,但不参与自动加载——尤其 .js 不会被执行

正文里的两个钩子

正文写作里讲过的两个标签,是把样式从正文交给样式表的正规方式:

  • <font=名> —— 换字体族。族名是项目里自动注册的字体,或系统字体名。找不到就回退到正文默认字体,不影响阅读。
  • <class=名> —— 挂一个语义类,渲染时加 kin- 前缀,交给作品 CSS 定义。嵌套的 <class> 累积生效(外层 letter + 内层 old 同时挂上)。类名覆盖整行时挂到行容器上(背景、边框、内边距这类块级样式完整可用),只包片段时挂在那个片段上。
<class=letter>信纸上写着:<class=old>见字如晤。</class></class>
.player .kin-letter { background: #f5efe0; padding: 12px 16px; }
.player .kin-old { font-family: "楷体", serif; opacity: .85; }

行内标签的取值受限、作品 CSS 完全开放,这是两件事。 行内标签是正文里的标记,取值经严格校验以杜绝经正文注入样式;作品 CSS 是你自己的样式表,任意属性与选择器都能写。<class=名> 正是把样式钩子从正文交给样式表的那道门。

到处都一样

外观随作品分发,在所有播放的地方生效:编辑器预览、桌面阅读器、网页书库、导出的独立网页。你在预览里看到的,就是读者看到的。

接下来

语言部分到这里就全了。往下是「用编辑器」与「发布与阅读」两部分——怎么写得更顺手,以及怎么把作品交到读者手里。