You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决mouseover/mouseleave触发多步动画的二次hover卡顿问题

问题描述

我编写了如下代码,实现了由mouseover和mouseleave事件触发的多步动画效果:

HTML代码

<body>
  <a class="one link" href="#a-propos">
  <span>about</span>
  <div class="up"></div>
  <div class="down"></div>
  </a>
</body>

CSS代码

body{
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

.notransition{
  transition: none !important;
}

a{
  color: black;
  text-decoration: none;
  display: block;
  position: relative;
}

a:hover{
  color: white;
}
span{
  display: block;
  width: 100%;
  height: 100%;
  z-index: 1;
  position: relative;
  transition: all 0.3s ease-in-out;
}

.up{
   display: block;
   width: 0;
   height: calc(50% + 10px);
   border-radius: 0 10px 0 0;
   position: absolute;
   background-color: blue;
   transition: width 0.5s cubic-bezier(0.165, 0.84, 0.44, 1);
   transform-origin: left;
   top: -10px;
   left: -15px;
   opacity: 0;
}
.down{
   display: block;
   width: 0;
   height: calc(50% + 10px);
   border-radius: 0 0 0 10px;
   position: absolute;
   background-color: red;
   transition: width 0.5s cubic-bezier(0.165, 0.84, 0.44, 1);
   transform-origin: right;
   bottom: -10px;
   right: -15px;
   opacity: 0;
}

.hovered .up{
  width: calc(100% + 20px);
  opacity: 1;
}
.hovered.leaved{
  pointer-events: none;
}

.hovered.leaved .up{
  opacity: 0;
  top: -30px;
  transition: opacity 0.5s cubic-bezier(0.165, 0.84, 0.44, 1), top 0.5s cubic-bezier(0.165, 0.84, 0.44, 1), height 0.5s cubic-bezier(0.165, 0.84, 0.44, 1);          
}
.hovered .down{
  width: calc(100% + 20px);
  opacity: 1;
}

.hovered.leaved .down{
  opacity: 0;
  bottom: -30px;
  transition: opacity 0.5s cubic-bezier(0.165, 0.84, 0.44, 1), top 0.5s cubic-bezier(0.165, 0.84, 0.44, 1), height 0.5s cubic-bezier(0.165, 0.84, 0.44, 1);          
}

JavaScript代码

jQuery(document).ready(function($) {

    $('.link').on('mouseover', function() {
        $(this).addClass('hovered');
    });
  
    $('.link').on('mouseleave', function() {
        $(this).addClass('leaved');
        setTimeout(() => {
            $(this).removeClass('hovered leaved');
        }, 500);
        setTimeout(() => {
            $(this).removeClass('notransition');
        }, 600);
    });

});

当前存在的问题:当mouseleave动画尚未完成时再次触发mouseover,过渡效果会不流畅。请问如何优化该代码,实现流畅的动画切换?


优化方案

核心思路

在中断退出动画时,先让元素同步到当前动画的实时状态,再无缝启动进入动画,避免状态突变导致的卡顿;同时清理残留的异步操作,确保状态切换的原子性。

具体调整

1. JavaScript逻辑优化

jQuery(document).ready(function($) {
    $('.link').each(function() {
        // 为每个元素独立存储定时器,避免互相干扰
        let timer1, timer2;
        
        $(this).on('mouseover', function() {
            // 清除所有残留的定时器,避免旧的异步操作干扰新状态
            clearTimeout(timer1);
            clearTimeout(timer2);
            
            const $el = $(this);
            // 中断退出动画,移除leaved类
            $el.removeClass('leaved');
            
            // 添加notransition类,强制同步当前动画状态(无过渡)
            $el.addClass('notransition');
            // 强制触发重绘,确保状态生效
            void $el[0].offsetWidth;
            // 移除notransition,恢复过渡能力
            $el.removeClass('notransition');
            
            // 启动进入动画
            $el.addClass('hovered');
        });
      
        $(this).on('mouseleave', function() {
            const $el = $(this);
            // 清除残留定时器
            clearTimeout(timer1);
            clearTimeout(timer2);
            
            // 启动退出动画
            $el.addClass('leaved');
            
            timer1 = setTimeout(() => {
                $el.removeClass('hovered leaved');
            }, 500);
            
            timer2 = setTimeout(() => {
                $el.removeClass('notransition');
            }, 600);
        });
    });
});

2. CSS细节修复

修正.hovered.leaved .down中的错误属性(把无效的top改为bottom),确保过渡逻辑正确:

.hovered.leaved .down{
  opacity: 0;
  bottom: -30px;
  transition: opacity 0.5s cubic-bezier(0.165, 0.84, 0.44, 1), bottom 0.5s cubic-bezier(0.165, 0.84, 0.44, 1), height 0.5s cubic-bezier(0.165, 0.84, 0.44, 1);          
}

优化原理

  • 清理定时器:避免之前的mouseleave异步操作在动画中断后仍修改元素状态,导致状态冲突
  • 强制同步状态:通过notransition类+强制重绘,让元素直接跳转到退出动画的当前进度,再无缝启动进入动画,消除卡顿感
  • 修正CSS错误:移除无效的过渡属性,确保动画逻辑的一致性

内容的提问来源于stack exchange,提问作者Cédric Teixeira Alves

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 02:04:53