agentcss 0.0.0-stage → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/01-tokens/README.md +236 -0
- package/01-tokens/behavior/dismissable.js +132 -0
- package/01-tokens/behavior/emit.js +76 -0
- package/01-tokens/behavior/focus-return.js +81 -0
- package/01-tokens/behavior/roving.js +152 -0
- package/01-tokens/behavior/typeahead.js +124 -0
- package/01-tokens/focus-ring-demo.html +133 -0
- package/01-tokens/focus-ring.css +102 -0
- package/01-tokens/page.css +244 -0
- package/01-tokens/polyfill.js +116 -0
- package/01-tokens/responsive-demo.html +171 -0
- package/01-tokens/scrollbar-demo.html +194 -0
- package/01-tokens/scrollbar.css +179 -0
- package/01-tokens/theme-toggle.js +103 -0
- package/01-tokens/tokens.css +972 -0
- package/01-tokens/typography.css +156 -0
- package/02-primitives/badge/README.md +71 -0
- package/02-primitives/badge/badge.css +141 -0
- package/02-primitives/badge/demo.html +101 -0
- package/02-primitives/button/README.md +99 -0
- package/02-primitives/button/button.css +353 -0
- package/02-primitives/button/demo.html +200 -0
- package/02-primitives/card/README.md +145 -0
- package/02-primitives/card/card.css +246 -0
- package/02-primitives/card/demo.html +170 -0
- package/02-primitives/choice/README.md +161 -0
- package/02-primitives/choice/choice.css +395 -0
- package/02-primitives/choice/demo.html +277 -0
- package/02-primitives/combobox/README.md +79 -0
- package/02-primitives/combobox/combobox.css +223 -0
- package/02-primitives/combobox/combobox.js +485 -0
- package/02-primitives/combobox/demo.html +109 -0
- package/02-primitives/date-range/README.md +100 -0
- package/02-primitives/date-range/date-range.css +206 -0
- package/02-primitives/date-range/date-range.js +301 -0
- package/02-primitives/date-range/demo.html +104 -0
- package/02-primitives/input/README.md +170 -0
- package/02-primitives/input/demo.html +246 -0
- package/02-primitives/input/input.css +239 -0
- package/02-primitives/popover/README.md +80 -0
- package/02-primitives/popover/demo.html +150 -0
- package/02-primitives/popover/popover.css +187 -0
- package/02-primitives/popover/popover.js +331 -0
- package/02-primitives/progress/README.md +82 -0
- package/02-primitives/progress/demo.html +154 -0
- package/02-primitives/progress/progress.css +172 -0
- package/02-primitives/select/README.md +95 -0
- package/02-primitives/select/demo.html +121 -0
- package/02-primitives/select/select.css +151 -0
- package/02-primitives/select/select.js +549 -0
- package/02-primitives/separator/README.md +63 -0
- package/02-primitives/separator/demo.html +84 -0
- package/02-primitives/separator/separator.css +73 -0
- package/02-primitives/skeleton/README.md +69 -0
- package/02-primitives/skeleton/demo.html +110 -0
- package/02-primitives/skeleton/skeleton.css +96 -0
- package/02-primitives/switch/README.md +65 -0
- package/02-primitives/switch/demo.html +115 -0
- package/02-primitives/switch/switch.css +370 -0
- package/03-patterns/accordion/README.md +121 -0
- package/03-patterns/accordion/accordion.css +453 -0
- package/03-patterns/accordion/accordion.js +369 -0
- package/03-patterns/accordion/demo.html +223 -0
- package/03-patterns/content/README.md +103 -0
- package/03-patterns/content/content.css +286 -0
- package/03-patterns/content/demo.html +88 -0
- package/03-patterns/drawer/README.md +79 -0
- package/03-patterns/drawer/demo.html +101 -0
- package/03-patterns/drawer/drawer.css +129 -0
- package/03-patterns/drawer/drawer.js +258 -0
- package/03-patterns/dropdown/README.md +78 -0
- package/03-patterns/dropdown/demo.html +101 -0
- package/03-patterns/dropdown/dropdown.css +135 -0
- package/03-patterns/dropdown/dropdown.js +451 -0
- package/03-patterns/form-validation/README.md +147 -0
- package/03-patterns/form-validation/demo.html +280 -0
- package/03-patterns/form-validation/form-validation.css +263 -0
- package/03-patterns/list/README.md +150 -0
- package/03-patterns/list/demo.html +225 -0
- package/03-patterns/list/flip.js +201 -0
- package/03-patterns/list/list.css +162 -0
- package/03-patterns/nav/README.md +225 -0
- package/03-patterns/nav/demo.html +131 -0
- package/03-patterns/nav/nav.css +314 -0
- package/03-patterns/nav/nav.js +430 -0
- package/03-patterns/nav/toc.js +111 -0
- package/03-patterns/overlay/README.md +196 -0
- package/03-patterns/overlay/demo.html +241 -0
- package/03-patterns/overlay/overlay.css +319 -0
- package/03-patterns/overlay/overlay.js +563 -0
- package/03-patterns/pagination/README.md +114 -0
- package/03-patterns/pagination/demo.html +165 -0
- package/03-patterns/pagination/pagination.css +195 -0
- package/03-patterns/pagination/pagination.js +395 -0
- package/03-patterns/reveal/README.md +91 -0
- package/03-patterns/reveal/demo.html +106 -0
- package/03-patterns/reveal/reveal.css +93 -0
- package/03-patterns/reveal/reveal.js +172 -0
- package/03-patterns/states/README.md +141 -0
- package/03-patterns/states/demo.html +240 -0
- package/03-patterns/states/states.css +252 -0
- package/03-patterns/tabs/README.md +84 -0
- package/03-patterns/tabs/demo.html +139 -0
- package/03-patterns/tabs/tabs.css +172 -0
- package/03-patterns/tabs/tabs.js +307 -0
- package/03-patterns/tooltip/README.md +96 -0
- package/03-patterns/tooltip/demo.html +78 -0
- package/03-patterns/tooltip/tooltip.css +89 -0
- package/03-patterns/tooltip/tooltip.js +288 -0
- package/03-patterns/tree/README.md +94 -0
- package/03-patterns/tree/demo.html +138 -0
- package/03-patterns/tree/tree.css +113 -0
- package/03-patterns/tree/tree.js +456 -0
- package/04-recipes/analysis-report/README.md +80 -0
- package/04-recipes/analysis-report/analysis-report.css +187 -0
- package/04-recipes/analysis-report/demo.html +274 -0
- package/04-recipes/data-showcase/README.md +45 -0
- package/04-recipes/data-showcase/demo.html +247 -0
- package/04-recipes/detail-page/README.md +93 -0
- package/04-recipes/detail-page/demo.html +55 -0
- package/04-recipes/detail-page/detail-page.css +190 -0
- package/04-recipes/detail-page/full.html +60 -0
- package/04-recipes/detail-page/null.html +60 -0
- package/04-recipes/detail-page/partial.html +60 -0
- package/04-recipes/detail-page/verify-skeleton.py +19 -0
- package/04-recipes/longform/README.md +93 -0
- package/04-recipes/longform/agc-memory.svg +4 -0
- package/04-recipes/longform/content.html +610 -0
- package/04-recipes/longform/content.md +51 -0
- package/04-recipes/longform/longform.html +627 -0
- package/04-recipes/report/README.md +176 -0
- package/04-recipes/report/demo.html +355 -0
- package/04-recipes/report/report.css +364 -0
- package/04-recipes/table/README.md +103 -0
- package/04-recipes/table/demo.html +455 -0
- package/04-recipes/table/table.css +372 -0
- package/04-recipes/tierA-tokens.css +189 -0
- package/09-assets/README.md +74 -0
- package/09-assets/bar/README.md +94 -0
- package/09-assets/bar/bar.css +166 -0
- package/09-assets/bar/bar.js +320 -0
- package/09-assets/bar/demo.html +176 -0
- package/09-assets/echarts-adapter/demo.html +192 -0
- package/09-assets/echarts-adapter/echarts-adapter.js +277 -0
- package/09-assets/model-viewer/README.md +155 -0
- package/09-assets/model-viewer/demo.html +105 -0
- package/09-assets/model-viewer/model-viewer.css +143 -0
- package/09-assets/model-viewer/model-viewer.js +423 -0
- package/09-assets/scientific-plot/README.md +94 -0
- package/09-assets/scientific-plot/demo.html +252 -0
- package/09-assets/scientific-plot/scientific-plot.css +141 -0
- package/09-assets/scientific-plot/scientific-plot.js +610 -0
- package/09-assets/sparkline/README.md +153 -0
- package/09-assets/sparkline/demo.html +163 -0
- package/09-assets/sparkline/sparkline.css +158 -0
- package/09-assets/sparkline/sparkline.js +508 -0
- package/API.md +332 -0
- package/CHANGELOG.md +3116 -0
- package/CODE_OF_CONDUCT.md +64 -0
- package/CONTRIBUTING.md +89 -0
- package/ERRORS.md +1658 -0
- package/LICENSE +21 -0
- package/README.md +491 -2
- package/SECURITY.md +72 -0
- package/START-HERE.md +164 -0
- package/SUPPORT.md +109 -0
- package/adapters/presentation/README.md +113 -0
- package/adapters/presentation/check.js +101 -0
- package/adapters/presentation/deck.schema.json +74 -0
- package/adapters/presentation/to-doc.js +138 -0
- package/ai/START-HERE.md +104 -0
- package/ai/behaviors.json +380 -0
- package/ai/behaviors.schema.json +61 -0
- package/ai/capabilities.json +56 -0
- package/ai/cli.js +387 -0
- package/ai/components.json +1944 -0
- package/ai/components.meta.json +168 -0
- package/ai/components.schema.json +220 -0
- package/ai/contract.schema.json +147 -0
- package/ai/deprecations.json +55 -0
- package/ai/deprecations.schema.json +85 -0
- package/ai/motion-policy.json +22 -0
- package/ai/patch.js +323 -0
- package/ai/patch.schema.json +63 -0
- package/ai/profiles.json +92 -0
- package/ai/tokens.audience.json +55 -0
- package/ai/tokens.audience.schema.json +73 -0
- package/ai/tokens.json +762 -0
- package/ai/tokens.schema.json +58 -0
- package/ai/tokens.tree.json +752 -0
- package/ai/tokens.tree.schema.json +56 -0
- package/ai/validate.js +383 -0
- package/dist/01-tokens/behavior/dismissable.js +60 -0
- package/dist/01-tokens/behavior/emit.js +21 -0
- package/dist/01-tokens/behavior/focus-return.js +31 -0
- package/dist/01-tokens/behavior/roving.js +77 -0
- package/dist/01-tokens/behavior/typeahead.js +61 -0
- package/dist/01-tokens/focus-ring.css +1 -0
- package/dist/01-tokens/page.css +1 -0
- package/dist/01-tokens/polyfill.js +78 -0
- package/dist/01-tokens/scrollbar.css +1 -0
- package/dist/01-tokens/theme-toggle.js +61 -0
- package/dist/01-tokens/tokens.css +1 -0
- package/dist/01-tokens/typography.css +1 -0
- package/dist/02-primitives/badge/badge.css +1 -0
- package/dist/02-primitives/button/button.css +1 -0
- package/dist/02-primitives/card/card.css +1 -0
- package/dist/02-primitives/choice/choice.css +1 -0
- package/dist/02-primitives/combobox/combobox.css +1 -0
- package/dist/02-primitives/combobox/combobox.js +439 -0
- package/dist/02-primitives/date-range/date-range.css +1 -0
- package/dist/02-primitives/date-range/date-range.js +267 -0
- package/dist/02-primitives/input/input.css +1 -0
- package/dist/02-primitives/popover/popover.css +1 -0
- package/dist/02-primitives/popover/popover.js +257 -0
- package/dist/02-primitives/progress/progress.css +1 -0
- package/dist/02-primitives/select/select.css +1 -0
- package/dist/02-primitives/select/select.js +449 -0
- package/dist/02-primitives/separator/separator.css +1 -0
- package/dist/02-primitives/skeleton/skeleton.css +1 -0
- package/dist/02-primitives/switch/switch.css +1 -0
- package/dist/03-patterns/accordion/accordion.css +1 -0
- package/dist/03-patterns/accordion/accordion.js +219 -0
- package/dist/03-patterns/content/content.css +1 -0
- package/dist/03-patterns/drawer/drawer.css +1 -0
- package/dist/03-patterns/drawer/drawer.js +229 -0
- package/dist/03-patterns/dropdown/dropdown.css +1 -0
- package/dist/03-patterns/dropdown/dropdown.js +365 -0
- package/dist/03-patterns/form-validation/form-validation.css +1 -0
- package/dist/03-patterns/list/flip.js +117 -0
- package/dist/03-patterns/list/list.css +1 -0
- package/dist/03-patterns/nav/nav.css +1 -0
- package/dist/03-patterns/nav/nav.js +322 -0
- package/dist/03-patterns/nav/toc.js +76 -0
- package/dist/03-patterns/overlay/overlay.css +1 -0
- package/dist/03-patterns/overlay/overlay.js +398 -0
- package/dist/03-patterns/pagination/pagination.css +1 -0
- package/dist/03-patterns/pagination/pagination.js +273 -0
- package/dist/03-patterns/reveal/reveal.css +1 -0
- package/dist/03-patterns/reveal/reveal.js +138 -0
- package/dist/03-patterns/states/states.css +1 -0
- package/dist/03-patterns/tabs/tabs.css +1 -0
- package/dist/03-patterns/tabs/tabs.js +242 -0
- package/dist/03-patterns/tooltip/tooltip.css +1 -0
- package/dist/03-patterns/tooltip/tooltip.js +213 -0
- package/dist/03-patterns/tree/tree.css +1 -0
- package/dist/03-patterns/tree/tree.js +383 -0
- package/dist/04-recipes/analysis-report/analysis-report.css +1 -0
- package/dist/04-recipes/detail-page/detail-page.css +1 -0
- package/dist/04-recipes/report/report.css +1 -0
- package/dist/04-recipes/table/table.css +1 -0
- package/dist/04-recipes/tierA-tokens.css +1 -0
- package/dist/09-assets/bar/bar.css +1 -0
- package/dist/09-assets/bar/bar.js +222 -0
- package/dist/09-assets/echarts-adapter/echarts-adapter.js +185 -0
- package/dist/09-assets/model-viewer/model-viewer.css +1 -0
- package/dist/09-assets/model-viewer/model-viewer.js +320 -0
- package/dist/09-assets/scientific-plot/scientific-plot.css +1 -0
- package/dist/09-assets/scientific-plot/scientific-plot.js +568 -0
- package/dist/09-assets/sparkline/sparkline.css +1 -0
- package/dist/09-assets/sparkline/sparkline.js +265 -0
- package/dist/COSTS.md +56 -0
- package/docs/AI-CONTRACT.md +197 -0
- package/docs/BACKLOG.md +127 -0
- package/docs/BENCHMARK.md +252 -0
- package/docs/GUIDANCE.md +154 -0
- package/docs/INVARIANT.md +372 -0
- package/docs/LAYER-BASELINE.md +158 -0
- package/docs/RELEASING.md +275 -0
- package/docs/RFC-THEME-SCOPE.md +141 -0
- package/docs/ROADMAP.md +182 -0
- package/index.html +82 -0
- package/package.json +107 -4
- package/types/index.d.ts +310 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<link rel="icon" href="data:,">
|
|
7
|
+
<title>导航 · 页头 / 目录 / 移动端抽屉</title>
|
|
8
|
+
<link rel="stylesheet" href="../../01-tokens/tokens.css">
|
|
9
|
+
<link rel="stylesheet" href="../../01-tokens/typography.css">
|
|
10
|
+
<link rel="stylesheet" href="../../01-tokens/page.css">
|
|
11
|
+
<link rel="stylesheet" href="../../02-primitives/button/button.css">
|
|
12
|
+
<link rel="stylesheet" href="nav.css">
|
|
13
|
+
<style>
|
|
14
|
+
.skip { position: absolute; top: 0; left: 0; z-index: var(--z-raised); /* 🔴*/
|
|
15
|
+
background: var(--accent); color: var(--text-on-accent); padding: var(--sp-2) var(--sp-4);
|
|
16
|
+
font-size: var(--fs-sm); text-decoration: none;
|
|
17
|
+
transform: translateY(-120%); }
|
|
18
|
+
.skip:focus { transform: translateY(0); }
|
|
19
|
+
.shell { display: grid; gap: var(--sp-6); max-width: 1040px; margin: 0 auto;
|
|
20
|
+
padding: var(--sp-6) var(--sp-5) var(--sp-8); grid-template-columns: 1fr; }
|
|
21
|
+
@media (min-width: 60rem) {.shell { grid-template-columns: 12rem minmax(0,1fr); }
|
|
22
|
+
|
|
23
|
+
}
|
|
24
|
+
main { max-width: var(--measure-prose); min-width: 0; }
|
|
25
|
+
p { max-width: var(--measure-prose); margin: 0 0 var(--sp-4); }
|
|
26
|
+
p.small { font-size: var(--fs-xs); color: var(--text-tertiary); line-height: 1.7; }
|
|
27
|
+
.aside { background: var(--warning-bg);
|
|
28
|
+
padding: var(--sp-3) var(--sp-4); border-radius: var(--r-sm);
|
|
29
|
+
font-size: var(--fs-sm); max-width: var(--measure-prose); margin: 0 0 var(--sp-5);
|
|
30
|
+
line-height: 1.65; }
|
|
31
|
+
.spacer { height: 55vh; }
|
|
32
|
+
|
|
33
|
+
/* 让目录高亮有滚动空间 */
|
|
34
|
+
</style>
|
|
35
|
+
</head>
|
|
36
|
+
<body class="page page">
|
|
37
|
+
|
|
38
|
+
<a class="skip" href="#main">跳到主内容</a>
|
|
39
|
+
|
|
40
|
+
<header class="nav" data-nav>
|
|
41
|
+
<div class="nav__inner">
|
|
42
|
+
<a class="nav__brand" href="#">技术考古 <span>/ AGC</span></a>
|
|
43
|
+
<button class="nav__toggle" id="nav-toggle" aria-expanded="false"
|
|
44
|
+
aria-controls="nav-list" aria-label="打开菜单"><i></i></button>
|
|
45
|
+
<ul class="nav__list" id="nav-list">
|
|
46
|
+
<li><a class="nav__link" href="#main" aria-current="page">制导计算机</a></li>
|
|
47
|
+
<li><a class="nav__link" href="#mem">存储器</a></li>
|
|
48
|
+
<li><a class="nav__link" href="#sched">调度</a></li>
|
|
49
|
+
<li><a class="nav__link" href="#sim">复现</a></li>
|
|
50
|
+
</ul>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="nav__scrim" id="nav-scrim"></div>
|
|
53
|
+
</header>
|
|
54
|
+
|
|
55
|
+
<div class="shell">
|
|
56
|
+
|
|
57
|
+
<nav class="toc" aria-label="本页目录">
|
|
58
|
+
<p class="toc__title">本页</p>
|
|
59
|
+
<ul class="toc__list" id="toc-list">
|
|
60
|
+
<li><a class="toc__link" href="#top">本页</a></li>
|
|
61
|
+
<li><a class="toc__link" href="#mem">存储器构成</a></li>
|
|
62
|
+
<li><a class="toc__link" href="#sched">优先级与准入</a></li>
|
|
63
|
+
<li><a class="toc__link" href="#sim">把它跑起来</a></li>
|
|
64
|
+
</ul>
|
|
65
|
+
</nav>
|
|
66
|
+
|
|
67
|
+
<main id="main">
|
|
68
|
+
<h1 id="top">导航的三件事</h1>
|
|
69
|
+
<p class="lead">
|
|
70
|
+
页头告诉你<b>在哪</b>,目录告诉你<b>读到哪</b>,抽屉在窄屏上替你省掉横向空间。
|
|
71
|
+
三件事看起来简单,做错都会让用户"点了个寂寞"。
|
|
72
|
+
</p>
|
|
73
|
+
|
|
74
|
+
<div class="aside">
|
|
75
|
+
<b>请这样试:</b>① 把窗口拖窄到 768px 以下 → 出现汉堡按钮,点它开合抽屉,
|
|
76
|
+
试 <code>Esc</code>、点遮罩、点链接后关闭;② 滚动正文,看左侧目录是否跟着高亮;
|
|
77
|
+
③ 点页头的"存储器",看它是否标记为当前页。
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<h2 id="mem" class="rule-top">存储器构成</h2>
|
|
81
|
+
<p>
|
|
82
|
+
AGC 的核心存储器是 2048 个 36 位字,总容量 73,728 位。指令与数据混在一起,
|
|
83
|
+
地址按字计。真正让人吃惊的是每位宇航员分到的 4 KB 重写区——那不是共享内存,
|
|
84
|
+
是<strong>每人一份</strong>。
|
|
85
|
+
</p>
|
|
86
|
+
<p>
|
|
87
|
+
换句话说:三个人可以各自在自己的 4 KB 里堆程序,哪怕会覆盖掉别人写的东西。
|
|
88
|
+
在那个年代这已经算是很大的宽容。
|
|
89
|
+
</p>
|
|
90
|
+
<div class="spacer"></div>
|
|
91
|
+
|
|
92
|
+
<h2 id="sched" class="rule-top">优先级与准入</h2>
|
|
93
|
+
<p>
|
|
94
|
+
AGC 的调度靠优先级抢占:更高优先级的任务可以打断低优先级的任务。
|
|
95
|
+
这套机制加上准入控制,让关键任务(姿态、点火)不会被普通计算饿死。
|
|
96
|
+
</p>
|
|
97
|
+
<p>
|
|
98
|
+
阿波罗 13 号在 33 万公里外反复报出的告警,就是这套机制在工作——
|
|
99
|
+
它宁可一直报错,也不肯停机,因为停了机地面就失去了唯一的实时数据源。
|
|
100
|
+
</p>
|
|
101
|
+
<div class="spacer"></div>
|
|
102
|
+
|
|
103
|
+
<h2 id="sim" class="rule-top">把它跑起来</h2>
|
|
104
|
+
<p>
|
|
105
|
+
工具链的成熟度足以支撑一次完整考古:从反汇编、到逐指令模拟、到和原厂手册对照。
|
|
106
|
+
这条路走过一遍之后的结论是——手册里的描述与实现的实际行为在细节上有出入,
|
|
107
|
+
而正是这些出入最能说明当时的工程取舍。
|
|
108
|
+
</p>
|
|
109
|
+
<p class="small">
|
|
110
|
+
目录高亮<strong>统一用 <code>scroll</code> 监听 + <code>requestAnimationFrame</code> 节流</strong>,
|
|
111
|
+
<strong>不依赖 <code>IntersectionObserver</code></strong>。
|
|
112
|
+
早期版本用的是它 + <code>rootMargin</code>,结果滚到两节之间时观察区里
|
|
113
|
+
一个 section 都没有,高亮卡住不动 —— 现在改成纯计算,任何滚动位置都有答案。
|
|
114
|
+
</p>
|
|
115
|
+
</main>
|
|
116
|
+
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<script src="toc.js"></script>
|
|
120
|
+
<script src="nav.js"></script>
|
|
121
|
+
<script>
|
|
122
|
+
/* ---------------------------------------------------------------- 目录高亮 */
|
|
123
|
+
Toc.init({ links: '#toc-list .toc__link', sections: 'main h2[id], main h1[id]' });
|
|
124
|
+
|
|
125
|
+
/* ------------------------------------------------ 抽屉
|
|
126
|
+
行为全部在 nav.js 里(本页只负责写 data-nav)。
|
|
127
|
+
⚠️ 这里曾经抄了 60 行开关逻辑,而抄出来的版本把 aria-hidden
|
|
128
|
+
打在了抽屉的祖先上 ⇒ 抽屉本身对读屏消失。抽成组件后修掉了。 */
|
|
129
|
+
</script>
|
|
130
|
+
</body>
|
|
131
|
+
</html>
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
frontend-lib / 03-patterns / nav / nav.css
|
|
3
|
+
页头 + 长文目录 + 移动端抽屉
|
|
4
|
+
|
|
5
|
+
依赖:01-tokens/tokens.css + 02-primitives/button/button.css
|
|
6
|
+
版本:A ✅ / B ✅ / C ✅
|
|
7
|
+
|
|
8
|
+
配套:toc.js(目录高亮,可降级)
|
|
9
|
+
规范:抽屉的展开/收起见本文件顶部说明
|
|
10
|
+
========================================================================= */
|
|
11
|
+
|
|
12
|
+
/* ============================================================================
|
|
13
|
+
1. 跳到主内容
|
|
14
|
+
=========================================================================
|
|
15
|
+
键盘用户第一个 Tab 就该能跳过整个导航。
|
|
16
|
+
平时移出视口,聚焦时滑入 —— 用 transform 不用 display:none,
|
|
17
|
+
否则它无法被 Tab 聚焦(display:none 会移出 tab 顺序)。 */
|
|
18
|
+
.skip {
|
|
19
|
+
position: absolute;
|
|
20
|
+
top: 0; inset-inline-start: 0;
|
|
21
|
+
z-index: var(--z-toast);
|
|
22
|
+
transform: translateY(-120%);
|
|
23
|
+
background: var(--accent);
|
|
24
|
+
/* 🔴 暗色下 --accent 变亮(#7aa9de),白字会看不清。 */
|
|
25
|
+
color: var(--text-on-accent);
|
|
26
|
+
padding: var(--sp-2) var(--sp-4);
|
|
27
|
+
font-size: var(--fs-sm);
|
|
28
|
+
text-decoration: none;
|
|
29
|
+
transition: transform var(--dur-fast) var(--ease-out);
|
|
30
|
+
}
|
|
31
|
+
.skip:focus { transform: translateY(0); }
|
|
32
|
+
|
|
33
|
+
/* ============================================================================
|
|
34
|
+
2. 页头
|
|
35
|
+
========================================================================= */
|
|
36
|
+
.nav {
|
|
37
|
+
position: sticky;
|
|
38
|
+
top: 0;
|
|
39
|
+
z-index: var(--z-header);
|
|
40
|
+
background: var(--paper);
|
|
41
|
+
border-bottom: 1px solid var(--border-decor);
|
|
42
|
+
}
|
|
43
|
+
.nav__inner {
|
|
44
|
+
display: flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
gap: var(--sp-4);
|
|
47
|
+
max-width: 1040px;
|
|
48
|
+
margin: 0 auto;
|
|
49
|
+
padding: 0 var(--sp-5);
|
|
50
|
+
min-height: 56px; /* 触摸目标不小于 44px,这里是页头整体 */
|
|
51
|
+
}
|
|
52
|
+
.nav__brand {
|
|
53
|
+
/* 🔴 补内边距:移动端实测高度正好 24px,
|
|
54
|
+
卡在 WCAG 2.5.8 的下限上,**没有余量** ——
|
|
55
|
+
换字号/换字体就可能掉到 24px 以下。
|
|
56
|
+
点击区用内边距撑开而不是固定 height:内容变了,触摸目标不会退化。 */
|
|
57
|
+
display: inline-flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
min-height: 44px; /* Apple/Google 建议值;WCAG 2.5.8 下限是 24 */
|
|
60
|
+
padding: var(--sp-2) 0;
|
|
61
|
+
font-size: var(--fs-sm);
|
|
62
|
+
font-weight: 500;
|
|
63
|
+
color: var(--text-primary);
|
|
64
|
+
text-decoration: none;
|
|
65
|
+
white-space: nowrap;
|
|
66
|
+
}
|
|
67
|
+
.nav__brand span { color: var(--text-tertiary); font-weight: 400; }
|
|
68
|
+
|
|
69
|
+
.nav__list {
|
|
70
|
+
display: flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
gap: var(--sp-4);
|
|
73
|
+
list-style: none;
|
|
74
|
+
margin: 0 0 0 auto; /* 靠右 */
|
|
75
|
+
padding: 0;
|
|
76
|
+
}
|
|
77
|
+
.nav__link {
|
|
78
|
+
display: block;
|
|
79
|
+
padding: var(--sp-2) 0;
|
|
80
|
+
font-size: var(--fs-sm);
|
|
81
|
+
color: var(--text-secondary);
|
|
82
|
+
text-decoration: none;
|
|
83
|
+
border-bottom: 2px solid transparent; /* 预留位:选中时下方那条线不推内容 */
|
|
84
|
+
transition: color var(--dur-fast) var(--ease-out),
|
|
85
|
+
border-color var(--dur-fast) var(--ease-out);
|
|
86
|
+
}
|
|
87
|
+
@media (hover: hover) and (pointer: fine) {
|
|
88
|
+
.nav__link:hover { color: var(--text-primary); }
|
|
89
|
+
}
|
|
90
|
+
/* 🔴 当前页指示用 aria-current,不是自定义 class ——
|
|
91
|
+
屏幕阅读器会播报"当前页面",自定义 class 它不知道。 */
|
|
92
|
+
.nav__link[aria-current="page"] {
|
|
93
|
+
color: var(--accent);
|
|
94
|
+
border-bottom-color: var(--accent);
|
|
95
|
+
font-weight: 500;
|
|
96
|
+
}
|
|
97
|
+
.nav__link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
98
|
+
|
|
99
|
+
/* 汉堡:桌面隐藏 */
|
|
100
|
+
.nav__toggle {
|
|
101
|
+
display: none;
|
|
102
|
+
margin-inline-start: auto;
|
|
103
|
+
width: 44px; height: 44px; /* 触摸目标 44px,硬下限 */
|
|
104
|
+
align-items: center; justify-content: center;
|
|
105
|
+
background: none;
|
|
106
|
+
border: 1px solid var(--border-decor);
|
|
107
|
+
border-radius: var(--r-sm);
|
|
108
|
+
cursor: pointer;
|
|
109
|
+
color: var(--text-primary);
|
|
110
|
+
}
|
|
111
|
+
.nav__toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
112
|
+
|
|
113
|
+
/* 三条线:中间那条用 transform 收成箭头,展开时变 X */
|
|
114
|
+
.nav__toggle i {
|
|
115
|
+
display: block;
|
|
116
|
+
width: 18px; height: 1.5px;
|
|
117
|
+
background: currentColor;
|
|
118
|
+
position: relative;
|
|
119
|
+
transition: transform var(--dur-base) var(--ease-out),
|
|
120
|
+
opacity var(--dur-fast) var(--ease-out);
|
|
121
|
+
}
|
|
122
|
+
.nav__toggle i::before,
|
|
123
|
+
.nav__toggle i::after {
|
|
124
|
+
content: "";
|
|
125
|
+
position: absolute;
|
|
126
|
+
inset-inline-start: 0;
|
|
127
|
+
width: 18px; height: 1.5px;
|
|
128
|
+
background: currentColor;
|
|
129
|
+
transition: transform var(--dur-base) var(--ease-out);
|
|
130
|
+
}
|
|
131
|
+
.nav__toggle i::before { top: -5.5px; }
|
|
132
|
+
.nav__toggle i::after { top: 5.5px; }
|
|
133
|
+
|
|
134
|
+
.nav__toggle[aria-expanded="true"] i { transform: rotate(45deg); }
|
|
135
|
+
.nav__toggle[aria-expanded="true"] i::before { transform: translateY(5.5px) rotate(-90deg); }
|
|
136
|
+
.nav__toggle[aria-expanded="true"] i::after { opacity: 0; }
|
|
137
|
+
|
|
138
|
+
/* ============================================================================
|
|
139
|
+
3. 移动端:抽屉
|
|
140
|
+
=========================================================================
|
|
141
|
+
🔴 按 08-状态切换规范:展开/收起**只动 transform**,不动 width/height/top ——
|
|
142
|
+
那样会引起重排,页面会"抖一下"。
|
|
143
|
+
|
|
144
|
+
🔴 抽屉打开时背景必须锁(inert),否则用户能 Tab 到抽屉外面去 ——
|
|
145
|
+
视觉上抽屉是覆盖层,逻辑上却不是模态,两边不一致。 */
|
|
146
|
+
@media (max-width: 48rem) {
|
|
147
|
+
.nav__toggle { display: flex; }
|
|
148
|
+
|
|
149
|
+
.nav__list {
|
|
150
|
+
position: fixed;
|
|
151
|
+
top: 0; inset-inline-end: 0; bottom: 0;
|
|
152
|
+
z-index: var(--z-overlay);
|
|
153
|
+
width: min(280px, 82vw);
|
|
154
|
+
margin: 0;
|
|
155
|
+
padding: var(--sp-7) var(--sp-5) var(--sp-5);
|
|
156
|
+
flex-direction: column;
|
|
157
|
+
align-items: stretch;
|
|
158
|
+
gap: 0;
|
|
159
|
+
background: var(--surface);
|
|
160
|
+
border-inline-start: 1px solid var(--border-decor);
|
|
161
|
+
box-shadow: var(--shadow-2);
|
|
162
|
+
|
|
163
|
+
transform: translateX(100%); /* 收起态:在视口外 */
|
|
164
|
+
transition: transform var(--dur-base) var(--ease-out);
|
|
165
|
+
overflow-y: auto;
|
|
166
|
+
}
|
|
167
|
+
.nav__list[data-state="open"] { transform: translateX(0); }
|
|
168
|
+
|
|
169
|
+
.nav__link {
|
|
170
|
+
padding: var(--sp-3) 0;
|
|
171
|
+
border-bottom: 1px solid var(--border-decor);
|
|
172
|
+
/* 抽屉里用整行色块表示当前页,比 2px 下划线清楚(竖排时) */
|
|
173
|
+
border-bottom-width: 1px;
|
|
174
|
+
}
|
|
175
|
+
.nav__link[aria-current="page"] {
|
|
176
|
+
color: var(--accent);
|
|
177
|
+
font-weight: 500;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.nav__scrim {
|
|
181
|
+
position: fixed;
|
|
182
|
+
inset: 0;
|
|
183
|
+
z-index: var(--z-header); /* 比抽屉低一层 */
|
|
184
|
+
/* 🔴 原来写死 rgba(21,24,28,.4)(深色遮罩)。
|
|
185
|
+
暗色模式下纸底本来就是深的 ⇒ 遮罩与底几乎同色 ⇒ **看不出"有遮罩"**。
|
|
186
|
+
改用令牌,深浅两套各自成立。 */
|
|
187
|
+
background: var(--scrim);
|
|
188
|
+
opacity: 0;
|
|
189
|
+
pointer-events: none;
|
|
190
|
+
transition: opacity var(--dur-base) var(--ease-out);
|
|
191
|
+
}
|
|
192
|
+
.nav__scrim[data-state="open"] { opacity: 1; pointer-events: auto; }
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/* ============================================================================
|
|
196
|
+
4. 长文目录
|
|
197
|
+
========================================================================= */
|
|
198
|
+
.toc {
|
|
199
|
+
/* 容器本身也要有定义 —— 否则 HTML 里的 class="toc" 是个悬空引用。
|
|
200
|
+
refs.py 会抓这种"引用了但没定义"的类。 */
|
|
201
|
+
min-width: 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/* 🔴 sticky 必须**在库里**而不是 demo 里。
|
|
205
|
+
修正:原来这条只写在 demo 的内联 <style> 里,
|
|
206
|
+
于是任何引了 nav.css 的页面都**没有 sticky** ——
|
|
207
|
+
目录会随正文滚出视口,"跟着走"这个最基本的效果没有。
|
|
208
|
+
**布局规则写在 demo 里 = 分层崩了。**
|
|
209
|
+
|
|
210
|
+
偏移量要大于页头高度,否则 sticky 会停在页头下面被遮住。
|
|
211
|
+
窄屏时目录在正文上方,不需要 sticky。 */
|
|
212
|
+
@media (min-width: 60rem) {
|
|
213
|
+
.toc {
|
|
214
|
+
position: sticky;
|
|
215
|
+
top: 76px; /* 页头 56px + 20px 留白 */
|
|
216
|
+
align-self: start; /* 🔴 grid 子项默认 stretch,会让 sticky 无处可动 */
|
|
217
|
+
max-height: calc(100vh - 96px);
|
|
218
|
+
overflow-y: auto; /* 目录比视口高时可滚 */
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
.toc__title {
|
|
222
|
+
font-size: var(--fs-xs);
|
|
223
|
+
color: var(--text-tertiary);
|
|
224
|
+
text-transform: uppercase;
|
|
225
|
+
letter-spacing: 0.1em;
|
|
226
|
+
margin: 0 0 var(--sp-3);
|
|
227
|
+
font-weight: 500;
|
|
228
|
+
}
|
|
229
|
+
.toc__list { list-style: none; margin: 0; padding: 0; }
|
|
230
|
+
/* 🔴 为什么这里保留竖条(0.8.4 · 全库竖条政策)
|
|
231
|
+
它不是装饰竖条,是**当前项指示器**:目录里"你在这一节"由它标记,
|
|
232
|
+
与当前项的文字加重是**两条独立线索** ——
|
|
233
|
+
去掉它,纯色弱 / 低对比场景下当前项就只剩字重变化可辨。
|
|
234
|
+
⚠️ 未选中时是灰调分隔色(--border-decor)、选中时才变强调色(--accent),
|
|
235
|
+
所以它平时就是一条安静的目录导轨,只有当前项会被点亮。 */
|
|
236
|
+
.toc__link {
|
|
237
|
+
display: block;
|
|
238
|
+
padding: var(--sp-1) 0 var(--sp-1) var(--sp-3);
|
|
239
|
+
color: var(--text-tertiary);
|
|
240
|
+
text-decoration: none;
|
|
241
|
+
font-size: var(--fs-xs);
|
|
242
|
+
border-inline-start: 2px solid var(--border-decor);
|
|
243
|
+
white-space: nowrap; /* 目录项换行就乱了 */
|
|
244
|
+
overflow: hidden;
|
|
245
|
+
text-overflow: ellipsis;
|
|
246
|
+
transition: color var(--dur-fast) var(--ease-out),
|
|
247
|
+
border-color var(--dur-fast) var(--ease-out);
|
|
248
|
+
}
|
|
249
|
+
@media (hover: hover) and (pointer: fine) {
|
|
250
|
+
.toc__link:hover { color: var(--text-primary); }
|
|
251
|
+
}
|
|
252
|
+
.toc__link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
253
|
+
/* 🔴 当前节用 aria-current="true"(不是 "location")——
|
|
254
|
+
"true" 表示"在当前范围内当前位置",目录高亮用它是通行做法。 */
|
|
255
|
+
.toc__link[aria-current="true"] {
|
|
256
|
+
color: var(--accent);
|
|
257
|
+
/* 🔴 必须是 border-inline-start-color(逻辑),与 .toc__link 的
|
|
258
|
+
border-inline-start 同侧。写物理 border-left-color 的话 RTL 下会着错边。 */
|
|
259
|
+
border-inline-start-color: var(--accent);
|
|
260
|
+
font-weight: 500;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* ============================================================================
|
|
264
|
+
reduced-motion
|
|
265
|
+
=========================================================================
|
|
266
|
+
抽屉的位移动画对前庭功能障碍患者是有刺激的 ⇒ 关掉,
|
|
267
|
+
但保留遮罩的 opacity 过渡(无刺激,且能交代"挡住了")。
|
|
268
|
+
========================================================================= */
|
|
269
|
+
@media (prefers-reduced-motion: reduce) {
|
|
270
|
+
.nav__list, .nav__toggle i, .nav__toggle i::before, .nav__scrim {
|
|
271
|
+
transition: opacity var(--dur-fast) linear;
|
|
272
|
+
transform: none;
|
|
273
|
+
}
|
|
274
|
+
.nav__toggle[aria-expanded="true"] i { transform: none; }
|
|
275
|
+
.nav__toggle[aria-expanded="true"] i::before { transform: none; }
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* 🔴 这两条**必须**带断点。抽屉的"收起态"靠 translateX(100%) 移出视口,
|
|
279
|
+
动画被关掉后得有东西撑着它;但曾经写在**无断点**的 reduced-motion 段里
|
|
280
|
+
⇒ 开启「减少动态效果」的桌面用户,顶部导航整体飞出屏幕右侧
|
|
281
|
+
(实测 1440 视口 scrollWidth 1440 → 1512 = 列表自身宽度),菜单直接消失。
|
|
282
|
+
默认环境下截图看不到它,只有 emulateMedia({reducedMotion:'reduce'}) 才暴露。
|
|
283
|
+
⭐ 教训:「关掉动画」不能顺手把布局也关掉。 */
|
|
284
|
+
@media (prefers-reduced-motion: reduce) and (max-width: 48rem) {
|
|
285
|
+
.nav__list { transform: translateX(100%); } /* 收起态:仍在视口外 */
|
|
286
|
+
.nav__list[data-state="open"] { transform: translateX(0); }
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/* ============================================================================
|
|
290
|
+
反模式
|
|
291
|
+
=========================================================================
|
|
292
|
+
1. 抽屉展开时动 width / left / top
|
|
293
|
+
⇒ 引起重排,页面抖一下。只该动 transform。
|
|
294
|
+
|
|
295
|
+
2. 抽屉打开后背景仍可 Tab / 可点
|
|
296
|
+
视觉上是覆盖层,逻辑上不是模态,两边不一致。
|
|
297
|
+
打开时给背景加 inert。
|
|
298
|
+
|
|
299
|
+
3. 汉堡按钮小于 44px
|
|
300
|
+
触摸目标是硬下限(WCAG 2.5.8 要 24px,但 44 是实践标准)。
|
|
301
|
+
|
|
302
|
+
4. 当前页指示用自定义 class 而不是 aria-current
|
|
303
|
+
屏幕阅读器不知道,用户失去"我在哪"。
|
|
304
|
+
|
|
305
|
+
5. 目录项允许换行
|
|
306
|
+
换行会让行高跳变,目录看着散。截断(ellipsis)。
|
|
307
|
+
|
|
308
|
+
6. 目录高亮在不支持 IntersectionObserver 时就整个不做
|
|
309
|
+
目录会变成一堆"点得动但看不出当前位置"的死链接。
|
|
310
|
+
scroll 监听,体验降级但功能不消失。
|
|
311
|
+
|
|
312
|
+
7. 页头 sticky 但没给背景色
|
|
313
|
+
内容会从页头下面透出来,看着像重影。
|
|
314
|
+
========================================================================= */
|