
本文介绍如何使用纯 JavaScript 实现“首项默认展开、悬停其他项时自动收起”的交互效果,解决 CSS 邻居选择器(~)导致的过渡动画卡顿问题,确保宽度/高度变化具备流畅的 transition 支持。
本文介绍如何使用纯 javascript 实现“首项默认展开、悬停其他项时自动收起”的交互效果,解决 css 邻居选择器(`~`)导致的过渡动画卡顿问题,确保宽度/高度变化具备流畅的 `transition` 支持。
在响应式协作板块中,常需突出展示一个主入口(如“Participate”),使其默认以扩展状态(更大尺寸 + 更高优先级)呈现;而当用户将鼠标移至其他选项(如“Explore”或“Submit”)时,主项应平滑收缩回常规尺寸,避免布局跳变。纯 CSS 方案虽可借助 :hover ~ .active 实现显隐控制,但因 display: none 会中断 transition(CSS 过渡无法在 display 变化时生效),导致动画生硬甚至失效。
推荐方案:纯 JavaScript + class 切换 + CSS 过渡
核心思路是避免 display 切换,改用尺寸与间距的 CSS 类控制,并通过 JS 动态添加/移除 .active 类来触发过渡动画:
✅ 优势:
立即学习“Java免费学习笔记(深入)”;
- 完全兼容 transition: all 0.4s ease
- 不依赖 DOM 顺序限制(CSS ~ 选择器要求目标元素必须在触发元素之后)
- 可精准控制多个目标元素(如同时收起 .active-collab 并显示 .submit)
✅ 正确实现步骤
1. HTML 结构优化(语义清晰 + 类名统一)
<div class="collab-container">
<div class="collab-item participate active">
<div class="homepage-content">
<div class="homepage-title"><p>Participate in<br /></p></div>
<div class="info-hover"><p>…</p></div>
</div>
</div>
<div class="collab-item explore not-active">
<div class="homepage-content">
<div class="homepage-title"><p>Explore<br />Co-Creation…</p></div>
<div class="info-hover"><p>…</p></div>
</div>
</div>
<div class="collab-item submit not-active">
<div class="homepage-content">
<div class="homepage-title"><p>Become part of a<br />global network</p></div>
<div class="info-hover"><p>…</p></div>
</div>
</div>
</div>⚠️ 注意:.active 类初始赋予首个元素;其余项统一加 .not-active 便于 JS 绑定事件。
2. 关键 CSS(启用 transition + 定义 active 状态)
.collab-item {
position: relative;
overflow: hidden;
display: inline-block;
width: 25%;
height: 419px;
background-color: green;
margin-right: 10px;
vertical-align: top;
transition: all 0.4s ease; /* ✅ 必须作用于基础类 */
}
/* 扩展状态:仅通过 class 控制,不依赖 :hover */
.active {
width: 32%;
height: 482px;
margin-right: 1%;
}
.collab-item:hover .info-hover,
.active .info-hover {
display: inline-block;
}
.info-hover {
position: absolute;
bottom: 0;
width: 100%;
padding: 15px;
display: none; /* ❗仍保留,但由 active 类激活 */
}3. 纯 JavaScript 控制逻辑(无框架、兼容性好)
// 获取所有非默认项(即需要触发收起动作的元素)
const triggerItems = document.querySelectorAll('.collab-item.not-active');
// 获取默认展开项(主项)
const defaultItem = document.querySelector('.collab-item.active');
triggerItems.forEach(item => {
// 鼠标进入:收起主项
item.addEventListener('mouseenter', () => {
defaultItem.classList.remove('active');
});
// 鼠标离开:恢复主项(可选:增强体验,避免意外残留收缩)
item.addEventListener('mouseleave', () => {
// 可选:仅当鼠标未移入其他 trigger 时才恢复(进阶防抖)
setTimeout(() => {
if (!document.querySelector('.collab-item.not-active:hover')) {
defaultItem.classList.add('active');
}
}, 100);
});
});? 注意事项与最佳实践
- 避免 display: none 干预过渡:所有尺寸变化必须通过 width/height/margin 等可过渡属性完成,禁用 display 切换。
- transition 必须写在基础类上:如 .collab-item,而非仅 .active,否则初始状态无过渡。
- 移动端适配:mouseenter/mouseleave 在触摸设备上不触发,生产环境建议补充 touchstart 事件或改用点击切换。
-
性能优化:若元素较多,可使用事件委托替代 forEach 绑定:
document.querySelector('.collab-container').addEventListener('mouseenter', e => { if (e.target.classList.contains('not-active')) { defaultItem.classList.remove('active'); } });
通过该方案,你既能保留 CSS 过渡的丝滑感,又能获得 JS 级别的精确控制力——无需 jQuery,不依赖特定 DOM 顺序,真正实现专业级交互体验。


















