This is my animation:
.ani span {
animation: animation 1s infinite;
display: inline-table;
}
#keyframes animation {
0% {
transform: translateY(0px);
}
33.333% {
transform: translateY(-5px);
}
66.666% {
transform: translateY(5px);
}
100% {
transform: translateY(0px);
}
}
.ani span:nth-child(1) {
animation-delay: .1s;
}
.ani span:nth-child(2) {
animation-delay: .2s;
}
.ani span:nth-child(3) {
animation-delay: .3s;
}
.ani span:nth-child(4) {
animation-delay: .4s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="ani"><span>h</span><span>e</span><span>l</span><span>l</span><span>o</span></div>
I will have different texts (not only »hello«) that should have this animation. So it would be great to have it as jQuery function. There should be calculated the text length, automatically placed <span></span>, and a fitting animation-delay.
How is it possible to code that?
Would be sooooo thankful for help.
You could do it like this:
var div, aniDivs, i,j;
aniDivs = document.querySelectorAll("div.ani");
for (var i = 0, len = aniDivs.length; i < len; i++) {
div = document.querySelectorAll("div.ani")[i];
let span = "";
for (j = 0; j < div.innerText.length; j++) {
if (div.innerText[j] !== " ") {
span += "<span style='animation-delay:." + (j + 1) + "s'>";
span += div.innerText[j];
span += "</span>";
}
}
div.innerHTML = span;
}
.ani span {
animation: animation 1s infinite;
display: inline-table;
}
#keyframes animation {
0% {
transform: translateY(0px);
}
33.333% {
transform: translateY(-5px);
}
66.666% {
transform: translateY(5px);
}
100% {
transform: translateY(0px);
}
}
.ani span:nth-child(1) {
animation-delay: .1s;
}
.ani span:nth-child(2) {
animation-delay: .2s;
}
.ani span:nth-child(3) {
animation-delay: .3s;
}
.ani span:nth-child(4) {
animation-delay: .4s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="ani">Welcome</div>
<div class="ani">again</div>
For this answer I incorporated this answer How to wrap each character from a string in spans given by Danny Fardy Jhonston Bermúdez.
This should work for string of arbitrary length
$aniDivs = $('.ani'); // collect all the divs that have 'ani' class
//loop over each
$aniDivs.each(function(divIndex, div){
//HTML part
var divTxt = $(div).text();
// get the text that's inside the ani div (ie. "hello" )
var lettersArr = divTxt.split('');
// make an array of letters that constitute the word (ie. ["h", "e", "l", "l", "o"] )
var spanContent = '';
// a bucket to hold the spans that we create dynamically
$.each(lettersArr, function(letterIndex, letter){
spanContent+= '<span>'+letter+'</span>';
});
// Now we have <span>h</span><span>e</span><span>l</span><span>l</span><span>o</span>
$(div).html(spanContent);
// put it inside current ani <div>
//CSS part
var delay = 0.1;
//now we collect the the <spans> that we just created and appended and increment the animation-delay in a progression
$(div).find('span').each(function(spanIndex,span){
$(span).css('animation-delay', delay.toFixed(1)+'s' );
delay=delay+0.1; // displace every subsequent div to .1 second from previous
});
});
.ani span {
animation: animation 1s infinite;
display: inline-table;
}
#keyframes animation {
0% {
transform: translateY(0px);
}
33.333% {
transform: translateY(-5px);
}
66.666% {
transform: translateY(5px);
}
100% {
transform: translateY(0px);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="ani">Lopadotemachoselachogaleokranioleipsanodrimhypotrimmatosilphioparaomelitokatakechymenokichlepikossyphophattoperisteralektryonoptekephalliokigklopeleiolagoiosiraiobaphetraganopterygon</div>
Related
I am new to css and javascript. I am trying to animate the spans within an h2 to fall from the top of the page on load and then on hover to have a bouncy effect. I was able to make them happen both BUT now the problem is that the animation delay I intended for the fall animation are applying to the bounce animation as well. When I add the animation name to the animation delay all the letter fall at the same time. What am I missing?
I tried specifying the animation name for the animation delay but it didn't work. When I add the animation name to the animation delay all the letter fall at the same time. What am I missing?. And I also tried to change the animation delay in JS after the first animation happens but wasn't able to figure out.
This is my html
<h2 class="test">
<span class="q">T</span><span class="q">a</span><span class="q">d</span><span
class="q">a</span><span class="q">a</span><span class="q">k</span><span class="q">i</span>
</h2>
<h2 class="test2">
<span class="q2">K</span><span class="q2">u</span><span class="q2">w</span><span
class="q2">a</span><span class="q2">y</span><span class="q2">a</span><span
class="q2">m</span><span class="q2">a</span>
</h2>
This is the CSS
span {
color: black;
font-size: 1em;
display: flex;
margin-bottom: 0;
padding-bottom: 0;
}
.onLoadAnimation {
position: relative;
transform: translateY(-100vh);
animation: fall 1s forwards;
animation-iteration-count: 1;
}
#keyframes fall {
100% {
transform: translateY(0);
}
}
.test span:nth-child(2) {
animation-delay: 0.1s;
}
.test span:nth-child(3) {
animation-delay: 0.2s;
}
.test span:nth-child(4) {
animation-delay: 0.3s;
}
.test span:nth-child(5) {
animation-delay: 0.4s;
}
.test span:nth-child(6) {
animation-delay: 0.5s;
}
.test span:nth-child(7) {
animation-delay: 0.6s;
}
.test2 span:nth-child(1) {
animation-delay: 0.1s;
}
.test2 span:nth-child(2) {
animation-delay: 0.12s;
}
.test2 span:nth-child(3) {
animation-delay: 0.3s;
}
.test2 span:nth-child(4) {
animation-delay: 0.4s;
}
.test2 span:nth-child(5) {
animation-delay: 0.5s;
}
.test2 span:nth-child(6) {
animation-delay: 0.6s;
}
.test2 span:nth-child(7) {
animation-delay: 0.7s;
}
.test2 span:nth-child(8) {
animation-delay: 0.8s;
}
.spanHoverEffect {
color: #0f4c5c;
animation: animate 0.6s;
}
#keyframes animate {
25% {
transform: scale(0.8, 1.3);
}
50% {
transform: scale(1.1, 0.8);
}
75% {
transform: scale(1.1, 0.8);
}
}
This is the JS
let letters = document.getElementsByClassName("q");
let lettersTwo = document.getElementsByClassName("q2");
window.onload = () => {
for (l of letters) {
l.classList.toggle('onLoadAnimation');
l.addEventListener('mouseover', function () {
this.classList
.remove('onLoadAnimation')
.add('spanHoverEffect')
});
l.addEventListener('mouseout', function () {
this.classList
.remove('onLoadAnimation')
.remove('spanHoverEffect')
});
}
for (l of lettersTwo) {
l.classList.toggle('onLoadAnimation');
l.addEventListener('mouseover', function () {
this.classList
.remove('onLoadAnimation')
.add('spanHoverEffect')
});
l.addEventListener('mouseout', function () {
this.classList
.remove('onLoadAnimation')
.remove('spanHoverEffect')
});
}
};
In this fiddle, I made two changes. The letters fall in sequence in Chrome, Firefox and Edge and the animation delay is not present when moused over in any of those browsers.
I added the onLoadAnimation class to the CSS for each letter.
.test .onLoadAnimation:nth-child(2) {
animation-delay: 0.1s;
}
And I removed the chained changes to classList, which is not something that classList supports in any of the browsers mentioned above.
l.classList.remove('onLoadAnimation')
l.classList.add('spanHoverEffect')
The reason I mention web browsers is that "this.classList.remove('onLoadAnimation').add('spanHoverEffect')" causes an error in all of those browsers, because remove returns undefined, so I am wondering if you are using a less-used browser that may work differently.
I am feeding text to a div from the top.
The following code gives the newest paragraph a slide-down animation as it is added to the div.
How can I make all paragraphs slide down as the new one is created?
Also, any tips on my code will be greatly appreciated!
HTML:
<div id="text">
Javascript:
function addText(message) {
var el = document.getElementById('text');
var p = document.createElement('p');
p.appendChild(document.createTextNode(message));
el.insertBefore(p, el.childNodes[0] || null);
$(p).addClass("reveal");
}
CSS:
.reveal {
animation: slide-down 1s;
}
#keyframes slide-down {
from {
-moz-transform: translateY(-50px);
-webkit-transform: translateY(-50px);
transform: translateY(-50px);
opacity: 0;
}
to {
opacity: 1;
-moz-transform: translateY(0px);
-webkit-transform: translateY(0px);
transform: translateY(0px);
-moz-animation: linear;
-webkit-animation: linear;
animation: linear;
}
}
Can you try this.
function addText(message) {
$('p').removeClass("reveal");
setTimeout(function(){
var el = document.getElementById('text');
var p = document.createElement('p');
p.appendChild(document.createTextNode(message));
el.insertBefore(p, el.childNodes[0] || null);
$('p').addClass("reveal");
}, 500);
}
addText('Welcome to first paragrap');
Then you call second one in console.
So I have got different animations made in CSS, though the problem is that they start right away when the page loads (ofcourse). I do not want this though. Is there a way in Vanilla JavaScript to get the animation to fire up only when it is in the viewport?
I have searched in a lot of places, but I either find a plugin I need to use or jQuery.
HTML:
<div class="introduction">
<h1>I can do the following for you:</h1>
<ul>
<li>Create a custommade, new website.</li>
<li>Code a PSD template into a working website.</li>
<li>Rework an outdated website.</li>
<li>Clean up messy code of a website.</li>
</ul>
</div>
CSS:
#keyframes showOnLoad {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.introduction li {
list-style-type: none;
margin-bottom: 5px;
text-align: center;
opacity: 0;
-webkit-animation: showOnLoad;
animation: showOnLoad;
-webkit-animation-duration: 2s;
animation-duration: 2s;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
.introduction li:nth-child(2) {
-webkit-animation-delay: 1s;
animation-delay: 1s;
}
.introduction li:nth-child(3) {
-webkit-animation-delay: 2s;
animation-delay: 2s;
}
.introduction li:nth-child(4) {
-webkit-animation-delay: 3s;
animation-delay: 3s;
}
This is the code you need.
window.addEventListener("scroll", onScroll);
function onScroll() {
for (var item of document.querySelectorAll(".introduction li")) {
elementVisible(item);
}
}
function elementVisible(el) {
let top = el.offsetTop;
let height = el.offsetHeight;
let bottom = top + height;
let IsOverBottom = top > (window.pageYOffset + window.innerHeight);
let IsBeforeTop = bottom < window.pageYOffset;
if (!IsOverBottom && !IsBeforeTop) {
el.classList.add("show");
}
}
And a bit of CSS
#keyframes slideIn {
0% {
opacity: 0;
transform: translateX(100%);
}
100% {
opacity: 1;
transform: translateX(0%);
}
}
.show {
animation: slideIn 5s ease-in-out;
}
This is a basic implementation but it gets you closer.
http://jsbin.com/hetapaj/1/edit?css,js,output
Having some trouble building a CSS3 loader using keyframe animations.
The loader consists of 4 boxes that animate going up and down. The issue I'm having is that when the animation is supposed to stop, the boxes jump to the initial position. The behaviour I'm looking for is: loader is animating infinitely until loading is done, at which point it should animate to the initial position and stop, sort of like having animation-iteration-count: infinite and changing it to animation-iteration-count: 1 to stop the animation. (which doesn't work btw).
See this fiddle to see what I mean: https://jsfiddle.net/cazacuvlad/qjmhm4ma/ (when clicking the stop button, the boxes should animate to the initial position, instead of jumping)
The basic setup is:
<div class="loader-wrapper"><span></span><span></span><span></span><span></span></div>
To start the loader, I'm adding a loader-active class that contains the animation to the loader-wrapper.
LESS:
.loader-wrapper {
&.loader-active {
span {
.animation-name(loader);
.animation-duration(1200ms);
.animation-timing-function(ease-in-out);
.animation-play-state(running);
.animation-iteration-count(infinite);
&:nth-child(1) {
}
&:nth-child(2) {
.animation-delay(300ms);
}
&:nth-child(3) {
.animation-delay(600ms);
}
&:nth-child(4) {
.animation-delay(900ms);
}
}
}
}
I've tried adding the animation to the spans in the loader-wrapper class w/o loader-active and playing around with animation-iteration-count and animation-play-state when loader-active is added without any luck.
Found a pretty simple workaround. Still not pure CSS, it involves a bit of JS, but it works well.
Updated fiddle: https://jsfiddle.net/cazacuvlad/qjmhm4ma/2/
What I did was to move the loader-active class to each span (instead of the wrapper), listen to the animationiteration event on each span and stop the animation then.
$('.loader-wrapper span').on('animationiteration webkitAnimationIteration', function () {
var $this = $(this);
$this.removeClass('loader-active');
$this.off();
});
This basically stops the animation at the very end of an iteration cycle.
Updated LESS
.loader-wrapper {
span {
&.loader-active {
.animation-name(loader);
.animation-duration(1200ms);
.animation-timing-function(ease-in-out);
.animation-play-state(running);
.animation-iteration-count(infinite);
&:nth-child(1) {
}
&:nth-child(2) {
.animation-delay(300ms);
}
&:nth-child(3) {
.animation-delay(600ms);
}
&:nth-child(4) {
.animation-delay(900ms);
}
}
}
}
You can also add a class which specifies the iteration count to stop the infinite loop. The advantage of this approach is that you can change the duration and timing-function which can be nice for easing out some animation (Like a rotating logo for example).
.animate-end {
animation-iteration-count: 3;
animation-duration: 1s;
animation-timing-function: ease-out;
}
We can add this class with js and it will now stop the animation at count 3.
document.querySelector(".loader-wrapper").classList.add("animate-end");
But you can also end the current itertion by counting it and change the style of the element dynamcly with Js.
let iterationCount = 0;
document.querySelector(".loader-wrapper span").addEventListener('animationiteration', () => {
//count iterations
iterationCount++;
});
yourElement.style.animationIterationCount = iterationCount + 1;
Here is a demo with your code:
document.querySelector("#start_loader").addEventListener("click", function(){
document.querySelector(".loader-wrapper").classList.add("loader-active");
})
let iterationCount = 0;
document.querySelector(".loader-wrapper span").addEventListener('animationiteration', () => {
//count iterations
iterationCount++;
console.log(`Animation iteration count: ${iterationCount}`);
});
document.querySelector("#stop_loader").addEventListener("click", function(){
//For some animation it can be nice to change the duration or timing animation
document.querySelector(".loader-wrapper").classList.add("animate-end");
//End current iteration
document.querySelectorAll(".loader-wrapper span").forEach(element => {
element.style.animationIterationCount = iterationCount + 1;
});
//Remove Classes with a timeout or animationiteration event
setTimeout(() => {
document.querySelector(".loader-wrapper").classList.remove("loader-active");
document.querySelector(".loader-wrapper").classList.remove("animate-end");
}, 1200);
})
#-moz-keyframes 'loader' {
0% {
-moz-transform: translate3d(0, 0, 0);
}
50% {
-moz-transform: translate3d(0, -10px, 0);
}
100% {
-moz-transform: translate3d(0, 0, 0);
}
}
#-webkit-keyframes 'loader' {
0% {
-webkit-transform: translate3d(0, 0, 0);
}
50% {
-webkit-transform: translate3d(0, -10px, 0);
}
100% {
-webkit-transform: translate3d(0, 0, 0);
}
}
#-o-keyframes 'loader' {
0% {
-o-transform: translate3d(0, 0, 0);
}
50% {
-o-transform: translate3d(0, -10px, 0);
}
100% {
-o-transform: translate3d(0, 0, 0);
}
}
#keyframes 'loader' {
0% {
transform: translate3d(0, 0, 0)
}
50% {
transform: translate3d(0, -10px, 0)
}
100% {
transform: translate3d(0, 0, 0)
}
}
.loader-wrapper {
margin-bottom: 30px;
}
.loader-wrapper.loader-active span {
-webkit-animation-name: loader;
-moz-animation-name: loader;
-ms-animation-name: loader;
-o-animation-name: loader;
animation-name: loader;
-webkit-animation-duration: 1200ms;
-moz-animation-duration: 1200ms;
-ms-animation-duration: 1200ms;
-o-animation-duration: 1200ms;
-webkit-animation-timing-function: ease-in-out;
-moz-animation-timing-function: ease-in-out;
-ms-animation-timing-function: ease-in-out;
-o-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
-webkit-animation-play-state: running;
-moz-animation-play-state: running;
-ms-animation-play-state: running;
-o-animation-play-state: running;
animation-play-state: running;
-webkit-animation-iteration-count: infinite;
-moz-animation-iteration-count: infinite;
-ms-animation-iteration-count: infinite;
-o-animation-iteration-count: infinite;
animation-iteration-count: infinite;
}
.loader-wrapper.animate-end span {
/* Works great for some animations */
/*animation-iteration-count: 1;*/
/*animation-duration: 1s;*/
}
.loader-wrapper.loader-active span:nth-child(1) {}
.loader-wrapper.loader-active span:nth-child(2) {
animation-delay: 300ms;
}
.loader-wrapper.loader-active span:nth-child(3) {
animation-delay: 600ms;
}
.loader-wrapper.loader-active span:nth-child(4) {
animation-delay: 900ms;
}
.loader-wrapper span {
margin-right: 5px;
display: inline-block;
vertical-align: middle;
background: black;
width: 10px;
height: 10px;
}
<div class="loader-wrapper"><span></span><span></span><span></span><span></span></div>
<button id="start_loader">Start</button>
<button id="stop_loader">Stop</button>
I have some keyframe animations in my css file. There is already an animation-delay specified.
The wrapper div has the attribute data-delay.
I want to get the animation-delay in the css file and add the value of data-delay to it.
Then i want that the animation start with the new delay.
I tried ele[i].style.animationDelay.
But it seems that this returns null until I set a value to it.
If I set ele[i].style.animationDelay = '5s' the animation still runs with the delay of the css file.
HTML
<div id="wrapper" data-delay="2s" >
<h1 id="hi">Hi</h1>
<h1 id="name">test!</h1>
</div>
CSS
body { font-size: 300%; }
#wrapper h1 { position: absolute; }
#hi {
transform: translate(-200px, 100px);
animation-name: hi;
animation-duration: .5s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 0s;
}
#name {
transform: translate(-200px, 150px);
animation-name: name;
animation-duration: .5s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
#keyframes hi{
100% { transform: translate(50px, 100px) };
}
#keyframes name{
100% { transform: translate(50px, 150px) };
}
JS
var wrapper = document.getElementById('wrapper');
var ele = wrapper.children;
var delay = wrapper.getAttribute('data-delay');
for (var i=0;i<ele.length;i++) {
alert(ele[i].style.animationDelay);
ele[i].style.animationDelay = delay;
alert(ele[i].style.animationDelay);
}
http://jsfiddle.net/FHuKN/4/
I've only tested this on Mac 10.8 Chrome 25, Safari 6.0, and FF 18.0.
Sounds like the main thing you wanted to do was add the data-delay value to whatever existing animation delay was applied to the elements.
HTML - unchanged
<div id="wrapper" data-delay="5.1s" >
<h1 id="hi">Hi</h1>
<h1 id="name">test!</h1>
</div>
CSS - Vendor prefixes and initial keyframes (0%) were added.
body { font-size: 300%; }
#wrapper h1 { position: absolute; }
#hi {
-webkit-transform: translate(-200px, 100px);
-webkit-animation-name: hi;
-webkit-animation-duration: .5s;
-webkit-animation-timing-function: linear;
-webkit-animation-fill-mode: forwards;
-webkit-animation-delay: 2.1s;
-moz-transform: translate(-200px, 100px);
-moz-animation-name: hi;
-moz-animation-duration: .5s;
-moz-animation-timing-function: linear;
-moz-animation-fill-mode: forwards;
-moz-animation-delay: 2.1s;
transform: translate(-200px, 100px);
animation-name: hi;
animation-duration: .5s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 2.1s;
}
#name {
-webkit-transform: translate(-200px, 150px);
-webkit-animation-name: name;
-webkit-animation-duration: .5s;
-webkit-animation-timing-function: linear;
-webkit-animation-fill-mode: forwards;
-webkit-animation-delay: 3.1s;
-moz-transform: translate(-200px, 150px);
-moz-animation-name: name;
-moz-animation-duration: .5s;
-moz-animation-timing-function: linear;
-moz-animation-fill-mode: forwards;
-moz-animation-delay: 3.1s;
transform: translate(-200px, 150px);
animation-name: name;
animation-duration: .5s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 3.1s;
}
#-moz-keyframes hi{
0% { -moz-transform: translate(-200px, 100px); }
100% { -moz-transform: translate(50px, 100px); }
}
#-webkit-keyframes hi {
0% { -webkit-transform: translate(-200px, 100px); }
100% { -webkit-transform: translate(50px, 100px); }
}
#keyframes hi{
0% { transform: translate(-200px, 100px); }
100% { transform: translate(50px, 100px); }
}
#-moz-keyframes name {
0% { -moz-transform: translate(-200px, 150px); }
100% { -moz-transform: translate(50px, 150px); }
}
#-webkit-keyframes name {
0% { -webkit-transform: translate(-200px, 150px); }
100% { -webkit-transform: translate(50px, 150px); }
}
#keyframes name {
0% { transform: translate(-200px, 150px); }
100% { transform: translate(50px, 150px); }
}
JAVASCRIPT
On an element, the style property doesn't hold all the style information because it only represents what is being set directly on the element via the style attribute. MDN
window.getComputedStyle() seems to work pretty well.
Juggling the prefixed properties is a little clunky, but it worked in the browsers I tested with.
(function(undefined) {
var wrapper = document.getElementById('wrapper'),
elms = wrapper.children,
delay = wrapper.getAttribute('data-delay'),
prop,
styl,
cur,
i;
delay = !delay ? 0 : Number(delay.replace(/[^\d\.]/g, ''));
if (!elms.length) {
return;
}
styl = window.getComputedStyle(elms[0]);
if (styl.getPropertyValue('animation-delay')) {
prop = 'animation-delay';
} else if (styl.getPropertyValue('-webkit-animation-delay')) {
prop = '-webkit-animation-delay';
} else if (styl.getPropertyValue('-moz-animation-delay')) {
prop = '-moz-animation-delay';
} else {
console.log('unable to find prop');
return;
}
// console.log('prop', prop);
for (i = 0; i < elms.length; i++) {
styl = window.getComputedStyle(elms[i]);
cur = styl.getPropertyValue(prop);
cur = Number(cur.replace(/[^\d\.]/g, ''));
elms[i].style.setProperty(prop, (cur + delay) + 's');
console.log('delay: ' + cur + 's -> ' + (cur + delay) + 's')
}
})();
http://jsfiddle.net/FHuKN/11/
Old Firefoxes (at least up to 16), Opera before migrating to Blink (<15), IE at least 10 - will not redraw the animation if we just change some of its attributes like (-prefix-)animation-delay. In order to make them do so, we have to apply some depper tricks.
The first will be removing and reinserting the animated element. And - for the sake of Webkit - applying all the style changes on it.
Just change the code from #tiffon's fiddle
elms[i].style.setProperty(prop, (cur + delay) + 's');
To
var newEl = elms[i].cloneNode(true);
newEl.style.setProperty(prop, (cur + delay) + 's', '');
elms[i].parentNode.replaceChild(newEl,elms[i]);
http://jsfiddle.net/FHuKN/28/
Remove the class name ar the attribute value, which the animation is attached to, wait for a bit (setTimeout) of - better - trigger the reflow (say, element.offsetWidth = element.offsetWidth;), and add the class name again.
http://jsfiddle.net/FHuKN/29/
The idea is not mine, all credit goes to Chris Coyer