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

如何让CSS:hover触发的动画结束后元素保持最终状态

如何让CSS:hover触发的动画结束后元素保持最终状态

嗨,我完全懂你的困扰——现在鼠标移开礼盒后,所有元素都会立刻跳回初始关闭状态,而你想让它们稳稳停在动画结束的打开状态对吧?其实这个问题的解决思路很清晰,核心就是把依赖:hover伪类的临时触发逻辑,改成用自定义类来控制持久状态,这样状态就不会随着鼠标离开而消失了。下面是具体的修改步骤和完整代码:

核心修改思路

原来的:hover伪类是临时性的,鼠标离开后对应的样式就会被移除,所以元素会回到初始状态。我们改用一个自定义类(比如.open)来触发动画和最终样式,一旦这个类被添加到元素上,就会一直保留,从而让元素维持动画结束后的状态。

具体修改步骤

  1. 调整CSS选择器:把所有.box-body:hover开头的选择器,替换成.box-body.open,这样当元素拥有.open类时,就会应用动画和最终样式。同时保留动画的forwards属性,确保动画结束后停在最后一帧。
  2. 添加JavaScript交互:给礼盒元素添加点击/hover事件,在触发动画后添加.open类,让状态固定下来。考虑到移动端已经是点击触发,我们统一用点击事件来实现跨端一致的体验,桌面端用户也可以通过点击来保持打开状态。

修改后的完整代码

HTML部分

<div class="container">
  <div class="row">
    <div class="col-12">
      <h3 class="text-center text-light my-5"><strong>点击或hover打开礼盒</strong></h3>
    </div>
    <div class="col-12 mt-5 d-flex justify-content-center">
      <div class="box">
        <div class="box-body">
          <img class="img" src="https://via.placeholder.com/150">
          <div class="box-lid">
            <div class="box-bowtie"></div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

CSS部分

body {
  background: black;
}

.box {
  position: relative;
}

.box::before {
  content: "";
  width: 440px;
  height: 440px;
  background-color: #89cff0;
  position: absolute;
  z-index: -1;
  top: 50%;
  left: 50%;
  -webkit-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
  border-radius: 50%;
}

.box-body {
  position: relative;
  height: 200px;
  width: 200px;
  margin-top: 123.3333333333px;
  background-color: #cc231e;
  border-bottom-left-radius: 5%;
  border-bottom-right-radius: 5%;
  box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.3);
  background: linear-gradient(#762c2c,#ff0303);
  cursor: pointer; /* 提前加上光标样式,不用等hover */
}

.box-body .img{
  opacity: 0;
  transform: translateY(0%); /* 修正原代码里的拼写错误ransform */
  transition: all 0.5s;
  margin: 0 auto;
  display: block;
}

/* 把hover替换成.open类 */
.box-body.open {
  -webkit-animation: box-body 1s forwards ease-in-out;
  animation: box-body 1s forwards ease-in-out;
}

.box-body.open .img{
  opacity: 1;
  z-index: 0;
  transform: translateY(-157px);
}

.box-body.open .box-lid {
  -webkit-animation: box-lid 1s forwards ease-in-out;
  animation: box-lid 1s forwards ease-in-out;
}

.box-body.open .box-bowtie::before {
  -webkit-animation: box-bowtie-left 1.1s forwards ease-in-out;
  animation: box-bowtie-left 1.1s forwards ease-in-out;
}

.box-body.open .box-bowtie::after {
  -webkit-animation: box-bowtie-right 1.1s forwards ease-in-out;
  animation: box-bowtie-right 1.1s forwards ease-in-out;
}

.box-body::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  -webkit-transform: translateX(-50%);
  transform: translateX(-50%);
  width: 50px;
  background: linear-gradient(#ffffff,#ffefa0)
}

.box-lid {
  position: absolute;
  z-index: 1;
  left: 50%;
  -webkit-transform: translateX(-50%);
  transform: translateX(-50%);
  bottom: 90%;
  height: 40px;
  background-color: #cc231e;
  height: 40px;
  width: 220px;
  border-radius: 5%;
  box-shadow: 0 8px 4px -4px rgba(0, 0, 0, 0.3);
}

.box-lid::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  -webkit-transform: translateX(-50%);
  transform: translateX(-50%);
  width: 50px;
  background: linear-gradient(#ffefa0,#fff)
}

.box-bowtie {
  z-index: 1;
  height: 100%;
}

.box-bowtie::before, .box-bowtie::after {
  content: "";
  width: 83.3333333333px;
  height: 83.3333333333px;
  border: 16.6666666667px solid white;
  border-radius: 50% 50% 0 50%;
  position: absolute;
  bottom: 99%;
  z-index: -1;
}

.box-bowtie::before {
  left: 50%;
  -webkit-transform: translateX(-100%) skew(10deg, 10deg);
  transform: translateX(-100%) skew(10deg, 10deg);
}

.box-bowtie::after {
  left: 50%;
  -webkit-transform: translateX(0%) rotate(90deg) skew(10deg, 10deg);
  transform: translateX(0%) rotate(90deg) skew(10deg, 10deg);
}

@-webkit-keyframes box-lid {
  0%,
  42% {
    -webkit-transform: translate3d(-50%, 0%, 0) rotate(0deg);
    transform: translate3d(-50%, 0%, 0) rotate(0deg);
  }
  60% {
    -webkit-transform: translate3d(-85%, -230%, 0) rotate(-25deg);
    transform: translate3d(-85%, -230%, 0) rotate(-25deg);
  }
  90%, 100% {
    -webkit-transform: translate3d(-119%, 225%, 0) rotate(-70deg);
    transform: translate3d(-119%, 225%, 0) rotate(-70deg);
  }
}

@keyframes box-lid {
  0%,
  42% {
    -webkit-transform: translate3d(-50%, 0%, 0) rotate(0deg);
    transform: translate3d(-50%, 0%, 0) rotate(0deg);
  }
  60% {
    -webkit-transform: translate3d(-85%, -230%, 0) rotate(-25deg);
    transform: translate3d(-85%, -230%, 0) rotate(-25deg);
  }
  90%, 100% {
    -webkit-transform: translate3d(-119%, 225%, 0) rotate(-70deg);
    transform: translate3d(-119%, 225%, 0) rotate(-70deg);
  }
}

@-webkit-keyframes box-body {
  0% {
    -webkit-transform: translate3d(0%, 0%, 0) rotate(0deg);
    transform: translate3d(0%, 0%, 0) rotate(0deg);
  }
  25% {
    -webkit-transform: translate3d(0%, 25%, 0) rotate(20deg);
    transform: translate3d(0%, 25%, 0) rotate(20deg);
  }
  50% {
    -webkit-transform: translate3d(0%, -15%, 0) rotate(0deg);
    transform: translate3d(0%, -15%, 0) rotate(0deg);
  }
  70% {
    -webkit-transform: translate3d(0%, 0%, 0) rotate(0deg);
    transform: translate3d(0%, 0%, 0) rotate(0deg);
  }
}

@keyframes box-body {
  0% {
    -webkit-transform: translate3d(0%, 0%, 0) rotate(0deg);
    transform: translate3d(0%, 0%, 0) rotate(0deg);
  }
  25% {
    -webkit-transform: translate3d(0%, 25%, 0) rotate(20deg);
    transform: translate3d(0%, 25%, 0) rotate(20deg);
  }
  50% {
    -webkit-transform: translate3d(0%, -15%, 0) rotate(0deg);
    transform: translate3d(0%, -15%, 0) rotate(0deg);
  }
  70% {
    -webkit-transform: translate3d(0%, 0%, 0) rotate(0deg);
    transform: translate3d(0%, 0%, 0) rotate(0deg);
  }
}

@-webkit-keyframes box-bowtie-right {
  0%,
  50%,
  75% {
    -webkit-transform: translateX(0%) rotate(90deg) skew(10deg, 10deg);
    transform: translateX(0%) rotate(90deg) skew(10deg, 10deg);
  }
  90%,
  100% {
    -webkit-transform: translate(-50%, -15%) rotate(45deg) skew(10deg, 10deg);
    transform: translate(-50%, -15%) rotate(45deg) skew(10deg, 10deg);
    box-shadow: 0px 4px 8px -4px rgba(0, 0, 0, 0.3);
  }
}

@keyframes box-bowtie-right {
  0%,
  50%,
  75% {
    -webkit-transform: translateX(0%) rotate(90deg) skew(10deg, 10deg);
    transform: translateX(0%) rotate(90deg) skew(10deg, 10deg);
  }
  90%,
  100% {
    -webkit-transform: translate(-50%, -15%) rotate(45deg) skew(10deg, 10deg);
    transform: translate(-50%, -15%) rotate(45deg) skew(10deg, 10deg);
    box-shadow: 0px 4px 8px -4px rgba(0, 0, 0, 0.3);
  }
}

@-webkit-keyframes box-bowtie-left {
  0% {
    -webkit-transform: translateX(-100%) rotate(0deg) skew(10deg, 10deg);
    transform: translateX(-100%) rotate(0deg) skew(10deg, 10deg);
  }
  50%,
  75% {
    -webkit-transform: translate(-50%, -15%) rotate(45deg) skew(10deg, 10deg);
    transform: translate(-50%, -15%) rotate(45deg) skew(10deg, 10deg);
  }
  90%,
  100% {
    -webkit-transform: translateX(-100%) rotate(0deg) skew(10deg, 10deg);
    transform: translateX(-100%) rotate(0deg) skew(10deg, 10deg);
  }
}

@keyframes box-bowtie-left {
  0% {
    -webkit-transform: translateX(-100%) rotate(0deg) skew(10deg, 10deg);
    transform: translateX(-100%) rotate(0deg) skew(10deg, 10deg);
  }
  50%,
  75% {
    -webkit-transform: translate(-50%, -15%) rotate(45deg) skew(10deg, 10deg);
    transform: translate(-50%, -15%) rotate(45deg) skew(10deg, 10deg);
  }
  90%,
  100% {
    -webkit-transform: translateX(-100%) rotate(0deg) skew(10deg, 10deg);
    transform: translateX(-100%) rotate(0deg) skew(10deg, 10deg);
  }
}

JavaScript部分

const boxBody = document.querySelector('.box-body');

// 点击触发打开状态,同时支持桌面端hover触发(可选)
boxBody.addEventListener('click', () => {
  // 只添加一次类,避免重复触发动画
  if (!boxBody.classList.contains('open')) {
    boxBody.classList.add('open');
  }
});

// 可选:桌面端hover时也触发,鼠标移开不关闭
boxBody.addEventListener('mouseenter', () => {
  if (!boxBody.classList.contains('open')) {
    boxBody.classList.add('open');
  }
});

额外说明

  • 我还修正了你CSS里的一个小拼写错误:.box-body .img里的ransform改成了transform,不然图片的过渡效果会失效。
  • 现在不管是点击还是hover(桌面端),礼盒动画完成后都会保持打开状态,鼠标移开也不会回去,和移动端的体验一致啦。

备注:内容来源于stack exchange,提问作者Erick

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 13:04:37