[{"data":1,"prerenderedAt":1451},["ShallowReactive",2],{"article-/topics/design/typography-system-deep-optimization":3,"related-design":298,"content-query-vKczzI72fD":1240},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"topic":5,"author":11,"tags":12,"image":18,"imageQuery":19,"pexelsPhotoId":20,"pexelsUrl":21,"featured":6,"readingTime":22,"body":23,"_type":292,"_id":293,"_source":294,"_file":295,"_stem":296,"_extension":297},"/topics/design/typography-system-deep-optimization","design",false,"","排版系统深度优化：从字重层级到阅读节奏的系统治理","排版系统优化的难点不在选几套字体，而在让字号、行距、层级和阅读密度形成一致规则。本文从内容站与产品界面两类场景出发，讲清排版系统的深度优化方法。","2026-04-25","HTMLPAGE 团队",[13,14,15,16,17],"Typography","Design System","Readability","UI Design","Content Design","/images/topics/design/typography-system-deep-optimization.jpg","typography design layout on computer screen",14553730,"https://www.pexels.com/photo/code-on-computer-screen-14553730/",14,{"type":24,"children":25,"toc":282},"root",[26,34,39,64,69,76,81,86,104,109,115,120,125,138,143,149,154,159,164,187,193,198,203,208,236,241,246,251],{"type":27,"tag":28,"props":29,"children":30},"element","p",{},[31],{"type":32,"value":33},"text","很多团队提到排版系统时，最先想到的通常是字体选择。",{"type":27,"tag":28,"props":35,"children":36},{},[37],{"type":32,"value":38},"这当然重要，但真正影响体验的，往往不是“用什么字体”，而是这些关系是否成立：",{"type":27,"tag":40,"props":41,"children":42},"ul",{},[43,49,54,59],{"type":27,"tag":44,"props":45,"children":46},"li",{},[47],{"type":32,"value":48},"标题层级清不清楚",{"type":27,"tag":44,"props":50,"children":51},{},[52],{"type":32,"value":53},"正文读起来累不累",{"type":27,"tag":44,"props":55,"children":56},{},[57],{"type":32,"value":58},"不同页面之间密度是否一致",{"type":27,"tag":44,"props":60,"children":61},{},[62],{"type":32,"value":63},"内容站和产品界面有没有统一语言",{"type":27,"tag":28,"props":65,"children":66},{},[67],{"type":32,"value":68},"所以排版系统深度优化的重点，不是视觉偏好，而是阅读节奏和系统一致性的治理。",{"type":27,"tag":70,"props":71,"children":73},"h2",{"id":72},"排版系统先解决的是层级关系而不是样式丰富度",[74],{"type":32,"value":75},"排版系统先解决的是层级关系，而不是样式丰富度",{"type":27,"tag":28,"props":77,"children":78},{},[79],{"type":32,"value":80},"很多排版系统看起来定义了很多字号和字重，但真正使用时依然混乱。",{"type":27,"tag":28,"props":82,"children":83},{},[84],{"type":32,"value":85},"原因通常是层级关系没有被收敛：",{"type":27,"tag":40,"props":87,"children":88},{},[89,94,99],{"type":27,"tag":44,"props":90,"children":91},{},[92],{"type":32,"value":93},"同一级标题出现多种尺寸",{"type":27,"tag":44,"props":95,"children":96},{},[97],{"type":32,"value":98},"正文和说明文没有清晰区分",{"type":27,"tag":44,"props":100,"children":101},{},[102],{"type":32,"value":103},"表单、表格和长文各自为政",{"type":27,"tag":28,"props":105,"children":106},{},[107],{"type":32,"value":108},"排版系统真正要先回答的是：页面里有哪些稳定的信息层级，以及它们之间应该保持什么节奏。",{"type":27,"tag":70,"props":110,"children":112},{"id":111},"内容站与产品界面应共用语言但不必完全同构",[113],{"type":32,"value":114},"内容站与产品界面应共用语言，但不必完全同构",{"type":27,"tag":28,"props":116,"children":117},{},[118],{"type":32,"value":119},"很多团队会纠结：内容页面和后台界面是不是要用同一套排版规则。",{"type":27,"tag":28,"props":121,"children":122},{},[123],{"type":32,"value":124},"更现实的答案通常是：",{"type":27,"tag":40,"props":126,"children":127},{},[128,133],{"type":27,"tag":44,"props":129,"children":130},{},[131],{"type":32,"value":132},"共用基本语言：字号梯度、字重规范、颜色层次",{"type":27,"tag":44,"props":134,"children":135},{},[136],{"type":32,"value":137},"区分场景密度：内容页强调阅读，后台强调扫描效率",{"type":27,"tag":28,"props":139,"children":140},{},[141],{"type":32,"value":142},"这样既能保持品牌一致性，也不会牺牲实际场景体验。",{"type":27,"tag":70,"props":144,"children":146},{"id":145},"行长行距和留白决定了阅读疲劳度",[147],{"type":32,"value":148},"行长、行距和留白决定了阅读疲劳度",{"type":27,"tag":28,"props":150,"children":151},{},[152],{"type":32,"value":153},"排版体验最容易被忽视的，不是字号，而是阅读节奏参数。",{"type":27,"tag":28,"props":155,"children":156},{},[157],{"type":32,"value":158},"如果这些参数不稳定，用户即便说不出具体问题，也会明显感觉“读起来累”。",{"type":27,"tag":28,"props":160,"children":161},{},[162],{"type":32,"value":163},"尤其在长文和知识型内容里，更需要系统控制：",{"type":27,"tag":40,"props":165,"children":166},{},[167,172,177,182],{"type":27,"tag":44,"props":168,"children":169},{},[170],{"type":32,"value":171},"行长",{"type":27,"tag":44,"props":173,"children":174},{},[175],{"type":32,"value":176},"行距",{"type":27,"tag":44,"props":178,"children":179},{},[180],{"type":32,"value":181},"段落间距",{"type":27,"tag":44,"props":183,"children":184},{},[185],{"type":32,"value":186},"标题和正文切换节奏",{"type":27,"tag":70,"props":188,"children":190},{"id":189},"一个常见失败案例页面很精致但阅读体验越来越重",[191],{"type":32,"value":192},"一个常见失败案例：页面很精致，但阅读体验越来越重",{"type":27,"tag":28,"props":194,"children":195},{},[196],{"type":32,"value":197},"这类问题常常发生在视觉优化后。团队不断加粗、加大、加颜色，结果信息层级反而更混乱。",{"type":27,"tag":28,"props":199,"children":200},{},[201],{"type":32,"value":202},"原因通常是排版系统只做了风格决策，没有做节奏决策。",{"type":27,"tag":70,"props":204,"children":206},{"id":205},"一份可直接复用的检查清单",[207],{"type":32,"value":205},{"type":27,"tag":40,"props":209,"children":210},{},[211,216,221,226,231],{"type":27,"tag":44,"props":212,"children":213},{},[214],{"type":32,"value":215},"是否先收敛了标题、正文、说明、数据等核心层级",{"type":27,"tag":44,"props":217,"children":218},{},[219],{"type":32,"value":220},"内容站与产品界面是否共享排版语言但保留场景差异",{"type":27,"tag":44,"props":222,"children":223},{},[224],{"type":32,"value":225},"行长、行距和段落节奏是否有稳定规则",{"type":27,"tag":44,"props":227,"children":228},{},[229],{"type":32,"value":230},"新页面是否能在不新增样式的情况下接入现有排版系统",{"type":27,"tag":44,"props":232,"children":233},{},[234],{"type":32,"value":235},"排版优化是否围绕阅读负担而不是单纯视觉变化进行",{"type":27,"tag":70,"props":237,"children":239},{"id":238},"总结",[240],{"type":32,"value":238},{"type":27,"tag":28,"props":242,"children":243},{},[244],{"type":32,"value":245},"排版系统深度优化的关键，不是增加更多样式，而是让层级、节奏和场景密度形成稳定规则。只要先把阅读体验做成系统，排版才会成为长期资产，而不是持续返工来源。",{"type":27,"tag":28,"props":247,"children":248},{},[249],{"type":32,"value":250},"进一步阅读：",{"type":27,"tag":40,"props":252,"children":253},{},[254,264,273],{"type":27,"tag":44,"props":255,"children":256},{},[257],{"type":27,"tag":258,"props":259,"children":261},"a",{"href":260},"/topics/design/design-system-documentation-best-practices",[262],{"type":32,"value":263},"设计系统文档化最佳实践",{"type":27,"tag":44,"props":265,"children":266},{},[267],{"type":27,"tag":258,"props":268,"children":270},{"href":269},"/topics/design/loading-state-design-best-practices",[271],{"type":32,"value":272},"加载状态设计最佳实践",{"type":27,"tag":44,"props":274,"children":275},{},[276],{"type":27,"tag":258,"props":277,"children":279},{"href":278},"/topics/design/web-design-readability-testing-playbook",[280],{"type":32,"value":281},"Web 设计可读性测试手册",{"title":7,"searchDepth":283,"depth":283,"links":284},3,[285,287,288,289,290,291],{"id":72,"depth":286,"text":75},2,{"id":111,"depth":286,"text":114},{"id":145,"depth":286,"text":148},{"id":189,"depth":286,"text":192},{"id":205,"depth":286,"text":205},{"id":238,"depth":286,"text":238},"markdown","content:topics:design:typography-system-deep-optimization.md","content","topics/design/typography-system-deep-optimization.md","topics/design/typography-system-deep-optimization","md",[299,659,961],{"_path":300,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":301,"description":302,"keywords":303,"image":309,"author":11,"date":310,"readingTime":311,"topic":5,"body":312,"_type":292,"_id":656,"_source":294,"_file":657,"_stem":658,"_extension":297},"/topics/design/button-component-design","按钮组件设计详解","学习按钮样式、交互状态、无障碍性和最佳实践",[304,305,306,307,308],"按钮设计","Button Component","交互状态","UI 组件","用户体验","/images/topics/button-design.jpg","2025-12-08",18,{"type":24,"children":313,"toc":638},[314,318,323,328,335,348,354,363,369,378,382,388,399,405,414,420,429,434,443,448,459,464,473,478,491,525,536,579,584],{"type":27,"tag":70,"props":315,"children":316},{"id":301},[317],{"type":32,"value":301},{"type":27,"tag":28,"props":319,"children":320},{},[321],{"type":32,"value":322},"按钮是 UI 中最重要的交互元素。优秀的按钮设计能够指导用户行为。",{"type":27,"tag":70,"props":324,"children":326},{"id":325},"按钮类型",[327],{"type":32,"value":325},{"type":27,"tag":329,"props":330,"children":332},"h3",{"id":331},"primary-button主按钮",[333],{"type":32,"value":334},"Primary Button（主按钮）",{"type":27,"tag":336,"props":337,"children":342},"pre",{"className":338,"code":340,"language":341,"meta":7},[339],"language-css",".btn-primary {\n  background-color: #0066cc;\n  color: #ffffff;\n  padding: 12px 24px;\n  border: none;\n  border-radius: 4px;\n  font-weight: 600;\n  font-size: 16px;\n  cursor: pointer;\n  transition: all 0.2s ease;\n}\n\n.btn-primary:hover {\n  background-color: #0052a3;\n  box-shadow: 0 4px 12px rgba(0, 102, 204, 0.2);\n}\n\n.btn-primary:active {\n  background-color: #003d7a;\n  transform: scale(0.98);\n}\n\n.btn-primary:disabled {\n  background-color: #cccccc;\n  cursor: not-allowed;\n  opacity: 0.6;\n}\n","css",[343],{"type":27,"tag":344,"props":345,"children":346},"code",{"__ignoreMap":7},[347],{"type":32,"value":340},{"type":27,"tag":329,"props":349,"children":351},{"id":350},"secondary-button次按钮",[352],{"type":32,"value":353},"Secondary Button（次按钮）",{"type":27,"tag":336,"props":355,"children":358},{"className":356,"code":357,"language":341,"meta":7},[339],".btn-secondary {\n  background-color: transparent;\n  color: #0066cc;\n  border: 2px solid #0066cc;\n  padding: 10px 22px;\n  border-radius: 4px;\n  font-weight: 600;\n  cursor: pointer;\n  transition: all 0.2s;\n}\n\n.btn-secondary:hover {\n  background-color: rgba(0, 102, 204, 0.1);\n}\n\n.btn-secondary:active {\n  background-color: rgba(0, 102, 204, 0.2);\n}\n",[359],{"type":27,"tag":344,"props":360,"children":361},{"__ignoreMap":7},[362],{"type":32,"value":357},{"type":27,"tag":329,"props":364,"children":366},{"id":365},"danger-button危险按钮",[367],{"type":32,"value":368},"Danger Button（危险按钮）",{"type":27,"tag":336,"props":370,"children":373},{"className":371,"code":372,"language":341,"meta":7},[339],".btn-danger {\n  background-color: #cc0000;\n  color: #ffffff;\n  padding: 12px 24px;\n  border-radius: 4px;\n  cursor: pointer;\n  font-weight: 600;\n}\n\n.btn-danger:hover {\n  background-color: #990000;\n  box-shadow: 0 4px 12px rgba(204, 0, 0, 0.2);\n}\n",[374],{"type":27,"tag":344,"props":375,"children":376},{"__ignoreMap":7},[377],{"type":32,"value":372},{"type":27,"tag":70,"props":379,"children":380},{"id":306},[381],{"type":32,"value":306},{"type":27,"tag":329,"props":383,"children":385},{"id":384},"loading-状态",[386],{"type":32,"value":387},"Loading 状态",{"type":27,"tag":336,"props":389,"children":394},{"className":390,"code":392,"language":393,"meta":7},[391],"language-jsx","import { useState } from 'react';\n\nfunction Button({ children, onClick, loading, ...props }) {\n  const [isLoading, setIsLoading] = useState(false);\n  \n  const handleClick = async () => {\n    setIsLoading(true);\n    try {\n      await onClick();\n    } finally {\n      setIsLoading(false);\n    }\n  };\n  \n  return (\n    \u003Cbutton\n      onClick={handleClick}\n      disabled={isLoading || loading}\n      aria-busy={isLoading || loading}\n      {...props}\n    >\n      {isLoading ? (\n        \u003C>\n          \u003Cspan className=\"spinner\" aria-hidden=\"true\">\u003C/span>\n          {children}\n        \u003C/>\n      ) : (\n        children\n      )}\n    \u003C/button>\n  );\n}\n","jsx",[395],{"type":27,"tag":344,"props":396,"children":397},{"__ignoreMap":7},[398],{"type":32,"value":392},{"type":27,"tag":329,"props":400,"children":402},{"id":401},"disabled-状态",[403],{"type":32,"value":404},"Disabled 状态",{"type":27,"tag":336,"props":406,"children":409},{"className":407,"code":408,"language":341,"meta":7},[339],".btn:disabled {\n  opacity: 0.5;\n  cursor: not-allowed;\n  background-color: #cccccc;\n  color: #999999;\n}\n\n/* 禁用状态下隐藏指针光标 */\n.btn:disabled:hover {\n  box-shadow: none;\n  transform: none;\n}\n",[410],{"type":27,"tag":344,"props":411,"children":412},{"__ignoreMap":7},[413],{"type":32,"value":408},{"type":27,"tag":329,"props":415,"children":417},{"id":416},"focus-状态",[418],{"type":32,"value":419},"Focus 状态",{"type":27,"tag":336,"props":421,"children":424},{"className":422,"code":423,"language":341,"meta":7},[339],".btn:focus {\n  outline: none;\n  box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1),\n              0 0 0 5px #0066cc;\n}\n\n/* 键盘导航焦点 */\n.btn:focus-visible {\n  outline: 2px solid #0066cc;\n  outline-offset: 2px;\n}\n",[425],{"type":27,"tag":344,"props":426,"children":427},{"__ignoreMap":7},[428],{"type":32,"value":423},{"type":27,"tag":70,"props":430,"children":432},{"id":431},"按钮大小",[433],{"type":32,"value":431},{"type":27,"tag":336,"props":435,"children":438},{"className":436,"code":437,"language":341,"meta":7},[339],"/* 小按钮 */\n.btn-sm {\n  padding: 6px 12px;\n  font-size: 12px;\n  min-height: 32px;\n  min-width: 32px;\n}\n\n/* 中等按钮（默认） */\n.btn-md {\n  padding: 12px 24px;\n  font-size: 16px;\n  min-height: 44px;\n  min-width: 44px;\n}\n\n/* 大按钮 */\n.btn-lg {\n  padding: 16px 32px;\n  font-size: 18px;\n  min-height: 56px;\n  min-width: 56px;\n}\n\n/* 全宽按钮 */\n.btn-block {\n  width: 100%;\n  display: block;\n}\n",[439],{"type":27,"tag":344,"props":440,"children":441},{"__ignoreMap":7},[442],{"type":32,"value":437},{"type":27,"tag":70,"props":444,"children":446},{"id":445},"无障碍性",[447],{"type":32,"value":445},{"type":27,"tag":336,"props":449,"children":454},{"className":450,"code":452,"language":453,"meta":7},[451],"language-html","\u003C!-- 语义正确 -->\n\u003Cbutton type=\"submit\" aria-label=\"提交表单\">\n  提交\n\u003C/button>\n\n\u003C!-- 加载状态 -->\n\u003Cbutton aria-busy=\"true\" disabled>\n  \u003Cspan aria-hidden=\"true\" class=\"spinner\">\u003C/span>\n  加载中...\n\u003C/button>\n\n\u003C!-- 图标按钮 -->\n\u003Cbutton aria-label=\"关闭\">\n  \u003Csvg aria-hidden=\"true\" width=\"24\" height=\"24\">\n    \u003Cline x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n    \u003Cline x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n  \u003C/svg>\n\u003C/button>\n\n\u003C!-- 切换按钮 -->\n\u003Cbutton aria-pressed=\"false\" aria-label=\"点赞\">\n  ♥\n\u003C/button>\n","html",[455],{"type":27,"tag":344,"props":456,"children":457},{"__ignoreMap":7},[458],{"type":32,"value":452},{"type":27,"tag":70,"props":460,"children":462},{"id":461},"完整组件示例",[463],{"type":32,"value":461},{"type":27,"tag":336,"props":465,"children":468},{"className":466,"code":467,"language":393,"meta":7},[391],"const Button = React.forwardRef((\n  {\n    children,\n    variant = 'primary',\n    size = 'md',\n    loading = false,\n    disabled = false,\n    icon,\n    className,\n    ...props\n  },\n  ref\n) => {\n  return (\n    \u003Cbutton\n      ref={ref}\n      className={`btn btn-${variant} btn-${size} ${className}`}\n      disabled={disabled || loading}\n      aria-busy={loading}\n      {...props}\n    >\n      {icon && \u003Cspan className=\"btn-icon\" aria-hidden=\"true\">{icon}\u003C/span>}\n      {loading ? (\n        \u003C>\n          \u003Cspan className=\"spinner\" aria-hidden=\"true\">\u003C/span>\n          {children}\n        \u003C/>\n      ) : (\n        children\n      )}\n    \u003C/button>\n  );\n});\n\nButton.displayName = 'Button';\n",[469],{"type":27,"tag":344,"props":470,"children":471},{"__ignoreMap":7},[472],{"type":32,"value":467},{"type":27,"tag":70,"props":474,"children":476},{"id":475},"最佳实践",[477],{"type":32,"value":475},{"type":27,"tag":28,"props":479,"children":480},{},[481,483,489],{"type":32,"value":482},"✅ ",{"type":27,"tag":484,"props":485,"children":486},"strong",{},[487],{"type":32,"value":488},"应该做的事",{"type":32,"value":490},":",{"type":27,"tag":40,"props":492,"children":493},{},[494,499,504,515,520],{"type":27,"tag":44,"props":495,"children":496},{},[497],{"type":32,"value":498},"最小触摸目标 44x44px",{"type":27,"tag":44,"props":500,"children":501},{},[502],{"type":32,"value":503},"清晰的视觉反馈",{"type":27,"tag":44,"props":505,"children":506},{},[507,509],{"type":32,"value":508},"使用语义 HTML ",{"type":27,"tag":344,"props":510,"children":512},{"className":511},[],[513],{"type":32,"value":514},"\u003Cbutton>",{"type":27,"tag":44,"props":516,"children":517},{},[518],{"type":32,"value":519},"提供加载状态反馈",{"type":27,"tag":44,"props":521,"children":522},{},[523],{"type":32,"value":524},"支持键盘导航",{"type":27,"tag":28,"props":526,"children":527},{},[528,530,535],{"type":32,"value":529},"❌ ",{"type":27,"tag":484,"props":531,"children":532},{},[533],{"type":32,"value":534},"不应该做的事",{"type":32,"value":490},{"type":27,"tag":40,"props":537,"children":538},{},[539,552,557,562,567],{"type":27,"tag":44,"props":540,"children":541},{},[542,544,550],{"type":32,"value":543},"使用 ",{"type":27,"tag":344,"props":545,"children":547},{"className":546},[],[548],{"type":32,"value":549},"\u003Cdiv>",{"type":32,"value":551}," 模拟按钮",{"type":27,"tag":44,"props":553,"children":554},{},[555],{"type":32,"value":556},"隐藏焦点指示器",{"type":27,"tag":44,"props":558,"children":559},{},[560],{"type":32,"value":561},"过多的按钮样式",{"type":27,"tag":44,"props":563,"children":564},{},[565],{"type":32,"value":566},"忽视禁用状态",{"type":27,"tag":44,"props":568,"children":569},{},[570,571,577],{"type":32,"value":543},{"type":27,"tag":344,"props":572,"children":574},{"className":573},[],[575],{"type":32,"value":576},"\u003Ca>",{"type":32,"value":578}," 代替按钮",{"type":27,"tag":70,"props":580,"children":582},{"id":581},"测试清单",[583],{"type":32,"value":581},{"type":27,"tag":40,"props":585,"children":588},{"className":586},[587],"contains-task-list",[589,602,611,620,629],{"type":27,"tag":44,"props":590,"children":593},{"className":591},[592],"task-list-item",[594,600],{"type":27,"tag":595,"props":596,"children":599},"input",{"disabled":597,"type":598},true,"checkbox",[],{"type":32,"value":601}," 在各种浏览器中测试",{"type":27,"tag":44,"props":603,"children":605},{"className":604},[592],[606,609],{"type":27,"tag":595,"props":607,"children":608},{"disabled":597,"type":598},[],{"type":32,"value":610}," 验证键盘导航",{"type":27,"tag":44,"props":612,"children":614},{"className":613},[592],[615,618],{"type":27,"tag":595,"props":616,"children":617},{"disabled":597,"type":598},[],{"type":32,"value":619}," 检查色彩对比度",{"type":27,"tag":44,"props":621,"children":623},{"className":622},[592],[624,627],{"type":27,"tag":595,"props":625,"children":626},{"disabled":597,"type":598},[],{"type":32,"value":628}," 测试触摸设备",{"type":27,"tag":44,"props":630,"children":632},{"className":631},[592],[633,636],{"type":27,"tag":595,"props":634,"children":635},{"disabled":597,"type":598},[],{"type":32,"value":637}," 屏幕阅读器兼容性",{"title":7,"searchDepth":283,"depth":283,"links":639},[640,641,646,651,652,653,654,655],{"id":301,"depth":286,"text":301},{"id":325,"depth":286,"text":325,"children":642},[643,644,645],{"id":331,"depth":283,"text":334},{"id":350,"depth":283,"text":353},{"id":365,"depth":283,"text":368},{"id":306,"depth":286,"text":306,"children":647},[648,649,650],{"id":384,"depth":283,"text":387},{"id":401,"depth":283,"text":404},{"id":416,"depth":283,"text":419},{"id":431,"depth":286,"text":431},{"id":445,"depth":286,"text":445},{"id":461,"depth":286,"text":461},{"id":475,"depth":286,"text":475},{"id":581,"depth":286,"text":581},"content:topics:design:button-component-design.md","topics/design/button-component-design.md","topics/design/button-component-design",{"_path":660,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":661,"description":662,"keywords":663,"image":668,"author":11,"date":310,"readingTime":669,"topic":5,"body":670,"_type":292,"_id":958,"_source":294,"_file":959,"_stem":960,"_extension":297},"/topics/design/dark-mode-design","暗黑模式设计完整方案","学习暗黑模式实现、色彩方案、对比度管理和最佳实践",[664,665,666,667,308],"暗黑模式","Dark Mode","色彩系统","CSS 变量","/images/topics/dark-mode-design.jpg",20,{"type":24,"children":671,"toc":941},[672,676,681,686,692,701,707,716,721,727,736,742,753,759,768,773,782,787,796,801,810,814,823,851,860,888,892],{"type":27,"tag":70,"props":673,"children":674},{"id":661},[675],{"type":32,"value":661},{"type":27,"tag":28,"props":677,"children":678},{},[679],{"type":32,"value":680},"暗黑模式已成为现代应用的标准功能。它能够减少眼睛疲劳、节省电池、改善用户体验。",{"type":27,"tag":70,"props":682,"children":684},{"id":683},"核心色彩系统",[685],{"type":32,"value":683},{"type":27,"tag":329,"props":687,"children":689},{"id":688},"light-mode-配色",[690],{"type":32,"value":691},"Light Mode 配色",{"type":27,"tag":336,"props":693,"children":696},{"className":694,"code":695,"language":341,"meta":7},[339],":root {\n  /* Light Mode */\n  --bg-primary: #ffffff;\n  --bg-secondary: #f5f5f5;\n  --bg-tertiary: #efefef;\n  \n  --text-primary: #1a1a1a;\n  --text-secondary: #666666;\n  --text-tertiary: #999999;\n  \n  --border-color: #e0e0e0;\n  --divider-color: #f0f0f0;\n}\n",[697],{"type":27,"tag":344,"props":698,"children":699},{"__ignoreMap":7},[700],{"type":32,"value":695},{"type":27,"tag":329,"props":702,"children":704},{"id":703},"dark-mode-配色",[705],{"type":32,"value":706},"Dark Mode 配色",{"type":27,"tag":336,"props":708,"children":711},{"className":709,"code":710,"language":341,"meta":7},[339],"@media (prefers-color-scheme: dark) {\n  :root {\n    /* Dark Mode */\n    --bg-primary: #1a1a1a;\n    --bg-secondary: #2d2d2d;\n    --bg-tertiary: #3a3a3a;\n    \n    --text-primary: #ffffff;\n    --text-secondary: #e0e0e0;\n    --text-tertiary: #a0a0a0;\n    \n    --border-color: #404040;\n    --divider-color: #2a2a2a;\n  }\n}\n",[712],{"type":27,"tag":344,"props":713,"children":714},{"__ignoreMap":7},[715],{"type":32,"value":710},{"type":27,"tag":70,"props":717,"children":719},{"id":718},"实现方案",[720],{"type":32,"value":718},{"type":27,"tag":329,"props":722,"children":724},{"id":723},"方案-1prefers-color-scheme",[725],{"type":32,"value":726},"方案 1：prefers-color-scheme",{"type":27,"tag":336,"props":728,"children":731},{"className":729,"code":730,"language":341,"meta":7},[339],"/* 自动跟随系统设置 */\n@media (prefers-color-scheme: light) {\n  :root {\n    --bg: #fff;\n    --text: #000;\n  }\n}\n\n@media (prefers-color-scheme: dark) {\n  :root {\n    --bg: #1a1a1a;\n    --text: #fff;\n  }\n}\n\nbody {\n  background: var(--bg);\n  color: var(--text);\n}\n",[732],{"type":27,"tag":344,"props":733,"children":734},{"__ignoreMap":7},[735],{"type":32,"value":730},{"type":27,"tag":329,"props":737,"children":739},{"id":738},"方案-2javascript-切换",[740],{"type":32,"value":741},"方案 2：JavaScript 切换",{"type":27,"tag":336,"props":743,"children":748},{"className":744,"code":746,"language":747,"meta":7},[745],"language-javascript","// 检测和切换暗黑模式\nfunction initDarkMode() {\n  const isDark = localStorage.getItem('darkMode') === 'true' ||\n                 window.matchMedia('(prefers-color-scheme: dark)').matches;\n  \n  if (isDark) {\n    document.documentElement.setAttribute('data-theme', 'dark');\n  }\n}\n\nfunction toggleDarkMode() {\n  const isDark = document.documentElement.getAttribute('data-theme') === 'dark';\n  const newTheme = isDark ? 'light' : 'dark';\n  \n  document.documentElement.setAttribute('data-theme', newTheme);\n  localStorage.setItem('darkMode', newTheme === 'dark');\n}\n\n// CSS 应用\nhtml[data-theme='light'] {\n  color-scheme: light;\n}\n\nhtml[data-theme='dark'] {\n  color-scheme: dark;\n}\n","javascript",[749],{"type":27,"tag":344,"props":750,"children":751},{"__ignoreMap":7},[752],{"type":32,"value":746},{"type":27,"tag":329,"props":754,"children":756},{"id":755},"方案-3css-variables-javascript",[757],{"type":32,"value":758},"方案 3：CSS Variables + JavaScript",{"type":27,"tag":336,"props":760,"children":763},{"className":761,"code":762,"language":747,"meta":7},[745],"const themes = {\n  light: {\n    '--bg-primary': '#ffffff',\n    '--text-primary': '#000000',\n    '--accent': '#0066cc',\n    '--border': '#e0e0e0',\n  },\n  dark: {\n    '--bg-primary': '#1a1a1a',\n    '--text-primary': '#ffffff',\n    '--accent': '#4da3ff',\n    '--border': '#404040',\n  },\n};\n\nfunction applyTheme(themeName) {\n  const theme = themes[themeName];\n  Object.entries(theme).forEach(([key, value]) => {\n    document.documentElement.style.setProperty(key, value);\n  });\n  localStorage.setItem('theme', themeName);\n}\n",[764],{"type":27,"tag":344,"props":765,"children":766},{"__ignoreMap":7},[767],{"type":32,"value":762},{"type":27,"tag":70,"props":769,"children":771},{"id":770},"对比度管理",[772],{"type":32,"value":770},{"type":27,"tag":336,"props":774,"children":777},{"className":775,"code":776,"language":341,"meta":7},[339],"/* Light Mode 对比度 */\n:root {\n  --contrast-high: #000000;     /* 21:1 */\n  --contrast-medium: #333333;   /* 12.6:1 */\n  --contrast-low: #666666;      /* 5.1:1 */\n}\n\n/* Dark Mode 对比度 */\n@media (prefers-color-scheme: dark) {\n  :root {\n    --contrast-high: #ffffff;    /* 21:1 */\n    --contrast-medium: #e0e0e0;  /* 11.6:1 */\n    --contrast-low: #a0a0a0;     /* 4.5:1 */\n  }\n}\n\n/* 应用对比度 */\n.text-primary { color: var(--contrast-high); }\n.text-secondary { color: var(--contrast-medium); }\n.text-tertiary { color: var(--contrast-low); }\n",[778],{"type":27,"tag":344,"props":779,"children":780},{"__ignoreMap":7},[781],{"type":32,"value":776},{"type":27,"tag":70,"props":783,"children":785},{"id":784},"图片和图表处理",[786],{"type":32,"value":784},{"type":27,"tag":336,"props":788,"children":791},{"className":789,"code":790,"language":453,"meta":7},[451],"\u003C!-- 针对不同主题的图片 -->\n\u003Cpicture>\n  \u003Csource \n    media=\"(prefers-color-scheme: dark)\" \n    srcset=\"chart-dark.svg\"\n  />\n  \u003Cimg src=\"chart-light.svg\" alt=\"图表\" />\n\u003C/picture>\n\n\u003C!-- SVG 颜色适配 -->\n\u003Csvg class=\"icon\">\n  \u003Ccircle cx=\"50\" cy=\"50\" r=\"40\" fill=\"currentColor\" />\n\u003C/svg>\n\n\u003Cstyle>\n  .icon {\n    color: var(--text-primary);\n  }\n\u003C/style>\n",[792],{"type":27,"tag":344,"props":793,"children":794},{"__ignoreMap":7},[795],{"type":32,"value":790},{"type":27,"tag":70,"props":797,"children":799},{"id":798},"完整示例",[800],{"type":32,"value":798},{"type":27,"tag":336,"props":802,"children":805},{"className":803,"code":804,"language":393,"meta":7},[391],"import { useState, useEffect } from 'react';\n\nfunction ThemeProvider({ children }) {\n  const [theme, setTheme] = useState('light');\n  const [mounted, setMounted] = useState(false);\n  \n  useEffect(() => {\n    setMounted(true);\n    \n    // 获取保存的主题或系统偏好\n    const savedTheme = localStorage.getItem('theme');\n    const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches \n      ? 'dark' \n      : 'light';\n    \n    const initialTheme = savedTheme || systemTheme;\n    setTheme(initialTheme);\n    document.documentElement.setAttribute('data-theme', initialTheme);\n  }, []);\n  \n  const toggleTheme = () => {\n    const newTheme = theme === 'light' ? 'dark' : 'light';\n    setTheme(newTheme);\n    localStorage.setItem('theme', newTheme);\n    document.documentElement.setAttribute('data-theme', newTheme);\n  };\n  \n  // 防止闪烁\n  if (!mounted) {\n    return null;\n  }\n  \n  return (\n    \u003CThemeContext.Provider value={{ theme, toggleTheme }}>\n      {children}\n      \u003CThemeToggle theme={theme} onChange={toggleTheme} />\n    \u003C/ThemeContext.Provider>\n  );\n}\n\nfunction ThemeToggle({ theme, onChange }) {\n  return (\n    \u003Cbutton \n      onClick={onChange}\n      aria-label={`切换到${theme === 'light' ? '暗黑' : '亮色'}模式`}\n    >\n      {theme === 'light' ? '🌙' : '☀️'}\n    \u003C/button>\n  );\n}\n",[806],{"type":27,"tag":344,"props":807,"children":808},{"__ignoreMap":7},[809],{"type":32,"value":804},{"type":27,"tag":70,"props":811,"children":812},{"id":475},[813],{"type":32,"value":475},{"type":27,"tag":28,"props":815,"children":816},{},[817,818,822],{"type":32,"value":482},{"type":27,"tag":484,"props":819,"children":820},{},[821],{"type":32,"value":488},{"type":32,"value":490},{"type":27,"tag":40,"props":824,"children":825},{},[826,831,836,841,846],{"type":27,"tag":44,"props":827,"children":828},{},[829],{"type":32,"value":830},"支持系统偏好",{"type":27,"tag":44,"props":832,"children":833},{},[834],{"type":32,"value":835},"提供手动切换选项",{"type":27,"tag":44,"props":837,"children":838},{},[839],{"type":32,"value":840},"确保足够的对比度",{"type":27,"tag":44,"props":842,"children":843},{},[844],{"type":32,"value":845},"优化图片和图表",{"type":27,"tag":44,"props":847,"children":848},{},[849],{"type":32,"value":850},"防止加载闪烁",{"type":27,"tag":28,"props":852,"children":853},{},[854,855,859],{"type":32,"value":529},{"type":27,"tag":484,"props":856,"children":857},{},[858],{"type":32,"value":534},{"type":32,"value":490},{"type":27,"tag":40,"props":861,"children":862},{},[863,868,873,878,883],{"type":27,"tag":44,"props":864,"children":865},{},[866],{"type":32,"value":867},"强制单一模式",{"type":27,"tag":44,"props":869,"children":870},{},[871],{"type":32,"value":872},"忽视性能影响",{"type":27,"tag":44,"props":874,"children":875},{},[876],{"type":32,"value":877},"使用相同的颜色",{"type":27,"tag":44,"props":879,"children":880},{},[881],{"type":32,"value":882},"忘记保存用户偏好",{"type":27,"tag":44,"props":884,"children":885},{},[886],{"type":32,"value":887},"过度使用深色背景",{"type":27,"tag":70,"props":889,"children":890},{"id":581},[891],{"type":32,"value":581},{"type":27,"tag":40,"props":893,"children":895},{"className":894},[587],[896,905,914,923,932],{"type":27,"tag":44,"props":897,"children":899},{"className":898},[592],[900,903],{"type":27,"tag":595,"props":901,"children":902},{"disabled":597,"type":598},[],{"type":32,"value":904}," 在浅色和深色模式下测试所有页面",{"type":27,"tag":44,"props":906,"children":908},{"className":907},[592],[909,912],{"type":27,"tag":595,"props":910,"children":911},{"disabled":597,"type":598},[],{"type":32,"value":913}," 检查颜色对比度符合 WCAG 标准",{"type":27,"tag":44,"props":915,"children":917},{"className":916},[592],[918,921],{"type":27,"tag":595,"props":919,"children":920},{"disabled":597,"type":598},[],{"type":32,"value":922}," 验证图片和图表在两种模式下清晰",{"type":27,"tag":44,"props":924,"children":926},{"className":925},[592],[927,930],{"type":27,"tag":595,"props":928,"children":929},{"disabled":597,"type":598},[],{"type":32,"value":931}," 测试主题切换的平滑性",{"type":27,"tag":44,"props":933,"children":935},{"className":934},[592],[936,939],{"type":27,"tag":595,"props":937,"children":938},{"disabled":597,"type":598},[],{"type":32,"value":940}," 检查用户偏好是否被保存",{"title":7,"searchDepth":283,"depth":283,"links":942},[943,944,948,953,954,955,956,957],{"id":661,"depth":286,"text":661},{"id":683,"depth":286,"text":683,"children":945},[946,947],{"id":688,"depth":283,"text":691},{"id":703,"depth":283,"text":706},{"id":718,"depth":286,"text":718,"children":949},[950,951,952],{"id":723,"depth":283,"text":726},{"id":738,"depth":283,"text":741},{"id":755,"depth":283,"text":758},{"id":770,"depth":286,"text":770},{"id":784,"depth":286,"text":784},{"id":798,"depth":286,"text":798},{"id":475,"depth":286,"text":475},{"id":581,"depth":286,"text":581},"content:topics:design:dark-mode-design.md","topics/design/dark-mode-design.md","topics/design/dark-mode-design",{"_path":962,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":963,"description":964,"keywords":965,"image":970,"author":971,"date":310,"readingTime":669,"topic":5,"body":972,"_type":292,"_id":1237,"_source":294,"_file":1238,"_stem":1239,"_extension":297},"/topics/design/form-controls-design","表单控件设计规范","学习输入框、选择框、复选框等表单控件的设计和实现",[966,967,968,969,308],"表单设计","Form Controls","输入框","验证反馈","/images/topics/form-controls-design.jpg","AI Content Team",{"type":24,"children":973,"toc":1223},[974,978,983,988,993,1002,1007,1016,1020,1029,1034,1043,1048,1057,1062,1071,1076,1085,1089,1098,1124,1133,1161,1165],{"type":27,"tag":70,"props":975,"children":976},{"id":963},[977],{"type":32,"value":963},{"type":27,"tag":28,"props":979,"children":980},{},[981],{"type":32,"value":982},"优秀的表单设计能够提高用户完成率和满意度。",{"type":27,"tag":70,"props":984,"children":986},{"id":985},"输入框设计",[987],{"type":32,"value":985},{"type":27,"tag":329,"props":989,"children":991},{"id":990},"基础文本输入",[992],{"type":32,"value":990},{"type":27,"tag":336,"props":994,"children":997},{"className":995,"code":996,"language":341,"meta":7},[339],".input {\n  width: 100%;\n  padding: 12px 16px;\n  font-size: 16px;\n  border: 2px solid #e0e0e0;\n  border-radius: 4px;\n  font-family: inherit;\n  transition: border-color 0.2s;\n}\n\n.input:hover {\n  border-color: #bdbdbd;\n}\n\n.input:focus {\n  outline: none;\n  border-color: #0066cc;\n  box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);\n}\n\n.input:disabled {\n  background-color: #f5f5f5;\n  color: #999999;\n  cursor: not-allowed;\n}\n\n.input.error {\n  border-color: #cc0000;\n}\n\n.input.success {\n  border-color: #00cc00;\n}\n",[998],{"type":27,"tag":344,"props":999,"children":1000},{"__ignoreMap":7},[1001],{"type":32,"value":996},{"type":27,"tag":329,"props":1003,"children":1005},{"id":1004},"标签和提示",[1006],{"type":32,"value":1004},{"type":27,"tag":336,"props":1008,"children":1011},{"className":1009,"code":1010,"language":453,"meta":7},[451],"\u003Cdiv class=\"form-group\">\n  \u003Clabel for=\"email\" class=\"form-label\">\n    邮箱地址 \u003Cspan class=\"required\">*\u003C/span>\n  \u003C/label>\n  \u003Cinput\n    id=\"email\"\n    type=\"email\"\n    placeholder=\"user@example.com\"\n    class=\"input\"\n    aria-describedby=\"email-hint\"\n  />\n  \u003Cp id=\"email-hint\" class=\"form-hint\">\n    我们永远不会分享你的邮箱\n  \u003C/p>\n\u003C/div>\n",[1012],{"type":27,"tag":344,"props":1013,"children":1014},{"__ignoreMap":7},[1015],{"type":32,"value":1010},{"type":27,"tag":70,"props":1017,"children":1018},{"id":969},[1019],{"type":32,"value":969},{"type":27,"tag":336,"props":1021,"children":1024},{"className":1022,"code":1023,"language":393,"meta":7},[391],"function FormInput({ label, error, success, helperText, value, onChange, ...props }) {\n  return (\n    \u003Cdiv className=\"form-group\">\n      \u003Clabel className=\"form-label\">{label}\u003C/label>\n      \u003Cinput\n        className={`input ${\n          error ? 'error' : success ? 'success' : ''\n        }`}\n        value={value}\n        onChange={onChange}\n        {...props}\n      />\n      {error && (\n        \u003Cp className=\"form-error\" role=\"alert\">\n          {error}\n        \u003C/p>\n      )}\n      {success && (\n        \u003Cp className=\"form-success\">\n          ✓ {success}\n        \u003C/p>\n      )}\n      {helperText && (\n        \u003Cp className=\"form-hint\">{helperText}\u003C/p>\n      )}\n    \u003C/div>\n  );\n}\n",[1025],{"type":27,"tag":344,"props":1026,"children":1027},{"__ignoreMap":7},[1028],{"type":32,"value":1023},{"type":27,"tag":70,"props":1030,"children":1032},{"id":1031},"选择框设计",[1033],{"type":32,"value":1031},{"type":27,"tag":336,"props":1035,"children":1038},{"className":1036,"code":1037,"language":341,"meta":7},[339],".select {\n  appearance: none;\n  width: 100%;\n  padding: 12px 16px;\n  border: 2px solid #e0e0e0;\n  border-radius: 4px;\n  background-image: url('data:image/svg+xml;...');\n  background-repeat: no-repeat;\n  background-position: right 12px center;\n  padding-right: 40px;\n  font-size: 16px;\n  cursor: pointer;\n}\n\n.select:hover {\n  border-color: #bdbdbd;\n}\n\n.select:focus {\n  outline: none;\n  border-color: #0066cc;\n  box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);\n}\n",[1039],{"type":27,"tag":344,"props":1040,"children":1041},{"__ignoreMap":7},[1042],{"type":32,"value":1037},{"type":27,"tag":70,"props":1044,"children":1046},{"id":1045},"复选框和单选按钮",[1047],{"type":32,"value":1045},{"type":27,"tag":336,"props":1049,"children":1052},{"className":1050,"code":1051,"language":341,"meta":7},[339],".checkbox-group {\n  display: flex;\n  gap: 12px;\n  align-items: center;\n}\n\n.checkbox-input {\n  width: 20px;\n  height: 20px;\n  cursor: pointer;\n  accent-color: #0066cc;\n}\n\n.checkbox-label {\n  cursor: pointer;\n  user-select: none;\n}\n\n/* 自定义复选框 */\n.custom-checkbox {\n  appearance: none;\n  width: 20px;\n  height: 20px;\n  border: 2px solid #e0e0e0;\n  border-radius: 4px;\n  cursor: pointer;\n  background-color: white;\n  transition: all 0.2s;\n}\n\n.custom-checkbox:checked {\n  background-color: #0066cc;\n  border-color: #0066cc;\n  background-image: url('data:image/svg+xml;...');\n}\n\n.custom-checkbox:focus {\n  box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);\n}\n",[1053],{"type":27,"tag":344,"props":1054,"children":1055},{"__ignoreMap":7},[1056],{"type":32,"value":1051},{"type":27,"tag":70,"props":1058,"children":1060},{"id":1059},"文本区域",[1061],{"type":32,"value":1059},{"type":27,"tag":336,"props":1063,"children":1066},{"className":1064,"code":1065,"language":341,"meta":7},[339],".textarea {\n  width: 100%;\n  min-height: 120px;\n  padding: 12px 16px;\n  border: 2px solid #e0e0e0;\n  border-radius: 4px;\n  font-family: inherit;\n  font-size: 16px;\n  resize: vertical;\n  transition: border-color 0.2s;\n}\n\n.textarea:focus {\n  outline: none;\n  border-color: #0066cc;\n  box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);\n}\n",[1067],{"type":27,"tag":344,"props":1068,"children":1069},{"__ignoreMap":7},[1070],{"type":32,"value":1065},{"type":27,"tag":70,"props":1072,"children":1074},{"id":1073},"完整表单示例",[1075],{"type":32,"value":1073},{"type":27,"tag":336,"props":1077,"children":1080},{"className":1078,"code":1079,"language":393,"meta":7},[391],"function SignupForm() {\n  const [formData, setFormData] = useState({\n    name: '',\n    email: '',\n    password: '',\n    confirmPassword: '',\n    subscribe: false,\n    terms: false,\n  });\n  \n  const [errors, setErrors] = useState({});\n  const [touched, setTouched] = useState({});\n  const [submitted, setSubmitted] = useState(false);\n  \n  const handleChange = (e) => {\n    const { name, value, type, checked } = e.target;\n    setFormData(prev => ({\n      ...prev,\n      [name]: type === 'checkbox' ? checked : value,\n    }));\n    \n    // 实时验证\n    if (touched[name]) {\n      validateField(name, type === 'checkbox' ? checked : value);\n    }\n  };\n  \n  const handleBlur = (e) => {\n    const { name } = e.target;\n    setTouched(prev => ({ ...prev, [name]: true }));\n    validateField(name, formData[name]);\n  };\n  \n  const validateField = (name, value) => {\n    const newErrors = { ...errors };\n    \n    switch (name) {\n      case 'name':\n        if (!value) newErrors.name = '名字不能为空';\n        else delete newErrors.name;\n        break;\n      case 'email':\n        if (!value) newErrors.email = '邮箱不能为空';\n        else if (!/^[^\\\\s@]+@[^\\\\s@]+\\\\.[^\\\\s@]+$/.test(value)) {\n          newErrors.email = '请输入有效的邮箱';\n        } else {\n          delete newErrors.email;\n        }\n        break;\n      case 'password':\n        if (!value) newErrors.password = '密码不能为空';\n        else if (value.length \u003C 8) newErrors.password = '密码至少 8 位';\n        else delete newErrors.password;\n        break;\n      case 'confirmPassword':\n        if (value !== formData.password) {\n          newErrors.confirmPassword = '两次密码输入不一致';\n        } else {\n          delete newErrors.confirmPassword;\n        }\n        break;\n      case 'terms':\n        if (!value) newErrors.terms = '必须同意服务条款';\n        else delete newErrors.terms;\n        break;\n      default:\n        break;\n    }\n    \n    setErrors(newErrors);\n  };\n  \n  const validate = () => {\n    const newErrors = {};\n    \n    if (!formData.name) newErrors.name = '名字不能为空';\n    if (!formData.email) newErrors.email = '邮箱不能为空';\n    if (formData.password.length \u003C 8) newErrors.password = '密码至少 8 位';\n    if (formData.password !== formData.confirmPassword) {\n      newErrors.confirmPassword = '两次密码输入不一致';\n    }\n    if (!formData.terms) newErrors.terms = '必须同意服务条款';\n    \n    return newErrors;\n  };\n  \n  const handleSubmit = async (e) => {\n    e.preventDefault();\n    \n    // 标记所有字段已触碰\n    setTouched({\n      name: true,\n      email: true,\n      password: true,\n      confirmPassword: true,\n      terms: true,\n    });\n    \n    const newErrors = validate();\n    \n    if (Object.keys(newErrors).length === 0) {\n      setSubmitted(true);\n      // 提交表单\n      console.log('Form submitted:', formData);\n      // 重置表单\n      setFormData({\n        name: '',\n        email: '',\n        password: '',\n        confirmPassword: '',\n        subscribe: false,\n        terms: false,\n      });\n    } else {\n      setErrors(newErrors);\n    }\n  };\n  \n  return (\n    \u003Cform onSubmit={handleSubmit} noValidate>\n      {submitted && (\n        \u003Cdiv className=\"form-success-message\" role=\"alert\">\n          注册成功！\n        \u003C/div>\n      )}\n      \n      \u003CFormInput\n        label=\"姓名\"\n        name=\"name\"\n        value={formData.name}\n        onChange={handleChange}\n        onBlur={handleBlur}\n        error={touched.name && errors.name}\n        helperText=\"请输入你的全名\"\n      />\n      \n      \u003CFormInput\n        label=\"邮箱\"\n        name=\"email\"\n        type=\"email\"\n        value={formData.email}\n        onChange={handleChange}\n        onBlur={handleBlur}\n        error={touched.email && errors.email}\n      />\n      \n      \u003CFormInput\n        label=\"密码\"\n        name=\"password\"\n        type=\"password\"\n        value={formData.password}\n        onChange={handleChange}\n        onBlur={handleBlur}\n        error={touched.password && errors.password}\n        helperText=\"至少 8 个字符\"\n      />\n      \n      \u003CFormInput\n        label=\"确认密码\"\n        name=\"confirmPassword\"\n        type=\"password\"\n        value={formData.confirmPassword}\n        onChange={handleChange}\n        onBlur={handleBlur}\n        error={touched.confirmPassword && errors.confirmPassword}\n      />\n      \n      \u003Cdiv className=\"form-group\">\n        \u003Clabel className=\"checkbox-label\">\n          \u003Cinput\n            type=\"checkbox\"\n            name=\"subscribe\"\n            checked={formData.subscribe}\n            onChange={handleChange}\n            className=\"checkbox-input\"\n          />\n          订阅我们的新闻通讯\n        \u003C/label>\n      \u003C/div>\n      \n      \u003Cdiv className=\"form-group\">\n        \u003Clabel className=\"checkbox-label\">\n          \u003Cinput\n            type=\"checkbox\"\n            name=\"terms\"\n            checked={formData.terms}\n            onChange={handleChange}\n            onBlur={handleBlur}\n            className=\"checkbox-input\"\n          />\n          我同意\n          \u003Ca href=\"/terms\" target=\"_blank\" rel=\"noopener noreferrer\">\n            服务条款\n          \u003C/a>\n          和\n          \u003Ca href=\"/privacy\" target=\"_blank\" rel=\"noopener noreferrer\">\n            隐私政策\n          \u003C/a>\n        \u003C/label>\n        {touched.terms && errors.terms && (\n          \u003Cp className=\"form-error\">{errors.terms}\u003C/p>\n        )}\n      \u003C/div>\n      \n      \u003Cbutton type=\"submit\" className=\"btn btn-primary btn-block\">\n        注册\n      \u003C/button>\n    \u003C/form>\n  );\n}\n",[1081],{"type":27,"tag":344,"props":1082,"children":1083},{"__ignoreMap":7},[1084],{"type":32,"value":1079},{"type":27,"tag":70,"props":1086,"children":1087},{"id":475},[1088],{"type":32,"value":475},{"type":27,"tag":28,"props":1090,"children":1091},{},[1092,1093,1097],{"type":32,"value":482},{"type":27,"tag":484,"props":1094,"children":1095},{},[1096],{"type":32,"value":488},{"type":32,"value":490},{"type":27,"tag":40,"props":1099,"children":1100},{},[1101,1106,1111,1116,1120],{"type":27,"tag":44,"props":1102,"children":1103},{},[1104],{"type":32,"value":1105},"使用正确的输入类型",{"type":27,"tag":44,"props":1107,"children":1108},{},[1109],{"type":32,"value":1110},"提供实时验证反馈",{"type":27,"tag":44,"props":1112,"children":1113},{},[1114],{"type":32,"value":1115},"清晰的标签和提示",{"type":27,"tag":44,"props":1117,"children":1118},{},[1119],{"type":32,"value":498},{"type":27,"tag":44,"props":1121,"children":1122},{},[1123],{"type":32,"value":524},{"type":27,"tag":28,"props":1125,"children":1126},{},[1127,1128,1132],{"type":32,"value":529},{"type":27,"tag":484,"props":1129,"children":1130},{},[1131],{"type":32,"value":534},{"type":32,"value":490},{"type":27,"tag":40,"props":1134,"children":1135},{},[1136,1141,1146,1151,1156],{"type":27,"tag":44,"props":1137,"children":1138},{},[1139],{"type":32,"value":1140},"隐藏标签",{"type":27,"tag":44,"props":1142,"children":1143},{},[1144],{"type":32,"value":1145},"过度使用占位符",{"type":27,"tag":44,"props":1147,"children":1148},{},[1149],{"type":32,"value":1150},"验证后立即提交",{"type":27,"tag":44,"props":1152,"children":1153},{},[1154],{"type":32,"value":1155},"忽视无障碍性",{"type":27,"tag":44,"props":1157,"children":1158},{},[1159],{"type":32,"value":1160},"复杂的验证规则",{"type":27,"tag":70,"props":1162,"children":1163},{"id":581},[1164],{"type":32,"value":581},{"type":27,"tag":40,"props":1166,"children":1168},{"className":1167},[587],[1169,1178,1187,1196,1205,1214],{"type":27,"tag":44,"props":1170,"children":1172},{"className":1171},[592],[1173,1176],{"type":27,"tag":595,"props":1174,"children":1175},{"disabled":597,"type":598},[],{"type":32,"value":1177}," 所有控件都可用键盘导航",{"type":27,"tag":44,"props":1179,"children":1181},{"className":1180},[592],[1182,1185],{"type":27,"tag":595,"props":1183,"children":1184},{"disabled":597,"type":598},[],{"type":32,"value":1186}," 标签与输入框关联",{"type":27,"tag":44,"props":1188,"children":1190},{"className":1189},[592],[1191,1194],{"type":27,"tag":595,"props":1192,"children":1193},{"disabled":597,"type":598},[],{"type":32,"value":1195}," 验证消息清晰",{"type":27,"tag":44,"props":1197,"children":1199},{"className":1198},[592],[1200,1203],{"type":27,"tag":595,"props":1201,"children":1202},{"disabled":597,"type":598},[],{"type":32,"value":1204}," 色彩对比度足够",{"type":27,"tag":44,"props":1206,"children":1208},{"className":1207},[592],[1209,1212],{"type":27,"tag":595,"props":1210,"children":1211},{"disabled":597,"type":598},[],{"type":32,"value":1213}," 屏幕阅读器兼容",{"type":27,"tag":44,"props":1215,"children":1217},{"className":1216},[592],[1218,1221],{"type":27,"tag":595,"props":1219,"children":1220},{"disabled":597,"type":598},[],{"type":32,"value":1222}," 移动设备测试",{"title":7,"searchDepth":283,"depth":283,"links":1224},[1225,1226,1230,1231,1232,1233,1234,1235,1236],{"id":963,"depth":286,"text":963},{"id":985,"depth":286,"text":985,"children":1227},[1228,1229],{"id":990,"depth":283,"text":990},{"id":1004,"depth":283,"text":1004},{"id":969,"depth":286,"text":969},{"id":1031,"depth":286,"text":1031},{"id":1045,"depth":286,"text":1045},{"id":1059,"depth":286,"text":1059},{"id":1073,"depth":286,"text":1073},{"id":475,"depth":286,"text":475},{"id":581,"depth":286,"text":581},"content:topics:design:form-controls-design.md","topics/design/form-controls-design.md","topics/design/form-controls-design",{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"topic":5,"author":11,"tags":1241,"image":18,"imageQuery":19,"pexelsPhotoId":20,"pexelsUrl":21,"featured":6,"readingTime":22,"body":1242,"_type":292,"_id":293,"_source":294,"_file":295,"_stem":296,"_extension":297},[13,14,15,16,17],{"type":24,"children":1243,"toc":1443},[1244,1248,1252,1271,1275,1279,1283,1287,1302,1306,1310,1314,1318,1329,1333,1337,1341,1345,1349,1368,1372,1376,1380,1384,1407,1411,1415,1419],{"type":27,"tag":28,"props":1245,"children":1246},{},[1247],{"type":32,"value":33},{"type":27,"tag":28,"props":1249,"children":1250},{},[1251],{"type":32,"value":38},{"type":27,"tag":40,"props":1253,"children":1254},{},[1255,1259,1263,1267],{"type":27,"tag":44,"props":1256,"children":1257},{},[1258],{"type":32,"value":48},{"type":27,"tag":44,"props":1260,"children":1261},{},[1262],{"type":32,"value":53},{"type":27,"tag":44,"props":1264,"children":1265},{},[1266],{"type":32,"value":58},{"type":27,"tag":44,"props":1268,"children":1269},{},[1270],{"type":32,"value":63},{"type":27,"tag":28,"props":1272,"children":1273},{},[1274],{"type":32,"value":68},{"type":27,"tag":70,"props":1276,"children":1277},{"id":72},[1278],{"type":32,"value":75},{"type":27,"tag":28,"props":1280,"children":1281},{},[1282],{"type":32,"value":80},{"type":27,"tag":28,"props":1284,"children":1285},{},[1286],{"type":32,"value":85},{"type":27,"tag":40,"props":1288,"children":1289},{},[1290,1294,1298],{"type":27,"tag":44,"props":1291,"children":1292},{},[1293],{"type":32,"value":93},{"type":27,"tag":44,"props":1295,"children":1296},{},[1297],{"type":32,"value":98},{"type":27,"tag":44,"props":1299,"children":1300},{},[1301],{"type":32,"value":103},{"type":27,"tag":28,"props":1303,"children":1304},{},[1305],{"type":32,"value":108},{"type":27,"tag":70,"props":1307,"children":1308},{"id":111},[1309],{"type":32,"value":114},{"type":27,"tag":28,"props":1311,"children":1312},{},[1313],{"type":32,"value":119},{"type":27,"tag":28,"props":1315,"children":1316},{},[1317],{"type":32,"value":124},{"type":27,"tag":40,"props":1319,"children":1320},{},[1321,1325],{"type":27,"tag":44,"props":1322,"children":1323},{},[1324],{"type":32,"value":132},{"type":27,"tag":44,"props":1326,"children":1327},{},[1328],{"type":32,"value":137},{"type":27,"tag":28,"props":1330,"children":1331},{},[1332],{"type":32,"value":142},{"type":27,"tag":70,"props":1334,"children":1335},{"id":145},[1336],{"type":32,"value":148},{"type":27,"tag":28,"props":1338,"children":1339},{},[1340],{"type":32,"value":153},{"type":27,"tag":28,"props":1342,"children":1343},{},[1344],{"type":32,"value":158},{"type":27,"tag":28,"props":1346,"children":1347},{},[1348],{"type":32,"value":163},{"type":27,"tag":40,"props":1350,"children":1351},{},[1352,1356,1360,1364],{"type":27,"tag":44,"props":1353,"children":1354},{},[1355],{"type":32,"value":171},{"type":27,"tag":44,"props":1357,"children":1358},{},[1359],{"type":32,"value":176},{"type":27,"tag":44,"props":1361,"children":1362},{},[1363],{"type":32,"value":181},{"type":27,"tag":44,"props":1365,"children":1366},{},[1367],{"type":32,"value":186},{"type":27,"tag":70,"props":1369,"children":1370},{"id":189},[1371],{"type":32,"value":192},{"type":27,"tag":28,"props":1373,"children":1374},{},[1375],{"type":32,"value":197},{"type":27,"tag":28,"props":1377,"children":1378},{},[1379],{"type":32,"value":202},{"type":27,"tag":70,"props":1381,"children":1382},{"id":205},[1383],{"type":32,"value":205},{"type":27,"tag":40,"props":1385,"children":1386},{},[1387,1391,1395,1399,1403],{"type":27,"tag":44,"props":1388,"children":1389},{},[1390],{"type":32,"value":215},{"type":27,"tag":44,"props":1392,"children":1393},{},[1394],{"type":32,"value":220},{"type":27,"tag":44,"props":1396,"children":1397},{},[1398],{"type":32,"value":225},{"type":27,"tag":44,"props":1400,"children":1401},{},[1402],{"type":32,"value":230},{"type":27,"tag":44,"props":1404,"children":1405},{},[1406],{"type":32,"value":235},{"type":27,"tag":70,"props":1408,"children":1409},{"id":238},[1410],{"type":32,"value":238},{"type":27,"tag":28,"props":1412,"children":1413},{},[1414],{"type":32,"value":245},{"type":27,"tag":28,"props":1416,"children":1417},{},[1418],{"type":32,"value":250},{"type":27,"tag":40,"props":1420,"children":1421},{},[1422,1429,1436],{"type":27,"tag":44,"props":1423,"children":1424},{},[1425],{"type":27,"tag":258,"props":1426,"children":1427},{"href":260},[1428],{"type":32,"value":263},{"type":27,"tag":44,"props":1430,"children":1431},{},[1432],{"type":27,"tag":258,"props":1433,"children":1434},{"href":269},[1435],{"type":32,"value":272},{"type":27,"tag":44,"props":1437,"children":1438},{},[1439],{"type":27,"tag":258,"props":1440,"children":1441},{"href":278},[1442],{"type":32,"value":281},{"title":7,"searchDepth":283,"depth":283,"links":1444},[1445,1446,1447,1448,1449,1450],{"id":72,"depth":286,"text":75},{"id":111,"depth":286,"text":114},{"id":145,"depth":286,"text":148},{"id":189,"depth":286,"text":192},{"id":205,"depth":286,"text":205},{"id":238,"depth":286,"text":238},1777086814734]