How stop keyframe Animation exactly after 1 second without to use setTimeout ? - Problem events on queue

爷,独闯天下 提交于 2019-12-08 08:20:33

Here is a complete new idea that relies on transition instead of animation and where you can easily adjust the state without synchronization issue.

The main trick is to use a gradient for the background coloration and adjust its position in order to have the needed color.

Here is a simple code to illustrate the coloration:

.box {
  background: linear-gradient(to right, green, yellow, orange, red);
  background-size: 2000% 100%;
  transition:1s;
  background-repeat: no-repeat;
  background-position: 0 0;
  height: 200px;
}

.box:hover {
  background-position: 100% 0;
}
<div class="box">

</div>

As you can see, I defined a gradient with the 4 colors and we simply need to adjust the background-size in order to have the coloration (0% for green and 100% for red). This won't be exactly the same visually because we will not have a solid color like with animation and for this reason I made the background-size big enough to create the illusion of a solid color.

Now, we simply need to find the values of the background-position and the degree which is pretty easy. The backround-position is a value between 0% and 100% and the degree is a value between 180deg and 360deg. For the state 50% we will logically use 50% for the background-position and 270deg for the transformation and for an x% state we will use respectively x% and x%*(360deg - 180deg) + 180deg = x%*180deg + 180deg = 180deg(x% + 1)

Here is an example with 50% (hover to see)

#page {
  margin-top: 50px;
  width: 300px;
  height: 300px;
  background-color: #000;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  z-index: 4;
  overflow: hidden;
}

#box-first{
  width: 200px;
  height: 100px;
  background-color: #fff;
  border-radius: 200px 200px 0 0;
  margin-top: 10px;
  margin-bottom: 10px;
  position: relative;
  display: flex;
  justify-content: flex-end;
  align-items: flex-start;
  z-index: 3;
  overflow: hidden;
}

#first{
  border-radius: 200px 200px 0 0;
  margin: 0;
  background: linear-gradient(to right, green, yellow, orange, red);
  background-size: 2000% 100%;
  background-repeat:no-repeat;
  background-position:0% 0%;
  transition:1s;
  width: 200px;
  height: 100px;
  transform: rotate(180deg);
  transform-origin: 50% 100%;
  position: absolute;
  top: 0px;
  right: 0px;
  border: 0;
  z-index: 1;
}
#box-first:hover #first{
  transform: rotate(270deg);
  background-position:50% 0%;
}

#n1{
  font-size: 20px;
  color: #fff;
  font-weight: bold;
  position: absolute;
  left: 50px;
  right: 0;
  text-align: center;
  top: 50px;
  bottom: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 100px;
  height: 50px;
  background: #000;
  border-radius: 100px 100px 0 0;
  z-Index: 1;
  overflow: hidden;
}
<div id="page">
  <div id="box-first">
    <div id="first">

    </div>
    <div id="n1">
      1500
    </div>
  </div> 
</div>

In order to make this dynamic, we need to adjust the values using JS and the transition will do the job. For this we can define a data-attribute for the state that we convert to the needed value.

Here is an example where I also simplified the html and used pseudo element and CSS variables

setTimeout(function() {
  $('.box').each(function() {
    var d = $(this).data('state');
    $(this).attr("style", "--s:" + d);
  });
}, 1000);
body {
  margin: 0;
  background: #000;
}

.box {
  width: 200px;
  height: 100px;
  background-color: #fff;
  border-radius: 200px 200px 0 0;
  margin: 10px;
  position: relative;
  display: inline-flex;
  z-index: 0;
  overflow: hidden;
}

.box:before {
  content: "";
  position: absolute;
  z-index: -1;
  border-radius: 200px 200px 0 0;
  background: linear-gradient(to right, green, yellow, orange, red);
  background-size: 2000% 100%;
  background-repeat: no-repeat;
  background-position: calc(var(--s, 0) * 1%) 0%;
  transition:2s linear;
  width: 200px;
  height: 100px;
  transform: rotate(calc((var(--s, 0)/100 + 1)*180deg));
  transform-origin: 50% 100%;
  top: 0px;
  right: 0px;
}

.box:after {
  content: attr(data-number);
  font-size: 20px;
  color: #fff;
  font-weight: bold;
  text-align: center;
  margin: auto auto 0;
  width: 100px;
  height: 50px;
  line-height: 50px;
  background: #000;
  border-radius: 100px 100px 0 0;
  z-Index: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box" data-number="1500" data-state="50"></div>

<div class="box" data-number="1000" data-state="20"></div>

<div class="box" data-number="3000" data-state="80"></div>

<div class="box" data-number="6000" data-state="100"></div>

You may notice that all will have the same duration since the transition is the same for all. In case you want a different duration and keep the same speed, simply use the CSS variable within the transition also.

setTimeout(function() {
  $('.box').each(function() {
    var d = $(this).data('state');
    $(this).attr("style", "--s:" + d);
  });
}, 1000);
body {
  margin: 0;
  background: #000;
}

.box {
  width: 200px;
  height: 100px;
  background-color: #fff;
  border-radius: 200px 200px 0 0;
  margin: 10px;
  position: relative;
  display: inline-flex;
  z-index: 0;
  overflow: hidden;
}

.box:before {
  content: "";
  position: absolute;
  z-index: -1;
  border-radius: 200px 200px 0 0;
  background: linear-gradient(to right, green, yellow, orange, red);
  background-size: 2000% 100%;
  background-repeat: no-repeat;
  background-position: calc(var(--s, 0) * 1%) 0%;
  transition: calc(2s * var(--s, 0)/100) linear;
  width: 200px;
  height: 100px;
  transform: rotate(calc((var(--s, 0)/100 + 1)*180deg));
  transform-origin: 50% 100%;
  top: 0px;
  right: 0px;
}

.box:after {
  content: attr(data-number);
  font-size: 20px;
  color: #fff;
  font-weight: bold;
  text-align: center;
  margin: auto auto 0;
  width: 100px;
  height: 50px;
  line-height: 50px;
  background: #000;
  border-radius: 100px 100px 0 0;
  z-Index: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box" data-number="1500" data-state="50"></div>

<div class="box" data-number="1000" data-state="20"></div>

<div class="box" data-number="3000" data-state="80"></div>

<div class="box" data-number="6000" data-state="100"></div>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!