深色主题如何避免首屏闪烁?SSR 项目如何保存选择?
先理解原理和示例,再练习完整口述与追问。
回答要点
CSS 变量统一设计令牌;用户偏好优先于系统偏好;服务端 Cookie 决定首屏;首屏前设置主题;监听和清理系统变化。
原理拆解
把背景、文字、边框、强调色等定义成 CSS 自定义属性,在根元素的 data-theme 或类名下覆盖,并让组件引用这些变量,避免业务中散落硬编码颜色。主题要覆盖表单、弹窗、图表、图标和代码块,检查对比度,可用 color-scheme 告知浏览器原生控件的适用配色,但它不会自动替换全部业务样式。
偏好通常分为浅色、深色、跟随系统三种。SSR 可以读取经过白名单校验的 Cookie,在服务端 HTML 根元素直接输出主题,首屏即有正确样式;服务端不能访问 localStorage 或 window。如果只有客户端 localStorage,可通过受 CSP 允许、尽量早执行的小段初始化脚本在主要绘制前设置主题,并处理存储被禁用的情况。依赖 mounted 后再改主题通常容易闪烁,页面也要避免服务端与客户端初始属性不一致。
跟随系统时用 prefers-color-scheme 的媒体查询或 matchMedia,只有用户选择“跟随系统”才随系统变化,显式用户选择优先,并在卸载时清理监听。静态首屏、第三方组件和 SSR hydration 都应一起验收;动画切换尊重减少动态效果偏好,不应每次切换都触发大量布局与请求。
示例与推演
用户选深色后写入受控 Cookie,SSR 根据 light/dark/system 白名单输出 data-theme,CSS 变量立即匹配;跟随系统时通过媒体查询决定默认。客户端恢复同样选择,避免先浅后深。切换主题只修改令牌,不必重建整个应用或重新请求业务数据。
易错点
服务端不能读 localStorage。引入首屏内联脚本时要匹配 CSP;第三方图表、原生表单控件与动态图片也要单独适配。
参考回答可直接练习口述
把背景、文字、边框、强调色等定义成 CSS 自定义属性,在根元素的 data-theme 或类名下覆盖,并让组件引用这些变量,避免业务中散落硬编码颜色。主题要覆盖表单、弹窗、图表、图标和代码块,检查对比度,可用 color-scheme 告知浏览器原生控件的适用配色,但它不会自动替换全部业务样式。