htmx CSS 生命周期类
htmx 在 DOM 更新过程中,会在目标元素上短暂地添加和移除 CSS 类,通过监听这些类就能实现动画效果:
hx-swap 中 settle 时间结束。/* 旧内容淡出:在 swap 之前 */
.htmx-swapping {
opacity: 0;
transition: opacity 0.3s ease;
}
/* 新内容淡入:在 settle 期间 */
.htmx-settling {
opacity: 0;
}
/* settle 结束后(类被移除)才恢复 opacity:1 */
.htmx-settling > * {
transition: opacity 0.3s ease;
}
/* 新添加的列表项滑入 */
.htmx-added {
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(-20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
配合 hx-swap 时序修饰符
<!-- 旧内容淡出 300ms,然后换入新内容,新内容再有 settle 动画 -->
<div
hx-get="/api/content"
hx-swap="innerHTML swap:300ms settle:200ms"
hx-target="#content-area"
>
刷新内容
</div>
<div id="content-area">当前内容</div>
<!-- CSS 配合 -->
<style>
#content-area.htmx-swapping {
opacity: 0;
transition: opacity 300ms ease;
}
#content-area.htmx-settling {
opacity: 0;
transition: opacity 200ms ease;
}
</style>
View Transitions API
View Transitions API 是浏览器原生提供的页面过渡 API,Chrome 111+ 支持。htmx 可以通过配置使用它:
<!-- 方式1:全局启用 View Transitions -->
<meta name="htmx-config" content='{"globalViewTransitions": true}'/>
<!-- 方式2:单个请求启用 -->
<button
hx-get="/api/content"
hx-target="#main"
hx-swap="innerHTML transition:true"
>
带动画切换
</button>
/* View Transitions 动画定义 */
::view-transition-old(root) {
animation: fade-and-slide-out 0.3s ease forwards;
}
::view-transition-new(root) {
animation: fade-and-slide-in 0.3s ease forwards;
}
@keyframes fade-and-slide-out {
to { opacity: 0; transform: translateY(-10px); }
}
@keyframes fade-and-slide-in {
from { opacity: 0; transform: translateY(10px); }
}
/* 为特定元素指定单独的过渡 */
.hero-title {
view-transition-name: hero-title;
}
::view-transition-old(hero-title),
::view-transition-new(hero-title) {
animation-duration: 0.5s;
}
常用动画模式
模式1:列表项删除动画
<style>
.item.deleting {
animation: fadeOut 0.3s ease forwards;
}
@keyframes fadeOut {
to { opacity: 0; transform: translateX(20px); height: 0; padding: 0; margin: 0; }
}
</style>
<!-- 点击删除:先播放动画,再发出请求 -->
<div class="item">
列表项内容
<button
hx-delete="/api/items/1"
hx-target="closest .item"
hx-swap="outerHTML swap:300ms"
onclick="this.closest('.item').classList.add('deleting')"
>
删除
</button>
</div>
模式2:骨架屏加载
@keyframes shimmer {
to { background-position: 200% center; }
}
.skeleton {
background: linear-gradient(
90deg,
var(--surface) 25%,
var(--surface-2) 50%,
var(--surface) 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
border-radius: 4px;
height: 1em;
}
<!-- 初始显示骨架屏,内容加载后替换 -->
<div
hx-get="/api/article"
hx-trigger="load"
hx-swap="outerHTML"
>
<!-- 骨架屏占位 -->
<div class="skeleton"></div>
<div class="skeleton" style="width:80%;margin-top:8px"></div>
<div class="skeleton" style="width:60%;margin-top:8px"></div>
</div>
模式3:乐观更新 + 错误回滚
<div id="like-section">
<span id="like-count">42</span> 个赞
<button
id="like-btn"
hx-post="/api/posts/1/like"
hx-target="#like-count"
hx-swap="outerHTML"
onclick="optimisticLike(this)"
>
👍 点赞
</button>
</div>
<script>
function optimisticLike(btn) {
const countEl = document.getElementById('like-count');
const originalCount = countEl.textContent;
// 立即显示 +1(乐观更新)
countEl.textContent = parseInt(originalCount) + 1;
btn.disabled = true;
// 如果请求失败,回滚
btn.addEventListener('htmx:responseError', function() {
countEl.textContent = originalCount;
btn.disabled = false;
}, { once: true });
}
</script>
_hyperscript:htmx 的脚本搭档
_hyperscript 是与 htmx 同作者创建的轻量级脚本语言,用自然语言风格编写行内交互逻辑,弥补纯 CSS 无法实现的场景:
<!-- 引入 _hyperscript -->
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
<!-- 点击后 300ms 淡出,然后删除 -->
<div
_="on click add .fade-out then wait 300ms then remove me"
style="transition: opacity 0.3s"
>
点我消失
</div>
<!-- 切换 class -->
<button _="on click toggle .active on #sidebar">
切换侧边栏
</button>
<!-- htmx + _hyperscript 组合:先动画再发请求 -->
<button
hx-delete="/api/items/5"
hx-target="closest .item"
hx-swap="outerHTML swap:400ms"
_="on htmx:beforeRequest add .deleting to closest .item"
>
删除
</button>
如果只需要简单的 class 切换、显示/隐藏、等待再执行等操作,_hyperscript 比 JavaScript 代码更简洁。对于复杂交互(API 调用、状态管理、复杂算法),还是应该使用常规 JavaScript。两者可以自由混用。
过渡动画与 CSS 集成的核心要点:① htmx 在 swap 过程中自动添加三个 CSS 类——htmx-swapping(移除旧内容前)、htmx-settling(新内容插入后稳定前)、htmx-added(新元素进场),利用这些类可以写纯 CSS 过渡;② hx-swap 的 swap:200ms settle:100ms 参数控制各阶段等待时间,必须大于 CSS transition 时长;③ View Transitions API 通过 htmx.config.globalViewTransitions = true 全局开启,或 transition:true 单个元素开启,实现 SPA 级别的页面切换动画(仅 Chrome 支持);④ 删除动画的正确做法是先加 .removing class 触发 CSS 出场动画,再用 htmx:afterRequest 确认删除成功;⑤ _hyperscript 用 _="on click add .active" 等超自然语言表达简单 DOM 操作,与 htmx 属性共存;⑥ CSS @keyframes 结合 htmx-added 类实现列表新增条目的淡入效果;动画时间 150-300ms 是用户体验最佳区间。