正在加载...

CSS 无障碍

布局、动效和现代工具你已经会用了。CSS 里的无障碍是人们能感受到的那一层:键盘焦点在哪里看得见吗?文字读得清吗?转圈动画会不会让人不适?这节课不是 HTML 大杂烩(地标、alt、ARIA)。这里讲的是让焦点、对比度和动效能用起来的样式习惯。

焦点必须看得见

键盘用户用 Tab 在链接和控件间移动。焦点环消失了,他们就迷路了。优先用 :focus-visible:鼠标点击保持安静,键盘焦点保持醒目:

Visible keyboard focus with :focus-visible

css
:root {
--focus-ring: #2563eb;
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
outline: 3px solid var(--focus-ring);
outline-offset: 3px;
}

.text-link:focus:not(:focus-visible) {
outline: none;
}

:focus-visible 对准那些焦点环真正有帮助的场景(通常是键盘)。配上高对比环,并加一点 outline-offset,避免和边框撞在一起。

没有替代方案就别写 outline: none

去掉默认 outline 只有在你提供了更清晰的自定义焦点样式时才可以。光秃秃的 *:focus { outline: none; } 是经典陷阱:

Replace outline — do not erase focus

css
/* Bad: keyboard users lose the only cue */
.bad-button:focus {
outline: none;
}

/* Good: custom ring that still shows focus */
.good-button:focus-visible {
outline: none;
box-shadow: 0 0 0 3px #fff, 0 0 0 6px #0f766e;
}

如果你关掉了浏览器 outline,就必须用别的东西标出当前焦点控件——box-shadow、边框颜色,或在任何主题下都仍然明显的背景变化。

对比度是 CSS 的选择

品牌色在设计板上很锐利,在阳光下的手机上却发糊。把前景 / 背景色对当成无障碍决策,而不只是装饰:

Contrast-safe text and surface tokens

css
:root {
--surface: #0f172a;
--text: #f8fafc;
--muted: #cbd5e1;
--accent: #38bdf8;
--accent-text: #0c4a6e;
}

.hero {
background: var(--surface);
color: var(--text);
}

.hero .lede {
color: var(--muted);
}

.hero .cta {
background: var(--accent);
color: var(--accent-text);
font-weight: 700;
}

正文和按钮要追求强对比。装饰性灰色可以软一点用在次要标签上,但主文案和控件必须可读。上线配色前,用对比度检查工具核对色对。

尊重减少动效

动画和大变换可能引起不适。把非必要动效包进 prefers-reduced-motion:

Gate motion with prefers-reduced-motion

css
.banner {
transition: transform 0.4s ease, opacity 0.4s ease;
}

.banner.is-shown {
transform: translateY(0);
opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
.banner,
.banner.is-shown {
transition: none;
transform: none;
}

.spinner {
animation: none;
}
}

在系统里选择减少动效的用户仍应看到最终界面状态——只是没有过程。保留必要的透明度或布局变化;去掉循环旋转和大滑动。

高对比与 forced-colors

有些环境会覆盖你的调色板(Windows 高对比度 / forced-colors)。弱化脆弱装饰,保留真实边框:

Stay usable under forced-colors

css
.card {
border: 1px solid #e2e8f0;
background: #fff;
box-shadow: 0 8px 24px rgb(15 23 42 / 12%);
}

@media (forced-colors: active) {
.card {
border: 1px solid CanvasText;
background: Canvas;
box-shadow: none;
color: CanvasText;
}

.card a {
color: LinkText;
}
}

Canvas、CanvasText、LinkText 这类系统颜色关键字,能在颜色由用户——而不是品牌手册——决定时,让控件仍然可见。

CSS 侧清单

📊 CSS accessibility habits

Practice CSS habit Avoid
Keep focus findable :focus-visible + strong ring / shadow outline: none with no replacement
Readable type High-contrast text/background tokens Light grey on white for body copy
Kind motion @media (prefers-reduced-motion: reduce) Endless spins for everyone
Survive high contrast Real borders; forced-colors tweaks Shadow-only “edges”
Reachable controls Comfortable padding / hit area Tiny icon-only targets with no focus style

地标、标签和 alt 文本仍归 HTML。CSS 负责的是:样式化之后,这些控件是否仍然可感知。

跳过链接与 focus-within

跳过链接(skip link)可越过重复的页眉导航。把它做成聚焦时才出现。:focus-within 也能在子元素获得焦点时高亮整个组:

Skip link + focus-within group

css
.skip-link {
position: absolute;
left: 1rem;
top: -3rem;
padding: 0.5rem 0.75rem;
background: #111827;
color: #fff;
border-radius: 0.375rem;
z-index: 20;
}

.skip-link:focus-visible {
top: 1rem;
outline: 3px solid #fbbf24;
outline-offset: 2px;
}

.nav:focus-within {
box-shadow: inset 0 0 0 2px #2563eb;
}

跳过链接在未聚焦时留在屏幕外,聚焦后变得醒目。当 Tab 落到栏内子链接时,导航环能提供提示。

自己动手试

  1. 给链接和按钮加上 :focus-visible 环;用 Tab 浏览页面,确认焦点始终可见。
  2. 挑一对低对比色,用更深的文字或更深的表面修好。
  3. 把某个 transition 或 animation 包进 prefers-reduced-motion: reduce,并切换系统设置(或 DevTools 模拟)。
  4. 在 forced-colors 模拟下确认卡片仍有真实边框。
  5. 做一个仅在键盘聚焦时出现的跳过链接样式。

常见错误

  • 全局 outline: none(或 outline: 0)却没有自定义焦点样式
  • 漂亮但正文和主按钮对比度不达标的品牌色
  • 人人都看大动画,却没有 prefers-reduced-motion 闸门
  • 只用 opacity: 0 隐藏仍可 Tab 到的可聚焦控件
  • 把这节 CSS 课当成语义 HTML 与 ARIA 的完整替代

小结

  • 保持键盘焦点可见——优先 :focus-visible,没有更强提示就不要抹掉 outline
  • 把颜色对比度当作文字和控件的硬性要求
  • 遵守 prefers-reduced-motion,并为 forced-colors 加固样式
  • 为跳过链接写样式,并在组需要共同提示时使用 :focus-within
  • 下一课:CSS 小结与下一步(summary)——在小项目前收束整门课

🧠 测试您的知识

准备开始

测试您的知识

通过这个互动测验挑战自己,看看你对这个主题的理解程度如何

❓
7
问题
🎯
70%
及格要求
♾️
∞
时间
🔄
∞
尝试次数

📝 说明

  • 仔细阅读每个问题
  • 为每个问题选择最佳答案
  • 您可以随时重新参加测验
  • 您的进度将显示在顶部