transition需作用于可动画属性,如border-color、box-shadow;outline不支持过渡,display不可过渡;:focus与:focus-visible应分开处理;推荐时长0.15s–0.25s;移动端需用JS模拟focus状态。

transition 属性必须作用于可变化的 CSS 属性上
只写 transition: all 0.3s ease 不一定生效——浏览器只会对「实际发生变更」且「支持过渡」的属性做动画。比如 outline 默认不参与过渡,display 完全不可过渡,而 border-color、background-color、transform 等可以。
焦点变化(:focus / :focus-visible)常涉及以下属性,需显式声明:
-
border-color、box-shadow:最常用,视觉反馈强 -
outline:需先用outline: none清除默认,再自定义(否则 outline 不触发 transition) -
transform:适合微位移或缩放,比修改 layout 更高效 - 避免用
height、width、opacity做焦点过渡——它们可能引发重排或语义模糊
:focus 和 :focus-visible 的过渡要分开处理
:focus 在所有获得焦点时触发(包括鼠标点击),:focus-visible 仅在键盘导航时生效。若统一加 transition,鼠标点击后又用键盘操作,可能出现「过渡未重置」的卡顿。
推荐写法是:基础状态设过渡,伪类里只改值,不重复声明 transition:
立即学习“前端免费学习笔记(深入)”;
button {
border: 2px solid #ccc;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
button:focus {
border-color: #007bff;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
}
button:focus-visible {
outline: 2px solid #007bff;
outline-offset: 2px;
}
注意:outline 本身不支持 transition,所以 :focus-visible 中只设样式,不依赖动画;真正平滑的是 border-color 和 box-shadow 那部分。
transition-duration 太短或太长都会破坏体验
0.1s 以下人眼几乎无法识别变化,0.4s 以上容易让人感觉延迟。实测下来,0.15s–0.25s 是焦点反馈的黄金区间:
- 表单控件(
input、textarea)建议0.2s:兼顾响应感与柔和度 - 按钮类交互建议
0.18s:稍快,匹配点击节奏 - 避免用
transition: all 0.3s cubic-bezier(...)—— all 会把没变的属性也纳入计算,增加渲染负担
移动端 focus 状态可能不触发,得兼容 touch
iOS Safari 和部分 Android 浏览器在非可编辑元素上点击不会触发 :focus,除非该元素有 tabindex。更稳妥的方式是结合 JavaScript 监听 focusin / focusout,动态加 class:
element.addEventListener('focusin', () => element.classList.add('is-focused'));
element.addEventListener('focusout', () => element.classList.remove('is-focused'));
然后用 .is-focused 替代 :focus 写 transition 规则。这样既绕过 UA 差异,又能精准控制过渡起点。
真正难的不是写 transition,而是判断哪些属性变、何时变、在哪个设备上变——过渡只是表象,背后是焦点管理逻辑的完整性。










