动态更改CSS关键帧值以创建时钟 [英] Dynamically changing CSS keyframe values to create a clock

查看:78
本文介绍了动态更改CSS关键帧值以创建时钟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我非常第一尝试制作关键帧动画。之前我因无法通过JavaScript动态更改硬编码CSS值而感到失望。

This is my 'very first' foray into keyframe animation. I was put off before by the alleged inability to dynamically change hard coded CSS values on the fly via JavaScript.

我在Google上搜索了一下,发现它可以完成,但是要花很多时间才能找到,删除和替换部分或整个样式表。

I Googled around a bit to find it 'can' be done but with a lot of fiddly work finding, removing and replacing parts of or whole stylesheets.

无论如何,这是我的努力。此特定脚本的最终目标是跳针。我已经可以使用过渡和三次贝塞尔曲线来做到这一点,但只能进行一次弹跳。我已经看到了使用各种js库等的效果,但是您知道它是如何-您想自己滚动。

Anyway, here's my effort. The eventual goal of this particular script is to be the bounce of clock hand. I can already do this with transition and cubic bezier but can only get one bounce in. I've seen this effect using various js libraries etc but you know how it is - you like to roll your own.

我的问题是-下面的方法有什么明显的错误。忽略琐事,这只是一个测试。我要查看的是我的GenerateKeyFrames()函数和调用它的两种方法。

My question is - Is there anything glaringly wrong with my method below. Ignore the trivia, it's just a test. What I want looking at is my GenerateKeyFrames() function and the two methods of calling it.

感谢您提供任何信息。

    var d = document;
    var incr = 1;
    var step = -6; //Initial start pos.

    var coreCss = 'display: block;position: absolute;'
               +'left: 100px;top: 10px;height: 95px;'
               +'width: 4px;background-color: #000;'
               +'transform-origin: center bottom;';

    var initialAniCss = 'animation: reGen'+incr+' 1s 1 forwards;';
    coreCss += initialAniCss;

    var elementToAnimate = d.createElement('div');
    elementToAnimate.setAttribute('style', coreCss);
    d.body.appendChild(elementToAnimate);

    function GenerateKeyFrames() {

    /* Remove previous 'tmpSheet' stylesheet */
    var currSheet = (d.getElementById('tmpSheet'));
    if (currSheet) {
        //currSheet.parentNode.removeChild(currSheet);// Doesn't seem as smooth as other 2 below!
        //currSheet.remove(); - Not IE, shame.
        currSheet.outerHTML = '';
    }

    /* Movement in degrees */
    var p1 = step;
    var p2 = step+6;
    var p3 = step+4;
    var p4 = step+6;
    var p5 = step+5; 
    var p6 = step+6;

    /* Create new keyframe. Must have new name! Adding an incrementing var to name does ok */
    var frames = '@keyframes reGen'+incr+' { '
    +'0% { transform: rotate('+p1+'deg) translateZ(0); animation-timing-function: ease-in;}'
    +'25% { transform: rotate('+p2+'deg) translateZ(0); animation-timing-function: ease-out;}'
    +'45% { transform: rotate('+p3+'deg) translateZ(0); animation-timing-function: ease-in;}'
    +'65% { transform: rotate('+p4+'deg) translateZ(0); animation-timing-function: ease-out;}' 
    +'75% { transform: rotate('+p5+'deg) translateZ(0); animation-timing-function: ease-in;}'
    +'85%,100% { transform: rotate('+p6+'deg) translateZ(0);animation-timing-function: ease-out;}}';

    /* Create new tmpSheet style sheet to head */
    var s = document.createElement( 'style' );
    s.setAttribute("id", "tmpSheet");
    s.innerHTML = frames;
    document.getElementsByTagName('head')[0].appendChild(s);

    /* Put it all together and it's ready to go */ 
    var newAni = 'animation: reGen'+incr+' 1s 1 forwards;';
    coreCss += newAni;
    elementToAnimate.setAttribute('style', coreCss);
    d.body.appendChild(elementToAnimate);
}
GenerateKeyFrames();

/* Can be called on animation end - or timed function rep().
elementToAnimate.addEventListener("animationend",function(e) {
    incr++;
    step += 6;
    elementToAnimate.removeAttribute("style");
    GenerateKeyFrames();
    },false);
*/

function rep() {
    incr++;
    step += 6;
    elementToAnimate.removeAttribute("style");
    GenerateKeyFrames();
setTimeout(rep, 2000);
}
rep();

推荐答案

我真的不喜欢用唯一的名称动态插入所有这些关键帧的想法。如果我这样做并尝试使用CSS关键帧动画,我将创建两个动画,一个动画提供双重弹跳效果,另一个动画使包装器围绕中心旋转。

I don't really like the idea of inserting all those keyframes dynamically with unique names. If I were doing this and trying to use CSS keyframe animations, I'd create two animations, one that provides your "double-bounce" effect, and one that rotates a wrapper around the center.

仅使用HTML和CSS,几乎可以创建一个完整的工作时钟,尽管没有JavaScript,您无法在适当的时间启动它。

Using just HTML and CSS, you can almost create a full working clock, although you don't have any way to start it at the right time without JavaScript.

虽然这是一个有趣的练习,但我能够仅使用关键帧动画和少量JavaScript来重新创建整个时钟效果,从而确定动画的开始时间并提供负值 动画延迟 将动画补偿到适当的时间范围。

This was a fun exercise though, and I was able to recreate the whole clock effect using just keyframe animations with a tiny bit of JavaScript to determine the starting time of the animation and supply a negative animation-delay to offset the animations to the proper timeframes.

时间可能会有所波动,但实际上并没有您想象的那么多。我让动画在Chrome,FF和IE上运行了一整夜,让我的电脑进入睡眠状态,而9个小时后,时钟仍然保持着完美的时间。但是,当我将其放置在手机的背景标签中过夜时,早上的时钟已完全中断。不过,从整个目的是在网页上显示时钟的角度来看,页面不太可能停留足够长的时间以至于时钟明显关闭。

The time can wander a bit, but really not as much as you might think. I left the animations running overnight in Chrome, FF, and IE, and allowed my computer to go to sleep, and 9 hours later the clocks were still keeping perfect time. However, when I left it running in a background tab of my phone overnight, the clock was completely broken in the morning. Though, seeing as how the whole purpose is to display a clock on a webpage, it's unlikely that the page would stick around long enough for the clock to be noticeably off.

无论如何,这是代码段:

Anyway, here's the snippet:

window.addEventListener("load", function() {
  var now = new Date();
  var secondsDelay = now.getSeconds();
  var minutesDelay = now.getMinutes() * 60 + secondsDelay;
  var hoursDelay = (now.getHours() % 12) * 3600 + minutesDelay;
  var minuteHand = document.querySelector(".minute .hand");
  var minuteWrapper = document.querySelector(".minute");
  var secondWrapper = document.querySelector(".second");
  var hourWrapper = document.querySelector(".hour");

  //set animation offsets with negative delay
  minuteHand.style.animation = "minuteTick 60s -" + secondsDelay + "s infinite";
  secondWrapper.style.animation = "rotateHolder steps(60) 60s -" + secondsDelay + "s infinite";
  minuteWrapper.style.animation = "rotateHolder steps(60) 3600s -" + minutesDelay + "s infinite";
  hourWrapper.style.animation = "rotateHolder steps(43200) 43200s -" + hoursDelay + "s infinite";

  //start running
  document.querySelector(".clock").classList.add("running");
});

.clock {
  width: 200px;
  height: 200px;
  background-color: gray;
  border-radius: 50%;
}
.sectionWrapper {
  width: 200px;
  height: 200px;
  position: absolute;
  transform: rotate(0deg);
}
.clock.running .second {
  animation: rotateHolder 60s steps(60) infinite;
}
.clock.running .second .hand {
  animation: secondTick 1s 0s infinite;
}
.clock.running .minute {
  animation: rotateHolder 3600s steps(60) infinite;
}
.clock.running .minute .hand {
  animation: minuteTick 60s 0s infinite;
}
.clock.running .hour {
  animation: rotateHolder 43200s steps(43200) infinite;
}
.hand {
  display: block;
  position: absolute;
  background-color: #000;
  transform-origin: center bottom;
}
.second .hand {
  left: 99px;
  top: 5px;
  height: 95px;
  width: 2px;
  background-color: red;
}
.minute .hand {
  left: 98px;
  top: 15px;
  height: 85px;
  width: 4px;
}
.hour .hand {
  left: 97px;
  top: 45px;
  height: 55px;
  width: 6px;
}
@keyframes secondTick {
  0% { transform: rotate(0deg); animation-timing-function: ease-in; }
  25% { transform: rotate(6deg); animation-timing-function: ease-out; }
  45% { transform: rotate(4deg); animation-timing-function: ease-in; }
  65% { transform: rotate(6deg); animation-timing-function: ease-out; } 
  75% { transform: rotate(5deg); animation-timing-function: ease-in; }
  85%,100% { transform: rotate(6deg);animation-timing-function: ease-out; }				
}
@keyframes minuteTick {
  0%,98.3% { transform: rotate(0deg); animation-timing-function: ease-in; }
  98.8% { transform: rotate(6deg); animation-timing-function: ease-out; }
  99.1% { transform: rotate(4deg); animation-timing-function: ease-in; }
  99.4% { transform: rotate(6deg); animation-timing-function: ease-out; } 
  99.6% { transform: rotate(5deg); animation-timing-function: ease-in; }
  99.8%,100% { transform: rotate(6deg);animation-timing-function: ease-out; }				
}
@keyframes rotateHolder {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

<div class="clock">
  <div class="hour sectionWrapper">
    <div class="hand"></div>
  </div>
  <div class="minute sectionWrapper">
    <div class="hand"></div>
  </div>
  <div class="second sectionWrapper">
    <div class="hand"></div>
  </div>
</div>

这篇关于动态更改CSS关键帧值以创建时钟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆