linear-gradient() 在深色模式下失效的根本原因是渐变色值未动态适配且缺乏 fallback;必须用 CSS 变量定义两套颜色、媒体查询重置全部变量、声明带 fallback 的渐变、独立控制 :active 状态、禁用 background-image 过渡、确保文字对比度达标。
直接写 linear-gradient() 在深色模式下按钮会发灰、对比度崩塌,甚至完全不可见——根本原因是渐变色值没随主题动态调整,且 fallback 机制缺失。
硬编码颜色(如 #007aff)在深色模式下无法自动适配,prefers-color-scheme 媒体查询也不能“改写”已声明的渐变函数。唯一可靠路径是把每种颜色都抽成变量,并在 :root 中完整定义两套值。
:root 里先声明默认浅色系:--btn-start: #4a90e2;、--btn-end: #1e5799;
@media (prefers-color-scheme: dark) 内必须重置全部变量,不能只改一两个:--btn-start: #3a6ea5;、--btn-end: #0d2b45;
background-image: linear-gradient(to right, var(--btn-start, #4a90e2), var(--btn-end, #1e5799));
style.setProperty() 动态设变量——它会屏蔽系统自动切换,下次用户在系统设置里切主题就失效iOS 和 Android WebView 对 :active 的渲染逻辑和背景渐变耦合极深。如果只靠变量换色,:active 状态可能在深色模式下变浅(比如从 #0d2b45 变成 #0a2035),导致按压感消失。
button:active 单独写深色/浅色两套 background-image,不能依赖变量继承:active 渐变终点建议比默认态再深 15–20%,例如默认用 var(--btn-end),:active 改用 #051525 这类硬编码值(加注释说明用途)-webkit-tap-highlight-color: transparent;,否则 iOS 点击时的灰色蒙层会覆盖整个渐变,按钮像“被罩住”一样深色模式切换本身是媒体查询触发的重绘,如果再叠加 background-image 的 transition,旧版 Safari(iOS 15–16)大概率掉帧或跳变,用户会觉得“按钮闪一下才变黑”。
transition: background-image 0.3s —— 它在 Safari 中不被硬件加速,且渐变插值精度低transition: background-color 0.3s + 两个预设 class 切换(如 .btn-light / .btn-dark),把渐变写死在 class 里transform: scale(0.98) 或 opacity,它们稳定支持硬件加速:hover 和 [data-theme="dark"] 同时修改同一属性,CSS 优先级冲突会导致 Safari 忽略其中一条规则最常被忽略的是:深色模式下按钮文字颜色也得用变量,且要和背景形成至少 4.5:1 的对比度。别以为“用了深色渐变就万事大吉”,color: var(--text-primary) 漏掉这句,按钮在 OLED 屏上可能直接看不见。