:样式方案与组件库)
上一篇完成了请求缓存与一致性本篇给任务看板建立可演进的视觉层。目标是让业务页面组合稳定组件而不是重复颜色、间距、焦点和禁用规则同时比较 CSS Modules、原子类与 CSS-in-JS 的边界。一、痛点组件库不是截图收藏直接复制设计稿像素会产生几十种近似灰色、任意间距和互不一致的按钮状态。先建立设计令牌原始色阶属于基础 tokencolor-surface、color-danger等语义 token 表达用途组件 token 再描述按钮。主题只替换语义映射业务代码不感知具体色值。样式方案按约束选。CSS Modules 构建期生成局部类名运行成本低适合多数产品Tailwind 以受约束工具类快速组合但需控制超长重复类串运行时 CSS-in-JS 擅长动态主题却可能增加客户端计算与 SSR 配置。不要在同一层混用三种方案。二、原理令牌是受控决策接口令牌必须数量有限、命名按语义、能被自动验证。任意值越容易写系统越快退化。下面程序把基础色映射成亮暗主题并计算 WCAG 相对亮度对比度真实系统还需覆盖悬停、焦点、禁用和高对比模式。defchannel(value):valuevalue/255returnvalue/12.92ifvalue0.04045else((value0.055)/1.055)**2.4defluminance(hex_color):rawhex_color.lstrip(#)rgb[int(raw[index:index2],16)forindexin(0,2,4)]red,green,bluemap(channel,rgb)return0.2126*red0.7152*green0.0722*bluedefcontrast(first,second):bright,darksorted((luminance(first),luminance(second)),reverseTrue)return(bright0.05)/(dark0.05)themes{light:{text:#111827,surface:#ffffff},dark:{text:#f9fafb,surface:#111827},}forname,colorsinthemes.items():ratiocontrast(colors[text],colors[surface])print(f{name}:{ratio:.2f}pass{ratio4.5})运行输出light: 17.74 passTrue dark: 16.98 passTrue三、实现从原语到业务组合先实现 Button、Input、Dialog 等原语再组合 TaskCard。Button 的variant、size、loading是有限 API不要开放red、paddingLeft等视觉细节。组件转发原生属性与 ref保留typebutton默认值以免在表单中误提交。图标按钮必须有可访问名称焦点环不能因“不好看”被删除。变体组合应能检测冲突。例如同一组件不能同时声明紧凑和宽松密度。下例模拟 class 生成器将受支持组合映射为确定性输出。BASE[inline-flex,items-center,rounded,focus-ring]VARIANTS{primary:[bg-brand,text-on-brand],secondary:[bg-muted,text-default],danger:[bg-danger,text-on-danger],}SIZES{sm:[h-8,px-3],md:[h-10,px-4],}defbutton_classes(variantprimary,sizemd,disabledFalse):ifvariantnotinVARIANTS:raiseValueError(funknown variant:{variant})ifsizenotinSIZES:raiseValueError(funknown size:{size})classesBASEVARIANTS[variant]SIZES[size]ifdisabled:classes[opacity-50,pointer-events-none]return .join(classes)print(button_classes(primary,sm))print(button_classes(danger,md,disabledTrue))运行输出inline-flex items-center rounded focus-ring bg-brand text-on-brand h-8 px-3 inline-flex items-center rounded focus-ring bg-danger text-on-danger h-10 px-4 opacity-50 pointer-events-none组件目录同时放样式、测试和 Storybook 故事。故事覆盖默认、长文本、加载、禁用、错误、键盘焦点与窄屏。业务层只组合公开出口禁止深层 import 内部样式。CSS 层叠可用layer明确 reset、tokens、components、utilities 顺序减少提高 specificity 的军备竞赛。四、踩坑主题不是简单反色暗色主题需要重新检查对比、阴影、图表和状态色不能对页面套滤镜。初始主题应在 HTML 尽早确定避免服务端浅色、客户端暗色造成闪烁。系统偏好只是默认值用户明确选择优先并可恢复“跟随系统”。不要把组件库变成业务仓库。通用 Dialog 不应知道“删除任务”接口业务组件负责文案与请求。也不要只做视觉回归一张截图无法证明 Tab 顺序、Escape 关闭、焦点归还和屏幕阅读器名称正确。五、验证视觉、交互与约束一起测自动扫描源码中的任意色值和不在间距刻度内的数值组件测试验证语义角色、键盘与禁用行为视觉回归覆盖主题、视口与关键状态用 axe 做基础无障碍扫描再进行人工键盘和读屏抽查。记录 CSS 体积和未使用规则避免组件库增长拖慢首屏。下一篇会把这些 Input、Button 与错误提示组合成可访问表单使用 schema 让客户端体验与服务端安全共享同一字段契约并处理异步校验、重复提交和错误聚焦。参考来源W3CDesign Tokens Format ModuleW3CWCAG Contrast MinimumMDNCSS Modules 觉得有用就点个赞 收藏方便回头查阅有疑问直接在评论区留言我看到都会回。 本文属于《现代前端框架实战》系列持续更新关注不迷路。 文章里的代码都能直接跑。想要可直接 clone 的完整工程 配套部署脚本 / 踩坑清单评论一声或发邮件到cj2664qq.com我免费发你。如果你正好在做类似系统、或有工程化难题想找人做也欢迎邮件聊一句——我按实际情况评估能落地的就接单或出方案。评论和邮件都能直接找到我不用跳别的平台。