glitch效果必须用伪元素而非直接动画文字,因真文字位移会破坏可访问性与seo;::before/::after为纯装饰层,主文字正常显示,伪元素复制content: attr(data-text)并分染红青色,通过steps(1,end)阶梯动画、错时偏移及像素级适配实现真实故障感。

glitch效果为什么必须用伪元素而不是直接动画文字
因为真文字加位移会破坏可访问性(屏幕阅读器读不到错位内容),也影响SEO;而::before和::after是纯装饰层,不干扰语义。直接对h1本身加transform再叠text-shadow,视觉上像glitch,但实际没“撕裂感”——真正的故障风需要两层错位文本轻微偏移+颜色分离+时间差闪动。
怎么用::before和::after复刻经典红蓝错位glitch
核心思路:主文字正常显示,伪元素复制内容、分别染成#ff0055(红)和#00ffff(青),再用animation让它们在x轴随机偏移+短暂闪现。
- 必须给伪元素设
content: attr(data-text),配合HTML里写data-text="Error",避免内容重复写两次 -
position: absolute且z-index要低于主文字,否则盖住原字 - 动画关键帧里用
translateX(calc(var(--tx, 0) * 1px))比固定px值更易调控偏移幅度 - 红层动画延迟
0.05s,青层延迟0.1s,制造“不同步故障”感
h1 { position: relative; font-family: monospace; } h1::before, h1::after { content: attr(data-text); position: absolute; top: 0; left: 0; } h1::before { color: #ff0055; animation: glitch-red 3s infinite; } h1::after { color: #00ffff; animation: glitch-cyan 3s infinite; } <p>@keyframes glitch-red { 0% { transform: translateX(0); } 20% { transform: translateX(-5px); } 40% { transform: translateX(3px); } 60% { transform: translateX(-2px); } 80% { transform: translateX(4px); } 100% { transform: translateX(0); } }
为什么animation-timing-function不能用ease或linear
glitch不是平滑过渡,是突然跳变+卡顿。用cubic-bezier(0.2, 0.8, 0.4, 1)这类缓动会让偏移“软着陆”,失去故障的生硬感。真正有效的做法是:
- 用
steps(1, end)强制帧间无过渡,比如animation: glitch-red 0.5s steps(1, end) infinite - 或者在关键帧里用
0%, 19% { transform: ... }和20%, 39% { transform: ... }这种“阶梯式”写法,逼出跳变 - 避免
animation-fill-mode: forwards——glitch必须归零,否则最后停在偏移态,就变成“歪标题”而不是“故障瞬间”
移动端适配和性能隐患在哪
伪元素glitch在ios safari上容易触发重绘卡顿,尤其字体大、动画快时。不是所有设备都扛得住每秒10次transform变化。
立即学习“前端免费学习笔记(深入)”;
- 加
will-change: transform到伪元素上,提前通知浏览器要动的是位置 - 用
@media (prefers-reduced-motion: reduce)关掉动画,否则可能引发眩晕 - 别用
font-weight: 900配glitch——粗字+错位=糊成一团,选font-weight: 600或等宽字体更清晰 - 如果用在导航栏里,确保
h1有足够line-height,否则伪元素偏移后可能被父容器overflow: hidden裁掉
真正难调的不是动效本身,是让红/青两层在各种DPR下都对得上像素——有时translateX(2px)在2x屏上其实是4物理像素,偏移就过猛了。这时候得用transform: translateX(calc(2px * 0.5))反向缩放,或者干脆用vw单位保相对精度。