输入关键词,开始搜索

↑↓ 选择↵ 打开esc 关闭
沉浸

无障碍与动效

无障碍与动效

这一章讲主题在键盘操作和动画上的行为。这些默认就已启用,不需要配置,但如果你要改样式或写新组件,得知道它们存在,免得不小心破坏掉。

键盘可达性

焦点环

用键盘 Tab 浏览时,当前聚焦的元素会有一圈强调色描边。规则定义在 src/styles/utilities/a11y.css:

CSS
:where(a, button, summary, input, select, textarea, [tabindex]):focus-visible {    outline: 2px solid var(--accent-color);    outline-offset: 2px;    border-radius: var(--radius-xs);}

用 :where() 包住是为了把优先级压到 0,你的组件想覆盖它随时可以,不需要 !important。

用的是 :focus-visible 而不是 :focus,所以鼠标点击不会出现描边,只有键盘操作才显示。

写组件时别裸用 outline: none

如果你为了去掉浏览器默认描边写了 outline: none,键盘用户就看不到焦点在哪了。正确做法是去掉默认的同时补回 :focus-visible 的:

CSS
.my-input {    outline: none;   /* 去掉鼠标点击时的描边 */} .my-input:focus-visible {    outline: 2px solid var(--accent-color);    outline-offset: 2px;}

跳过导航

每个页面的第一个可聚焦元素是一个「跳到主要内容」链接,平时藏在视口外,按 Tab 才滑出来。点它直接跳到正文,不用一路 Tab 穿过整个侧边栏。

正文容器都带 id="main-content"。如果你新建了布局,记得给主内容区加上这个 id,并在 <body> 开头放上跳转链接:

Astro
<body>    <a class="skip-link" href="#main-content">{t.a11y.skipToContent}</a>    <!-- ... -->    <main id="main-content">        <slot />    </main></body>

标题锚点

文章里的 h2 到 h4 标题末尾都有一个锚点链接,平时透明,鼠标悬停或键盘聚焦时才出现,点了可以复制那一节的地址。

这是 src/plugins/rehype-heading-anchors.mjs 自动加的,不需要在 Markdown 里做任何事。

动效

减少动态效果

系统里开启了「减少动态效果」的用户(macOS 的辅助功能设置、Windows 的动画设置),会自动关掉装饰性动画:滚动显现、页面转场、悬停缩放、循环动画、平滑滚动,全部停掉。

实现在 src/styles/animations.css 末尾的 @media (prefers-reduced-motion: reduce) 块里。它同时保证内容仍然可见——滚动显现的元素直接落到终态,不会因为动画被关掉而一片空白。

写新动画时不用单独处理,那个块用通配选择器覆盖了所有元素。

动效尺度

主题的动效遵循一个原则:运动量和元素大小成反比。小图标可以放大 10%,一张几百像素宽的卡片放大 4% 就已经很明显了。

现成的时长 token 在 src/styles/base/tokens.css:

Token值用在哪
--duration-fast150ms悬停变色、小图标
--duration-base200ms卡片抬升、展开收起
--duration-slow300ms页面级转场、弹窗

参考幅度:小图标 scale(1.06),卡片 translateY(-4px),图片 scale(1.03)。

按压反馈

按钮按下时会缩到 97%,链接则不缩放——整块卡片链接或正文里的文字链接如果跟着缩,视觉上会很怪,文字还会发虚。

可点击的卡片有完整的「抬起—按下」反馈:悬停抬升 4px,按下回落原位。给卡片加 card-interactive 类即可:

Astro
<div class="card-interactive hover:-translate-y-1 hover:shadow-md">    <!-- ... --></div>
transition 是简写属性,会互相覆盖

如果同一个元素上有多个类都写了 transition,后面的那条会把前面的整个重置掉,而不是叠加。

主题里的卡片常常同时带 reveal(滚动显现)和 card-interactive(悬停抬升),两者要过渡的属性不同。animations.css 里为此单独写了一条 .reveal.card-interactive 把四个属性合并声明。

你给元素加多个带 transition 的类时,注意同样的问题。

浮层层级

右下角的浮动元素(回到顶部、音频播放器、移动端目录按钮)用共享槽位排列,不会互相遮挡。槽位定义在 src/styles/utilities/floating-stack.css:

CSS
.floating-slot-1 { bottom: var(--floating-slot-1); }   /* 最靠近角落 */.floating-slot-2 { bottom: var(--floating-slot-2); }.floating-slot-3 { bottom: var(--floating-slot-3); }

新增浮动元素时挑一个没被占用的槽位,不要另写 bottom 值。

跨组件的层级同样有 token,从 --z-raised(10)到 --z-lightbox(300),定义在 tokens.css。不要再写 z-index: 9999。

未知标题
00:00
00:00
播放列表