跳到主要内容

主题Theming

主题不是一份配置对象,而是 <html> 上的三个属性:data-theme、data-accent、data-motion。所有组件的样式都从它们派生;OinkProvider 负责读写,useOink() 负责在组件里拿到当前值和切换方法。

深色与浅色

setTheme 的第二个参数是视口坐标。传了它,新主题会从这一点以圆形揭开(用的是 View Transitions;浏览器不支持、或者开了减弱动效时直接切换)。

theme = system,resolvedTheme = light

theme 是用户选的(可以是 'system'),resolvedTheme 是实际生效的 'light' 或 'dark'。判断“现在是不是深色”用后者。

强调色

五种预设:pink、orange、amber、blue、violet,也可以是任意颜色。柔和底、填充、悬停色、文字色都由 color-mix() 从这一个颜色派生,深浅两套主题各有一组配比。

accent = pink

自定义颜色。setAccent('#3fa7c4') 或 defaultAccent="#3fa7c4":<html> 上是 data-accent="custom",颜色和几个派生变量写在它的行内样式上。强调色上的文字按颜色的感知亮度自动选墨色或白色;当文字用的深一档(浅色主题,对白底至少 4.5:1)和亮一档(深色主题)也自动算出来。工具函数 accentVars(hex)、onAccentColor(hex) 可以单独用。挑颜色可以用 ColorPicker。

局部换色

派生色是在声明 data-accent 的那个元素上求值的,所以可以只给页面的一块换强调色。

局部强调色

动效偏好与 --ok-ms

所有时长令牌都乘了全局倍率 --ok-ms。系统开了“减弱动态效果”,或者 data-motion 为 reduced 时,它变成 0:位移归零,只保留状态切换。

--ok-ms = 1
  • auto:跟随系统设置(默认)。
  • full:即使系统要求减弱,也保留完整动效。只在用户自己明确选择时用。
  • reduced:强制减弱。

自己写的过渡用 var(--ok-dur-*),脚本动画用 animate(),就会自动跟着这个倍率走,不需要单独判断。减弱之后各种动效实际是什么样子,见 动效 · 减弱动效。也可以把 --ok-ms 设成别的数来整体放慢或加快,比如调试时设成 4。

圆角系数

容器的圆角用连续曲率的超椭圆曲线。同样的半径下超椭圆显得更方,所以配了一个半径倍率 --ok-rk 把视觉大小拉回来。

r-2
r-4
r-5
这个浏览器不支持 corner-shape:曲线回退为普通圆角,这里只能看到半径倍率的变化。切换会临时改写整页的 --ok-corner / --ok-rk,离开本页后恢复。
css
/* 默认:支持 corner-shape 的浏览器自动用超椭圆,并把半径放大 1.45 倍来保持视觉大小 */
@supports (corner-shape: squircle) {
  :root { --ok-corner: superellipse(1.75); --ok-rk: 1.45; }
}

/* 想在所有浏览器里都用普通圆角:覆盖回去 */
:root { --ok-corner: round; --ok-rk: 1; }

--ok-r-1 到 --ok-r-6 是在 :root 上用 calc(Npx * var(--ok-rk)) 算好的,所以要改倍率得在 :root 上改,写在子元素上不起作用。全圆(--ok-r-full)不受影响,始终是正圆。圆角刻度和同心圆角的规矩见 形状 · 间距 · 层级。

触屏高度

控件高度只有三档:32 / 40 / 48。触屏设备(pointer: coarse)上自动抬到 36 / 44 / 52,保证点按区域不小于 44px,输入框字号同时变成 16px;列表项(--ok-h-item)也抬到 44。各档令牌见“形状 · 间距 · 层级”。

API

OinkProvider

属性类型默认值说明
defaultTheme'light' | 'dark' | 'system''system'初始主题。
defaultAccentAccentPreset | '#rrggbb''pink'初始强调色:五种预设之一,或任意颜色。
defaultMotion'auto' | 'full' | 'reduced''auto'初始动效偏好。
storageKeystring—传了就把三项选择记到 localStorage 的这个键下。
tailReactNode | ((props: { className: string }) => ReactNode)—全局替换加载器和按钮加载状态里的尾巴图案,等于在最外层包一个 TailProvider。见下面“替换尾巴图案”。

useOink() 的返回值

属性类型默认值说明
themeThemeMode—用户选的主题,可能是 system。
resolvedTheme'light' | 'dark'—实际生效的主题。
accentAccent—当前强调色。
motionMotionMode—当前动效偏好。
setTheme(theme, origin?: { x, y }) => void—切换主题;传 origin(视口坐标)时从该点圆形揭开。
setAccent(accent: Accent) => void—切换强调色。
setMotion(motion: MotionMode) => void—切换动效偏好。

替换尾巴图案

品牌尾巴是加载与提示里用的图形:Spinner 的 tail 变体、Button 的加载状态都画它。它是默认值,但可以整体换掉:给 OinkProvider 传 tail,或者用 TailProvider 包住应用,就是全局替换;TailProvider 包住一块就只换那一块,可以嵌套,内层优先。

加载中加载中加载中
只有上面这一块被 TailProvider 包住,页面别处的加载器不受影响。

替换图案约定是一个 viewBox="0 0 48 48" 的 svg。它会拿到和默认尾巴一样的类名 ok-tail,于是:

  • 整体的摆动 / 旋转、尺寸、颜色(currentColor)自动跟上;
  • 带 pathLength="1" 的路径或图形会做描线动效;没有的只做摆动;
  • 没写 fill / stroke 属性的图形默认按尾巴的笔触描线(圆头,线宽 5.5);自己写了的保留。

组件里需要画尾巴时用 <TailGlyph className="ok-tail" />,它会读到最近的 TailProvider;useTail() 返回当前生效的替换图案(默认时为 undefined)。

TailProvider

属性类型默认值说明
tailReactNode | ((props: { className: string }) => ReactNode)—替换的图案。传节点时把 className 合并到它的根元素上并对读屏隐藏;传函数时自己处理。不传时沿用外层设置。