版本号 3.2.8 -> 3.2.9(邮件版式重做:白底 + 深色头部 + 暖色点缀)
用户对 3.2.8 的"整封同色系"给出了明确否定,并说明要什么: 背景要白的;顶部深蓝底白字;「新回复」标签不能用蓝色, 要黄或红、与头部有区分度;「查看完整讨论」按钮红底白字。 版式骨架改成了「白底 + 深头 + 暖色点缀」: - page_bg 由主色浅底改为纯白; - 头部改为主色的深版(deepen_to 压到白字 7:1),白字达 AAA; - 标签用暖色族,具体哪个由"与头部色相距离"挑(pick_warm), 主色偏红时金黄才撞得开; - 按钮固定红 #c62828 + 白字(5.62:1); - 新回复竖线改用同一套暖色,与标签呼应。 顺带修掉两个真 bug: - 标题色的循环从最暗档开始扫,实际取到的是最暗档(亮蓝下几乎全黑), 注释还写着"取最亮的达标档",方向与实现相反。改为从 0.90 往下扫, 并加色度下限(不低于种子 70%),避免浅主色被压成黑色; - 纯中性灰主色下 21px 标题取到 #717171 中灰,发虚。改为深墨色。 测试同步重写(旧判据服务的是"整封同色系",在白底版式下必红): - mail_color_audit.py 改为守四条性质:白底、头部深且白字达标、 标签暖色且撞开、按钮红底白字;定位靠结构不靠猜颜色; - pixel_color_audit.py 改为像素级守同一组性质:白像素 ≥45%、 顶部横跨的深色带、带内白字像素、带内撞色像素; 撞色必须判「带内」(判全图会把底部红按钮算进来,没牙齿); - falsify_color.py 四处注入全部退回旧做法,两层都能抓住; - run_tests/run_tests2/visual_audit/mail_design_audit/mail_shot 里 写死 #24292e 或"按钮跟主色"的过期断言一并改成本质性质。 verify_all.sh 14 组 / 463 条断言全绿(上一轮 320 条)。
This commit is contained in:
+264
-48
@@ -84,6 +84,11 @@ function yang_mail_shade($hex, $ratio = 0.82)
|
|||||||
* 交叉点附近,白字 3.95、深字 4.41 —— 两个都不到 4.5,但必须选一个。
|
* 交叉点附近,白字 3.95、深字 4.41 —— 两个都不到 4.5,但必须选一个。
|
||||||
* 所以配字时不要直接用它,用 yang_mail_fg_on():那里是"黑白里取更优",
|
* 所以配字时不要直接用它,用 yang_mail_fg_on():那里是"黑白里取更优",
|
||||||
* 顺带在都不达标时退回纯黑/纯白,能多榨出一两档。
|
* 顺带在都不达标时退回纯黑/纯白,能多榨出一两档。
|
||||||
|
*
|
||||||
|
* ⚠️ 本函数目前**没有生产调用点**(配字一律走 fg_on,配色档位一律走
|
||||||
|
* deepen_to)。保留它是为了给调用方一个便宜的"这是深色吗"判断,
|
||||||
|
* 以及 run_tests 里那三条亮度分类断言。别在配字场景重新启用它 ——
|
||||||
|
* 那正是 2.76:1 那个 bug 的来源。
|
||||||
*/
|
*/
|
||||||
function yang_mail_is_dark($hex)
|
function yang_mail_is_dark($hex)
|
||||||
{
|
{
|
||||||
@@ -277,7 +282,134 @@ function yang_mail_hsl_hex($h, $s, $l)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成整封邮件用的配色表(全部从主色派生,同色系)
|
* 取颜色的 HSL 饱和度
|
||||||
|
*
|
||||||
|
* 色度(通道极差)= S × (1 - |2L-1|),这里就是它的反解。
|
||||||
|
* 单独拿出来是因为「按亮度重设颜色」时必须保住原来的饱和度 ——
|
||||||
|
* 否则一个鲜艳的蓝压暗后会变成中性灰,头部就成了「深灰条」而不是「深蓝」。
|
||||||
|
*/
|
||||||
|
function yang_mail_hsl_s($hex)
|
||||||
|
{
|
||||||
|
list(, $l) = yang_mail_hsl($hex);
|
||||||
|
$den = 1 - abs(2 * $l - 1);
|
||||||
|
if ($den < 1e-6) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return min(1.0, yang_mail_chroma($hex) / $den);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 沿自身色相与饱和度,把颜色放到指定的 HSL 亮度上
|
||||||
|
*
|
||||||
|
* 用途:头部品牌条要「足够深、但不至于近黑」。只改亮度,
|
||||||
|
* 色相和饱和度是主色的原班底子,所以它仍认得出是哪个品牌色。
|
||||||
|
*/
|
||||||
|
function yang_mail_at_lightness($hex, $l)
|
||||||
|
{
|
||||||
|
list($h, ) = yang_mail_hsl($hex);
|
||||||
|
return yang_mail_hsl_hex($h, yang_mail_hsl_s($hex), max(0.0, min(1.0, (float) $l)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把颜色压深,直到叠在上面的文字达到目标对比度
|
||||||
|
*
|
||||||
|
* ── 为什么不是「取一个固定深色」────────────────────────────────
|
||||||
|
* 主色是用户填的,可能是亮蓝、亮绿、浅黄。同一个固定深色放在这些主色上
|
||||||
|
* 都不「属于」它们,品牌识别就没了。这里只沿它**自己的色相**往下压亮度,
|
||||||
|
* 压到「刚好够文字清楚」就停 —— 保住色相,也不会一路压成近黑。
|
||||||
|
*/
|
||||||
|
function yang_mail_deepen_to($hex, $target = 4.5, $fg = '#ffffff')
|
||||||
|
{
|
||||||
|
list($h, $l) = yang_mail_hsl($hex);
|
||||||
|
$s = yang_mail_hsl_s($hex);
|
||||||
|
for ($t = $l; $t >= 0.04; $t -= 0.01) {
|
||||||
|
$c = yang_mail_hsl_hex($h, $s, $t);
|
||||||
|
if (yang_mail_contrast($fg, $c) >= $target) {
|
||||||
|
return $c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return yang_mail_hsl_hex($h, $s, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 两个颜色的色相距离(0 = 同色相,0.5 = 正互补)
|
||||||
|
*
|
||||||
|
* 判「撞色够不够」必须用它,不能比较具体色值 —— 色值是用户主色的函数,
|
||||||
|
* 写死任何一个都会在主色变化时假红。
|
||||||
|
*/
|
||||||
|
function yang_mail_hue_dist($a, $b)
|
||||||
|
{
|
||||||
|
list($ha, ) = yang_mail_hsl($a);
|
||||||
|
list($hb, ) = yang_mail_hsl($b);
|
||||||
|
$d = abs($ha - $hb);
|
||||||
|
return $d > 0.5 ? 1 - $d : $d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暖色判定(红 / 橙 / 黄)
|
||||||
|
*
|
||||||
|
* 用户对「新回复」标签的要求是「不能用蓝色了,用黄色或者红色」。
|
||||||
|
* 判据直接写成语义:色相落在 -30°~75° 之外就是偏绿/偏蓝了,
|
||||||
|
* 换算成圈是 [0.917, 1] ∪ [0, 0.208]。绿色 #27ae60(h≈0.42)、
|
||||||
|
* 蓝色 #00a2ff(h≈0.56)都不在区间内。
|
||||||
|
*/
|
||||||
|
function yang_mail_is_warm($hex)
|
||||||
|
{
|
||||||
|
list($h, ) = yang_mail_hsl($hex);
|
||||||
|
return $h >= 0.917 || $h <= 0.208;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从暖色候选里挑「与头部拉开足够距离」的那个
|
||||||
|
*
|
||||||
|
* 用户的要求有两句:「标签不能再用蓝色,用黄或红」「要和背景有区分度」。
|
||||||
|
* 第一句决定了只能是暖色族,第二句决定了**不能固定一个色号**:
|
||||||
|
* 品牌色本身偏红时(#e74c3c 压深成 #a82315),一个红按钮与它只差 6°,
|
||||||
|
* 贴在深红头部下方等于"看不见的撞色"。
|
||||||
|
*
|
||||||
|
* ── 判据 ────────────────────────────────────────────────────
|
||||||
|
* 按候选顺序取**第一个色相距离 ≥ 0.10(36°)**的。
|
||||||
|
* 头部本身就是暖色、暖色族里挑不出更远的那个时,取距离最大的 ——
|
||||||
|
* 此时靠**亮度差**拉开层次(深色头部 L≈0.10 上的金黄 L 很高)。
|
||||||
|
* 候选顺序把金黄放第一:与冷色头部撞得最开,压黑字对比度也最高(14.5:1),
|
||||||
|
* 最符合用户说的「更醒目」。
|
||||||
|
*
|
||||||
|
* @param string $headerBg 头部底色
|
||||||
|
* @param array $cands 暖色候选,顺序即优先级
|
||||||
|
*/
|
||||||
|
function yang_mail_pick_warm($headerBg, $cands)
|
||||||
|
{
|
||||||
|
$best = $cands[0];
|
||||||
|
$bestD = -1;
|
||||||
|
foreach ($cands as $c) {
|
||||||
|
$d = yang_mail_hue_dist($c, $headerBg);
|
||||||
|
if ($d >= 0.10) {
|
||||||
|
return $c;
|
||||||
|
}
|
||||||
|
if ($d > $bestD) {
|
||||||
|
$bestD = $d;
|
||||||
|
$best = $c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $best;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成整封邮件用的配色表
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成整封邮件用的配色表
|
||||||
|
*
|
||||||
|
* ── 版式骨架(用户指定的审美,别再自己发挥)──────────────────
|
||||||
|
* · 外层背景**白色**。不是整片浅色底 —— 那样一眼看上去是「一张彩色纸」,
|
||||||
|
* 而不是「纸上一张卡片」。
|
||||||
|
* · 顶部品牌条**深色底 + 白字**。深色从主色压下来,色相仍是主色。
|
||||||
|
* · 「新回复」标签**暖色(黄/红)**,与冷色头部撞开。
|
||||||
|
* 早先它的底色是主色提亮一档 —— 与头部同色系,远看糊成一片,
|
||||||
|
* 用户的原话是「和背景蓝色没区分度」。
|
||||||
|
* · CTA 按钮**红底白字**,同样与头部撞开。
|
||||||
|
* 结论:这封邮件的色彩逻辑是「**白底 + 深头 + 暖色点缀**」,
|
||||||
|
* 而不是上一版那样「整封同色系」。
|
||||||
*
|
*
|
||||||
* ── 为什么整封邮件不能是灰的 ──────────────────────────────────
|
* ── 为什么整封邮件不能是灰的 ──────────────────────────────────
|
||||||
* 早先模板里只有品牌条、徽标、按钮、最后一块引用块的竖线用主色,
|
* 早先模板里只有品牌条、徽标、按钮、最后一块引用块的竖线用主色,
|
||||||
@@ -322,12 +454,47 @@ function yang_mail_palette($brand = null)
|
|||||||
* 零色相的纯灰宁可保持灰,也不要凭空编一个色相。 */
|
* 零色相的纯灰宁可保持灰,也不要凭空编一个色相。 */
|
||||||
$seed = yang_mail_has_hue($brand) ? yang_mail_ensure_chroma($brand, 0.30) : $brand;
|
$seed = yang_mail_has_hue($brand) ? yang_mail_ensure_chroma($brand, 0.30) : $brand;
|
||||||
|
|
||||||
$onBrand = yang_mail_fg_on($brand);
|
/* ── 头部:深色底 + 白字 ────────────────────────────────────
|
||||||
|
* 直接拿主色当头部底色在两种情况会翻:主色本身很亮(亮蓝/亮黄)时
|
||||||
|
* 白字看不清;主色本身很深时与正文的深色文字层次不分。
|
||||||
|
*
|
||||||
|
* ── 为什么压到 7:1 而不是只压到 AA 4.5 ────────────────────
|
||||||
|
* 只压到刚好 4.5 会得到一个「界限色」:亮蓝 #00a2ff 压出来是
|
||||||
|
* #007bc2,白字 4.55:1 —— 合规,但它是个中蓝,肉眼既不"深"也不"亮",
|
||||||
|
* 用户说的「深蓝色的背景」根本看不出来。压到 7:1 才真的落进深色区
|
||||||
|
* (#007bc2 的 L=0.181 恰好卡在 0.179 的深浅分界线上,这也是它
|
||||||
|
* 看着不深的原因)。白字 7:1 同时是 AAA 级正文标准,留有余量。
|
||||||
|
* 色相与饱和度仍是主色的原班底子,所以它认得出是哪个品牌色的深版。 */
|
||||||
|
$headerBg = yang_mail_deepen_to($seed, 7.0, '#ffffff');
|
||||||
|
$headerFg = yang_mail_fg_on($headerBg);
|
||||||
|
$headerDark = yang_mail_shade($headerBg, 0.80); // 下沿 3px 深色带
|
||||||
|
|
||||||
/* 浅底:混合后按自身亮度再补一次色度。
|
/* ── 强调色:暖色,与头部撞开 ───────────────────────────────
|
||||||
* 极浅底(ratio 0.94)本身亮度很高,能容纳的色度有限,
|
* 用户要求「标签不能用蓝色,要黄或红」。但从主色反推一个暖色是编造:
|
||||||
* 所以下限分两档 —— 用同一个值会让极浅底被迫变深、不再是"浅底"。
|
* 主色是 #27ae60(绿)时,把色相掰到红就等于替用户改了配色。
|
||||||
* 主色零色相时不补:那套灰是事实,硬染就是编造。 */
|
* 所以强调色用**语义固定**的暖色族,具体哪一个由「与头部的色相距离」
|
||||||
|
* 决定(见 yang_mail_pick_warm)—— 主色偏红时第一个候选贴上了,
|
||||||
|
* 就往暖色族里更远的那个退。
|
||||||
|
*
|
||||||
|
* 文字色走 fg_on():金黄 #ffd21f(L 高)压黑字 14.5:1,压白字只有 1.5:1。
|
||||||
|
* 这类"中亮度暖色"正是二元阈值最容易判错的地方。 */
|
||||||
|
$accent = yang_mail_pick_warm($headerBg, array('#ffd21f', '#f2a00b', '#e53935'));
|
||||||
|
$accentFg = yang_mail_fg_on($accent);
|
||||||
|
$accentBd = yang_mail_shade($accent, 0.86);
|
||||||
|
|
||||||
|
/* 按钮:用户明确要「红底白字」,就用红。
|
||||||
|
* 为什么不也按"与头部撞色"去挑:按钮在卡片最下方,中间隔着整段正文,
|
||||||
|
* 视觉上不与头部相邻 —— 用户说的「区分度」针对的是**贴在头部里面**的
|
||||||
|
* 标签。为它再引入一套撞色规则,只会在红主色站点上把按钮挑成橙色,
|
||||||
|
* 与「红白色的文字」这个明确指令冲突。
|
||||||
|
* 白字走 fg_on():#c62828 上 5.62:1,达 AA。 */
|
||||||
|
$ctaBg = '#c62828';
|
||||||
|
$ctaFg = yang_mail_fg_on($ctaBg);
|
||||||
|
|
||||||
|
/* ── 浅底色 ────────────────────────────────────────────────
|
||||||
|
* 外层背景必须是白(用户明确要求),卡片本身也是白;
|
||||||
|
* 浅底只留给「引用块」和「页脚」——没有它们,白底上全是散落的字,
|
||||||
|
* 分不出哪段是别人说的话。 */
|
||||||
$keep = yang_mail_has_hue($brand);
|
$keep = yang_mail_has_hue($brand);
|
||||||
$tintXX = $keep ? yang_mail_ensure_chroma(yang_mail_tint($seed, 0.94), 0.045)
|
$tintXX = $keep ? yang_mail_ensure_chroma(yang_mail_tint($seed, 0.94), 0.045)
|
||||||
: yang_mail_tint($seed, 0.94);
|
: yang_mail_tint($seed, 0.94);
|
||||||
@@ -337,47 +504,73 @@ function yang_mail_palette($brand = null)
|
|||||||
: yang_mail_tint($seed, 0.80);
|
: yang_mail_tint($seed, 0.80);
|
||||||
$tintMid = $keep ? yang_mail_ensure_chroma(yang_mail_tint($seed, 0.55), 0.220)
|
$tintMid = $keep ? yang_mail_ensure_chroma(yang_mail_tint($seed, 0.55), 0.220)
|
||||||
: yang_mail_tint($seed, 0.55);
|
: yang_mail_tint($seed, 0.55);
|
||||||
$pageBg = $keep ? yang_mail_ensure_chroma(yang_mail_tint($seed, 0.90), 0.065)
|
|
||||||
: yang_mail_tint($seed, 0.90);
|
|
||||||
|
|
||||||
/* 强调文字色:从种子一路压暗,取第一个"在白底和极浅底上都 ≥4.5"的档位。
|
/* 强调文字色:要「主色的深版」,不能直接拿主色当文字色 ——
|
||||||
* 不能直接拿主色当文字色 —— 亮蓝 #00a2ff 在白底只有 2.76:1。
|
* 亮蓝 #00a2ff 在白底只有 2.76:1。
|
||||||
* 也不能无脑取很深,那样就看不出是"主色的深版"了,所以要取**最亮的达标档**。 */
|
*
|
||||||
$textOnTint = $seed;
|
* ── 循环方向 ──────────────────────────────────────────────
|
||||||
for ($s = 0.20; $s <= 0.90; $s += 0.02) {
|
* shade() 是**按比例乘通道值**,所以 ratio 越小越暗。
|
||||||
|
* 从 0.90(最亮)往下扫到 0.20(最暗),取**第一个**达标的,
|
||||||
|
* 得到的是「最亮的达标档」:仍看得出属于主色,又刚够清楚。
|
||||||
|
* 反过来从 0.20 往上扫会取到最暗档 —— 亮蓝压成 #002033,标题看着是黑的。
|
||||||
|
*
|
||||||
|
* ── 为什么还要卡色度 ──────────────────────────────────────
|
||||||
|
* 只卡对比度时,主色很浅(如 #ffd21f 亮黄)会一路压到几乎发黑才达标,
|
||||||
|
* 那就不是"主色的深版"而是"黑色"了。要求色度不低于种子的 70%,
|
||||||
|
* 保证它还能被认出是同色系(浅主色达不到时退到最接近的那档)。 */
|
||||||
|
$seedC = yang_mail_chroma($seed);
|
||||||
|
$textOnTint = yang_mail_shade($seed, 0.90);
|
||||||
|
for ($s = 0.90; $s >= 0.20; $s -= 0.02) {
|
||||||
$c = yang_mail_shade($seed, $s);
|
$c = yang_mail_shade($seed, $s);
|
||||||
if (yang_mail_contrast($c, '#ffffff') >= 4.5
|
if (yang_mail_contrast($c, '#ffffff') >= 4.5
|
||||||
&& yang_mail_contrast($c, $tintXX) >= 4.5) {
|
&& yang_mail_contrast($c, $tintXX) >= 4.5
|
||||||
|
&& yang_mail_chroma($c) >= $seedC * 0.70) {
|
||||||
$textOnTint = $c;
|
$textOnTint = $c;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* 主色本身没有色相(纯灰)时,上面那条色度条件退化成恒真,
|
||||||
|
* 于是会选到 #717171 这种"最亮的中灰"当 21px 标题 —— 合规但看着发虚。
|
||||||
|
* 中性主色本来就没有"深版"可言,直接给一个真正的深墨色,
|
||||||
|
* 层次反而清楚(与正文 #243040 同为深色,靠字号/字重区分)。 */
|
||||||
|
if (!$keep) {
|
||||||
|
$textOnTint = '#1a1a1a';
|
||||||
|
}
|
||||||
|
|
||||||
/* 次要文字色:原来是固定的 #5c6b7a,但页脚底色改成了主色浅底之后,
|
/* 次要文字色:原来是固定的 #5c6b7a,但页脚底色改成了主色浅底之后,
|
||||||
* 这个固定值在浅蓝上只有 4.26:1 —— 12px 小字不达 AA。
|
* 这个固定值在浅蓝上只有 4.26:1 —— 12px 小字不达 AA。
|
||||||
* 「文字色写死、背景色随主色变」这个组合本身就是错的:背景一变浅,
|
* 「文字色写死、背景色随主色变」这个组合本身就是错的:背景一变浅,
|
||||||
* 固定灰就压不住。所以改成从基准灰往下压,压到在**它实际会遇到的
|
* 固定灰就压不住。所以改成从基准灰往下压,压到在**它实际会遇到的
|
||||||
* 两种背景**(页脚浅底、邮件最外层)上都达标为止。 */
|
* 三种背景**(页脚浅底、引用块浅底、白卡片)上都达标为止。 */
|
||||||
$muted = '#5c6b7a';
|
$muted = '#5c6b7a';
|
||||||
for ($t = 1.0; $t >= 0.55; $t -= 0.02) {
|
for ($t = 1.0; $t >= 0.55; $t -= 0.02) {
|
||||||
$cand = $t >= 0.999 ? $muted : yang_mail_shade($muted, $t);
|
$cand = $t >= 0.999 ? $muted : yang_mail_shade($muted, $t);
|
||||||
if (yang_mail_contrast($cand, $tintX) >= 4.5
|
if (yang_mail_contrast($cand, $tintX) >= 4.5
|
||||||
&& yang_mail_contrast($cand, $pageBg) >= 4.5) {
|
&& yang_mail_contrast($cand, $tintXX) >= 4.5
|
||||||
|
&& yang_mail_contrast($cand, '#ffffff') >= 4.5) {
|
||||||
$muted = $cand;
|
$muted = $cand;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'brand' => $brand, // 主色(品牌条、按钮)
|
'brand' => $brand, // 主色原件(引用块高亮竖线等)
|
||||||
'brand_dark' => yang_mail_shade($brand, 0.78), // 品牌条下沿深色带
|
'brand_dark' => yang_mail_shade($brand, 0.78), // 主色深版(备用)
|
||||||
'on_brand' => $onBrand, // 压在品牌色上的字
|
'on_brand' => $headerFg, // 压在头部上的字
|
||||||
|
'header_bg' => $headerBg, // 顶部品牌条底色(深色)
|
||||||
|
'header_fg' => $headerFg, // 头部白字
|
||||||
|
'header_dark'=> $headerDark, // 头部下沿深色带
|
||||||
|
'accent' => $accent, // 强调色(badge 底,暖色)
|
||||||
|
'accent_fg' => $accentFg, // badge 上的字
|
||||||
|
'accent_bd' => $accentBd, // badge 描边
|
||||||
|
'cta_bg' => $ctaBg, // 按钮底(红)
|
||||||
|
'cta_fg' => $ctaFg, // 按钮字(白)
|
||||||
'text' => $textOnTint, // 同色系的强调文字(标题/标签)
|
'text' => $textOnTint, // 同色系的强调文字(标题/标签)
|
||||||
'tint_xx' => $tintXX, // 极浅底:引用块、信息表
|
'tint_xx' => $tintXX, // 极浅底:引用块、信息表
|
||||||
'tint_x' => $tintX, // 稍深一点的浅底:页脚
|
'tint_x' => $tintX, // 稍深一点的浅底:页脚
|
||||||
'tint_line' => $tintLine, // 浅底上的描边/分隔线
|
'tint_line' => $tintLine, // 浅底上的描边/分隔线
|
||||||
'tint_mid' => $tintMid, // 中档:弱化竖线、次要描边
|
'tint_mid' => $tintMid, // 中档:弱化竖线、次要描边
|
||||||
'page_bg' => $pageBg, // 邮件最外层背景
|
'page_bg' => '#ffffff', // 邮件最外层背景(纯白,用户指定)
|
||||||
'body' => '#243040', // 正文(保持深灰蓝,长文好读)
|
'body' => '#243040', // 正文(保持深灰蓝,长文好读)
|
||||||
'muted' => $muted, // 次要文字(时间、页脚),按背景调过
|
'muted' => $muted, // 次要文字(时间、页脚),按背景调过
|
||||||
);
|
);
|
||||||
@@ -479,13 +672,22 @@ function yang_mail_tint($hex, $ratio = 0.18, $onto = '#ffffff')
|
|||||||
* 生成一个按钮(邮件里的按钮只能用表格单元格做,不能用 <button>)
|
* 生成一个按钮(邮件里的按钮只能用表格单元格做,不能用 <button>)
|
||||||
*
|
*
|
||||||
* Outlook 不认 `<a>` 的 `padding`,必须把 padding 放在 `<td>` 上。
|
* Outlook 不认 `<a>` 的 `padding`,必须把 padding 放在 `<td>` 上。
|
||||||
|
*
|
||||||
|
* ── 文字色为什么不写死 #ffffff ────────────────────────────────
|
||||||
|
* 按钮底色是可传入的(主题里默认给红 #c62828)。写死白字在浅底按钮上
|
||||||
|
* 会掉到 2:1 以下,而且「深还是浅」这个问题本身有结构性盲区(中灰两边
|
||||||
|
* 都不达标)。统一走 yang_mail_fg_on():在白与深之间取对比度更高的,
|
||||||
|
* 判据与任何阈值都解耦。
|
||||||
*/
|
*/
|
||||||
function yang_mail_button($text, $url, $bg = null)
|
function yang_mail_button($text, $url, $bg = null, $fg = null)
|
||||||
{
|
{
|
||||||
if ($bg === null) {
|
if ($bg === null) {
|
||||||
$bg = yang_mail_brand_color();
|
$pal = yang_mail_palette();
|
||||||
|
$bg = $pal['cta_bg'];
|
||||||
|
}
|
||||||
|
if ($fg === null) {
|
||||||
|
$fg = yang_mail_fg_on($bg);
|
||||||
}
|
}
|
||||||
$fg = yang_mail_is_dark($bg) ? '#ffffff' : '#1a1a1a';
|
|
||||||
$url = esc_url($url);
|
$url = esc_url($url);
|
||||||
$text = esc_html($text);
|
$text = esc_html($text);
|
||||||
return '<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="margin:0 auto;">'
|
return '<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="margin:0 auto;">'
|
||||||
@@ -541,12 +743,16 @@ function yang_mail_render($args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 整套配色从主色派生一次,后面所有颜色都从这里取。
|
/* 整套配色从主色派生一次,后面所有颜色都从这里取。
|
||||||
* 不在这里散落写死 #xxxxxx —— 那样主色一改,「彩色」就断了,
|
* 不在这里散落写死 #xxxxxx —— 那样主色一改,配色就断了。 */
|
||||||
* 又退回成"一个色块 + 一堆灰」。 */
|
|
||||||
$pal = yang_mail_palette();
|
$pal = yang_mail_palette();
|
||||||
$brand = $pal['brand'];
|
$brand = $pal['brand'];
|
||||||
$brandD = $pal['brand_dark'];
|
$cHeader = $pal['header_bg'];
|
||||||
$onBrand = $pal['on_brand'];
|
$cHeaderFg = $pal['header_fg'];
|
||||||
|
$cHeaderD = $pal['header_dark'];
|
||||||
|
$cAccent = $pal['accent'];
|
||||||
|
$cAccentFg = $pal['accent_fg'];
|
||||||
|
$cAccentBd = $pal['accent_bd'];
|
||||||
|
$cCtaBg = $pal['cta_bg'];
|
||||||
$cText = $pal['text'];
|
$cText = $pal['text'];
|
||||||
$cBody = $pal['body'];
|
$cBody = $pal['body'];
|
||||||
$cMuted = $pal['muted'];
|
$cMuted = $pal['muted'];
|
||||||
@@ -556,14 +762,16 @@ function yang_mail_render($args)
|
|||||||
$cTintMid = $pal['tint_mid'];
|
$cTintMid = $pal['tint_mid'];
|
||||||
$cPageBg = $pal['page_bg'];
|
$cPageBg = $pal['page_bg'];
|
||||||
|
|
||||||
// badge 的背景:把主色往白色方向提亮一档,得到比主色浅、但同色相的实色。
|
/* badge 不再复用头部配色。
|
||||||
// 主色本身是深色时提亮 22%,浅色时压暗 —— 否则浅主色上叠浅 badge 会看不见。
|
* 早先 $badgeBg 是主色提亮一档、文字色复用 $onBrand ⇒ 与头部同色系,
|
||||||
$badgeBg = yang_mail_is_dark($brand)
|
* 远看就是头部里的一块「差不多颜色」,用户原话「和背景蓝色没区分度」。
|
||||||
? yang_mail_tint($brand, 0.22)
|
* 现在用暖色强调色,与深色头部是撞色关系,红/黄一眼能挑出来。 */
|
||||||
: yang_mail_shade($brand, 0.88);
|
$badgeBg = $cAccent;
|
||||||
$badgeBd = yang_mail_is_dark($brand)
|
$badgeBd = $cAccentBd;
|
||||||
? yang_mail_tint($brand, 0.34)
|
|
||||||
: yang_mail_shade($brand, 0.72);
|
/* 引用块高亮竖线:用与按钮同一个红(比 badge 的琥珀更沉),
|
||||||
|
避免 12px 琥珀色小字旁边出现一块同样亮的竖线而互相抢眼。 */
|
||||||
|
$ctaBarColor = $cCtaBg;
|
||||||
|
|
||||||
$site = get_bloginfo('name');
|
$site = get_bloginfo('name');
|
||||||
$home = home_url('/');
|
$home = home_url('/');
|
||||||
@@ -607,21 +815,24 @@ function yang_mail_render($args)
|
|||||||
两套并存,各取所需。只写死 600px 会让手机横向滚动——实测过。 */ ?>
|
两套并存,各取所需。只写死 600px 会让手机横向滚动——实测过。 */ ?>
|
||||||
<table border="0" cellpadding="0" cellspacing="0" width="600" role="presentation" style="width:100%;max-width:600px;background-color:#ffffff;border-radius:12px;overflow:hidden;border:1px solid <?php echo esc_attr($cTintLine); ?>;">
|
<table border="0" cellpadding="0" cellspacing="0" width="600" role="presentation" style="width:100%;max-width:600px;background-color:#ffffff;border-radius:12px;overflow:hidden;border:1px solid <?php echo esc_attr($cTintLine); ?>;">
|
||||||
|
|
||||||
<?php /* ── 顶部品牌条 ── */ ?>
|
<?php /* ── 顶部品牌条 ──
|
||||||
|
* 深色底 + 白字。深色是从主色压下来的,色相仍是主色;
|
||||||
|
* 白字保证在深底上过 AA(详见 yang_mail_deepen_to 的推导)。 */ ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td bgcolor="<?php echo esc_attr($brand); ?>" style="background-color:<?php echo esc_attr($brand); ?>;padding:0;">
|
<td bgcolor="<?php echo esc_attr($cHeader); ?>" style="background-color:<?php echo esc_attr($cHeader); ?>;padding:0;">
|
||||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" role="presentation">
|
<table border="0" cellpadding="0" cellspacing="0" width="100%" role="presentation">
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding:26px 32px;">
|
<td style="padding:26px 32px;">
|
||||||
<div style="font-family:<?php echo $sans; ?>;font-size:19px;font-weight:600;color:<?php echo esc_attr($onBrand); ?>;letter-spacing:0.2px;line-height:1.3;">
|
<div style="font-family:<?php echo $sans; ?>;font-size:19px;font-weight:600;color:<?php echo esc_attr($cHeaderFg); ?>;letter-spacing:0.2px;line-height:1.3;">
|
||||||
<?php echo esc_html($site); ?>
|
<?php echo esc_html($site); ?>
|
||||||
</div>
|
</div>
|
||||||
<?php if ($d['badge'] !== ''): ?>
|
<?php if ($d['badge'] !== ''): ?>
|
||||||
<?php /* badge 用预算好的实色,不用 rgba —— Outlook 不认 rgba,会直接丢掉背景 */ ?>
|
<?php /* badge 用暖色强调色,衬在深色头部上是撞色 —— 一眼能挑出来。
|
||||||
|
仍用预算好的实色,不用 rgba:Outlook 不认 rgba,会直接丢掉背景。 */ ?>
|
||||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="margin-top:10px;">
|
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="margin-top:10px;">
|
||||||
<tr>
|
<tr>
|
||||||
<td bgcolor="<?php echo esc_attr($badgeBg); ?>" style="background-color:<?php echo esc_attr($badgeBg); ?>;border:1px solid <?php echo esc_attr($badgeBd); ?>;border-radius:20px;padding:4px 12px;font-family:<?php echo $sans; ?>;font-size:12px;font-weight:500;line-height:1.4;">
|
<td bgcolor="<?php echo esc_attr($badgeBg); ?>" style="background-color:<?php echo esc_attr($badgeBg); ?>;border:1px solid <?php echo esc_attr($badgeBd); ?>;border-radius:20px;padding:4px 12px;font-family:<?php echo $sans; ?>;font-size:12px;font-weight:600;line-height:1.4;">
|
||||||
<span style="color:<?php echo esc_attr($onBrand); ?>;"><?php echo esc_html($d['badge']); ?></span>
|
<span style="color:<?php echo esc_attr($cAccentFg); ?>;"><?php echo esc_html($d['badge']); ?></span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -631,11 +842,11 @@ function yang_mail_render($args)
|
|||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php /* 主色条下沿压一条深色,给扁平色块一点层次(渐变在 Outlook 里不生效,用纯色)。
|
<?php /* 头部下沿压一条深色,给扁平色块一点层次(渐变在 Outlook 里不生效,用纯色)。
|
||||||
height 必须**同时**写成 HTML 属性和 CSS:Outlook 只认属性,
|
height 必须**同时**写成 HTML 属性和 CSS:Outlook 只认属性,
|
||||||
只写 CSS 高度时这条 3px 带会撑成一行文字高(约 18px),比例就毁了。 */ ?>
|
只写 CSS 高度时这条 3px 带会撑成一行文字高(约 18px),比例就毁了。 */ ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td bgcolor="<?php echo esc_attr($brandD); ?>" height="3" style="background-color:<?php echo esc_attr($brandD); ?>;height:3px;line-height:3px;font-size:0;mso-line-height-rule:exactly;"> </td>
|
<td bgcolor="<?php echo esc_attr($cHeaderD); ?>" height="3" style="background-color:<?php echo esc_attr($cHeaderD); ?>;height:3px;line-height:3px;font-size:0;mso-line-height-rule:exactly;"> </td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<?php /* ── 正文 ── */ ?>
|
<?php /* ── 正文 ── */ ?>
|
||||||
@@ -658,13 +869,16 @@ function yang_mail_render($args)
|
|||||||
<?php
|
<?php
|
||||||
/* 引用块:左边一条竖线,用 border-left 而不是伪元素(邮件不支持 ::before)。
|
/* 引用块:左边一条竖线,用 border-left 而不是伪元素(邮件不支持 ::before)。
|
||||||
*
|
*
|
||||||
* 配色规则:**最后一块用主色高亮,前面的用弱化灰**。
|
* 配色规则:**最后一块用强调暖色高亮,前面的用主色系弱化档**。
|
||||||
* 为什么是「最后」而不是「第一」:评论回复场景里顺序是
|
* 为什么是「最后」而不是「第一」:评论回复场景里顺序是
|
||||||
* 「被回复的原评论」→「新的回复」,语义重点在新的回复上,所以让它高亮。
|
* 「被回复的原评论」→「新的回复」,语义重点在新的回复上,所以让它高亮。
|
||||||
* 只有一个块时它既是第一也是最后 ⇒ 拿到主色,与旧版行为一致。
|
* 只有一个块时它既是第一也是最后 ⇒ 拿到强调色,与旧版行为一致。
|
||||||
*/
|
*
|
||||||
|
* 高亮色从主色换成强调暖色,是为了与深色头部、红按钮形成同一套
|
||||||
|
* 「暖色点缀」语言;同时竖线与 badge 同色,收件人一眼把
|
||||||
|
* 「新回复」标签和「新回复那段字」连起来。 */
|
||||||
$isLast = ($qi === count($quoteList) - 1);
|
$isLast = ($qi === count($quoteList) - 1);
|
||||||
$barColor = $isLast ? $brand : $cTintMid;
|
$barColor = $isLast ? $ctaBarColor : $cTintMid;
|
||||||
$barBg = $isLast ? $cTintXX : $cTintX;
|
$barBg = $isLast ? $cTintXX : $cTintX;
|
||||||
$barMargin = $isLast ? '22px' : '14px';
|
$barMargin = $isLast ? '22px' : '14px';
|
||||||
?>
|
?>
|
||||||
@@ -715,7 +929,9 @@ function yang_mail_render($args)
|
|||||||
|
|
||||||
<?php if ($d['cta_text'] !== '' && $d['cta_url'] !== ''): ?>
|
<?php if ($d['cta_text'] !== '' && $d['cta_url'] !== ''): ?>
|
||||||
<div style="margin:0 0 28px 0;">
|
<div style="margin:0 0 28px 0;">
|
||||||
<?php echo yang_mail_button($d['cta_text'], $d['cta_url']); ?>
|
<?php /* 按钮用红底白字:与深色头部是撞色,位置又在正文末尾,
|
||||||
|
是全信第二个视觉落点。用户明确要求「红白色的文字」。 */ ?>
|
||||||
|
<?php echo yang_mail_button($d['cta_text'], $d['cta_url'], $cCtaBg); ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Theme Name: Kratos_Yang
|
Theme Name: Kratos_Yang
|
||||||
Text Domain: kratos_Yang
|
Text Domain: kratos_Yang
|
||||||
Version: 3.2.8
|
Version: 3.2.9
|
||||||
Requires PHP: 7.0
|
Requires PHP: 7.0
|
||||||
Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。
|
Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。
|
||||||
Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好
|
Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好
|
||||||
|
|||||||
Reference in New Issue
Block a user