字号阶梯收尾 + 主色补到 WCAG AA(新增 --tb-on-primary)
一号事项(剩余令牌化):
- templates/user/profile.html 20 处、base.css 9 处 font-size 全部落到 --tb-fs-*
- base.css 导航四档(0.95/0.88/0.82/0.78)合并成「桌面 md → ≤1000 xs」;logo 三档统一 lg
- 有理由保留的:.tb-pin-flag / .md-body code 的 0.9em(相对父级)、验证码 1.4/1.2rem(等宽字形)、
chat 关闭按钮 40px、password 页 3em、mail/*(邮件客户端不保证 var());行内 12px/0.75rem 等值顺手换掉
二号事项(主色对比度):
- base/default #1e87f0(3.42) → #0e6fd0(4.70);shiroko #4a7fc1(3.69) → #3b6dac(4.74);
sakura #e5678f(2.80) → #ba3e66(4.70,饱和度压到 .5 保持柔和)。同色相只压亮度,目标 4.7 留余量
- 深色块 muted 之前只对 --tb-bg 算(4.7 以为过了),对压平后的卡片其实 4.31/4.17 → 提到 #a18790 / #7f8ea1
- 新增 --tb-on-primary(亮 #ffffff / 暗 #0b1016):深色模式主色偏亮,白字只有 2.2~3.1:1,
用同一个令牌兼顾「链接色要深」和「按钮底要深」是矛盾的。.uk-button-primary 与
.uk-label:not(语义色) 改吃它 → 深色按钮变成浅底深字(6.10 / 8.65 / 7.27)
- 顺手封掉几处主色泄漏:header 验证码 focus、profile .feat-day.is-on、explore 随机投票的 JS outline、
vote-results 行内色,全部改成令牌(否则换主题时不跟着变)
生成器同步:paletteVars 导出 --tb-on-primary(白字/深字择优);?dump=palette 增加
onPrimaryCr / onPrimaryPickedBest / warnings —— 主色卡中间调时只警告不判失败;
配色面板给橙色提示。_scaffold 令牌 29 → 30。StaticVersion → 20261021c。
验证:TestSwatch 断言同步为 #ba3e66;8 种组合(base 亮暗 + 三主题亮暗)对比度全部 ≥4.5;
go test internal/{theme,templates,conf,i18n} 全绿;生成器 validate/fit/quality/palette/layers/fx/fxpipe 全过。
This commit is contained in:
@@ -685,6 +685,13 @@ function textBackdrops(p){
|
||||
return [p.bg, flatten(p.surface, p.bg)];
|
||||
}
|
||||
|
||||
/** 主色作背景时的文字色:白字和深字里挑对比度更高的那个。
|
||||
浅色模式主色深 → 白字;深色模式主色普遍偏亮(#5c8dff 之流),白字只有 2~3:1,
|
||||
必须换成深字。不写这个令牌就只能吃 base.css 的默认值,深浅两套必然错一套。 */
|
||||
function onPrimary(primary){
|
||||
return contrastRatio('#ffffff', primary) >= contrastRatio('#0b1016', primary) ? '#ffffff' : '#0b1016';
|
||||
}
|
||||
|
||||
function paletteVars(p){
|
||||
const back = textBackdrops(p);
|
||||
return [
|
||||
@@ -699,6 +706,7 @@ function paletteVars(p){
|
||||
` --tb-text-muted: ${mixToContrast(p.text, back, 4.5)};`,
|
||||
` --tb-primary: ${p.primary};`,
|
||||
` --tb-primary-weak: ${withAlpha(p.primary, 0.12)};`,
|
||||
` --tb-on-primary: ${onPrimary(p.primary)};`,
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
@@ -1610,6 +1618,19 @@ function renderPalette(){
|
||||
).join(' · ') + '<br>低于 4.5:1(WCAG AA 正文)会变橙。次要/淡文字由正文自动派生并保底。';
|
||||
wrap.appendChild(crL);
|
||||
|
||||
// 主色卡在中间调时,白字和深字都不到 4.5 —— 这不是文字色挑错,是主色本身要动。
|
||||
const bestOn = Math.max(contrastRatio('#ffffff', S.palette.primary),
|
||||
contrastRatio('#0b1016', S.palette.primary));
|
||||
if (bestOn < 4.5){
|
||||
const warn = document.createElement('p');
|
||||
warn.className = 'hint';
|
||||
warn.style.color = '#e0a33e';
|
||||
warn.textContent = `⚠ 主色偏中间调:白字 ${contrastRatio('#ffffff', S.palette.primary).toFixed(2)}:1、`
|
||||
+ `深字 ${contrastRatio('#0b1016', S.palette.primary).toFixed(2)}:1,按钮上的字都不够清楚。`
|
||||
+ '把主色压深一点(配白字)或提亮一点(配深字)就能过。';
|
||||
wrap.appendChild(warn);
|
||||
}
|
||||
|
||||
const note = document.createElement('p');
|
||||
note.className = 'hint';
|
||||
note.textContent = '深色配色写在生成结果里(深色不加载图片);要改深色请直接改 CSS。';
|
||||
@@ -3038,7 +3059,7 @@ function boot(){
|
||||
const r = { cases: {} };
|
||||
try {
|
||||
const cases = {
|
||||
'默认亮色': { bg:'#eef3f9', surface:'rgba(255,255,255,0.86)', navbar:'rgba(255,255,255,0.52)', text:'#222d3b', primary:'#4a7fc1', border:'#d6e0ec' },
|
||||
'默认亮色': { bg:'#eef3f9', surface:'rgba(255,255,255,0.86)', navbar:'rgba(255,255,255,0.52)', text:'#222d3b', primary:'#3d6fac', border:'#d6e0ec' },
|
||||
'默认深色': { bg:'#141a22', surface:'#1d2530', navbar:'#141a22', text:'#e3eaf4', primary:'#6fa3e0', border:'#334052' },
|
||||
// 极端:文字色本身就不达标 → 必须原样返回,不能继续往底色淡
|
||||
'低对比手填': { bg:'#f4f4f4', surface:'#ffffff', navbar:'#ffffff', text:'#c8ccd2', primary:'#dddddd', border:'#e5e5e5' },
|
||||
@@ -3046,6 +3067,7 @@ function boot(){
|
||||
'白卡彩底': { bg:'#f6d9e4', surface:'#ffffff', navbar:'#f6d9e4', text:'#3b2b33', primary:'#c2557d', border:'#efd3de' },
|
||||
};
|
||||
let allOk = true;
|
||||
const warns = [];
|
||||
for (const name in cases){
|
||||
const p = cases[name];
|
||||
const back = textBackdrops(p);
|
||||
@@ -3057,9 +3079,21 @@ function boot(){
|
||||
muted: +worst(mut).toFixed(2),
|
||||
rawText: +worst(p.text).toFixed(2),
|
||||
mutedDarkerThanSecondary: worst(mut) <= worst(sec), // 层级:淡文字必须比次要更淡
|
||||
// 主色作底的文字:白字 vs 深字里必须挑更优的那个。
|
||||
// 注意这里不断言「一定 ≥4.5」:主色卡在中间调时,两种文字色都不够,
|
||||
// 这不是挑错了,而是主色本身要调 —— 列进 warnings 提醒,不判失败。
|
||||
onPrimary: onPrimary(p.primary),
|
||||
onPrimaryCr: +contrastRatio(onPrimary(p.primary), p.primary).toFixed(2),
|
||||
onPrimaryPickedBest: Math.abs(
|
||||
contrastRatio(onPrimary(p.primary), p.primary) -
|
||||
Math.max(contrastRatio('#ffffff', p.primary), contrastRatio('#0b1016', p.primary))
|
||||
) < 0.01,
|
||||
// 关键断言:只要有 4.5 的空间就必须达标;本来就不达标的不算错
|
||||
ok: (worst(p.text) < 4.5) ? (mut === p.text) : (worst(mut) >= 4.5 && worst(sec) >= 4.5),
|
||||
ok: ((worst(p.text) < 4.5) ? (mut === p.text) : (worst(mut) >= 4.5 && worst(sec) >= 4.5))
|
||||
&& Math.abs(contrastRatio(onPrimary(p.primary), p.primary) -
|
||||
Math.max(contrastRatio('#ffffff', p.primary), contrastRatio('#0b1016', p.primary))) < 0.01,
|
||||
};
|
||||
if (row.onPrimaryCr < 4.5) warns.push(name + '(主色 ' + p.primary + ' 中间调,白字/深字都不到 4.5)');
|
||||
// 卡片半透明时必须按压平后的颜色算,否则白卡 86% 会被当成 #fff
|
||||
row.surfaceFlat = flatten(p.surface, p.bg);
|
||||
r.cases[name] = row;
|
||||
@@ -3069,6 +3103,14 @@ function boot(){
|
||||
for (const name in r.cases){
|
||||
if (!r.cases[name].mutedDarkerThanSecondary) allOk = false;
|
||||
}
|
||||
// demo 的两套配色也要过:导出后的 CSS 直接吃这两个值
|
||||
r.demoLight = { primary: S.palette.primary, on: onPrimary(S.palette.primary),
|
||||
cr: +contrastRatio(onPrimary(S.palette.primary), S.palette.primary).toFixed(2) };
|
||||
r.demoDark = { primary: S.dark.primary, on: onPrimary(S.dark.primary),
|
||||
cr: +contrastRatio(onPrimary(S.dark.primary), S.dark.primary).toFixed(2) };
|
||||
if (r.demoLight.cr < 4.5) warns.push('demo 亮色(可改 palette.primary)');
|
||||
if (r.demoDark.cr < 4.5) warns.push('demo 深色(可改 dark.primary)');
|
||||
r.warnings = warns;
|
||||
// 把生成结果里的派生值也打出来,方便和 base.css 的取值对照
|
||||
const css = buildCSS(false);
|
||||
r.mutedLine = (css.match(/--tb-text-muted:[^;]+;/) || [''])[0];
|
||||
|
||||
Reference in New Issue
Block a user