Files
Notes/src/styles/10-a11y.css
2026-10-16 16:34:15 +08:00

76 lines
3.1 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ===========================================================================
a11y 工具类:skip link + prefers-reduced-motion
自动从 src/styles.css 拆分(Stage 4a)
=========================================================================== */
/* ---------- skip link (Phase M) ----------
键盘用户 Tab 时第一站直达主内容(#viewer-main),跳过 9 个工具栏按钮 +
侧栏若干入口 + 排序切换。
- 默认视觉隐藏(不占布局、不抢 mouse 焦点),focus 时滑出右上角
- 用 `:focus-visible` 而非 `:focus`:鼠标点击不触发(避免每次点击
主页都闪一下右上角)
- z-index 高于 toolbar(toolbar 顶层 100),保证焦点环可见
*/
.skip-link {
position: absolute;
top: 8px;
right: 8px;
z-index: 1000;
padding: 8px 14px;
background: var(--accent, #4f8cff);
color: #fff;
text-decoration: none;
border-radius: 6px;
font-size: var(--fs-sm);
font-weight: 500;
/* 默认视觉隐藏但保留可访问性 —— 用 transform 移到屏外,不影响
屏幕阅读器在第一个 Tab 焦点候选里看到它 */
transform: translateY(-200%);
transition: transform 120ms ease-out;
}
.skip-link:focus,
.skip-link:focus-visible {
transform: translateY(0);
outline: 2px solid #fff;
outline-offset: 2px;
}
/* skip link target —— #viewer-main 拿到焦点时去掉默认 outline
(它是"已抵达目的地"的反馈,不是交互元素),但保留 SR focus 语义 */
.viewer:focus,
.viewer:focus-visible {
outline: none;
}
/* ---------- prefers-reduced-motion ----------
关掉持续脉冲 (dirty-pulse / halo / ai-pulse) 与一次性入场动画
(modal / toast / ai-diff / ai-chat / outline-slide)。
用 0.01ms 而非 0 / animation: none:保留渲染状态(toast/modal 还要显示),
只是让用户「感知不到」动画过程。
兜底使用 * 选择器覆盖未来新增 keyframes,避免遗漏。
关键修复:去掉 `transition-duration: 0.01ms !important` —— 之前 blanket 会
杀掉所有 hover/focus 过渡(按钮悬停高亮、tab 切换、focus 环),让前庭敏感
用户失去所有交互反馈(与禁用动画的初衷相反)。
transition 是「用户主动操作触发的短暂反馈」(平均 120ms),不是「持续脉冲」
这类持续性刺激;前者对前庭敏感用户基本无害,后者才是真正需要关的。
见 [[feedback-ui-detail-polish]] —— 体验与无障碍要兼顾。
*/
@media (prefers-reduced-motion: reduce) {
.btn-icon.is-dirty,
.btn-icon-text.is-dirty { animation: none; }
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-delay: 0 !important;
}
/* 阅读进度条是 width 过渡(非 animation),上面的 .01ms 规则收不掉它。
关掉过渡让进度"瞬切",避免每帧滚动触发持续的位置变化动画(前庭敏感用户)。 */
.reading-progress-bar { transition: none; }
/* 代码块复制按钮的 hover/active 颜色过渡 + 按下缩放也一并收掉 */
.code-copy-fab { transition: none; }
.code-copy-fab:active { transform: none; }
}