How to create a stepped animation from a strip? - javascript

I'm animating an element background, using a strip - a set of image blocks in a single image - by using only css keyframes. But it doesn't work properly as I don't want the transitions to be linear but in steps:
http://jsbin.com/muyeguba/4/
I tried the "step-end" that shows more or less what I want to achieve. I'm currently reading docs ( http://www.w3.org/TR/css3-transitions/ ) and it seems this is possible, by creating the timing function ourselves ?
Is it possible ? or Would a JS solution be better ?

Here's my CSS for a loading animation from my site. Since you did not provide any images, I'll provide mine as an example.
Pay attention to the animate property. The synatx is as follows:
animation: name duration timing-function delay iteration-count direction;
In my case direction is omitted.
Image:
.loader {
display: inline-block;
width: 32px !important;
height: 32px !important;
background-image: url("loader.png");
background-repeat: no-repeat;
background-size: 2400px 32px;
animation: play16 3.25s steps(75) infinite;
}
#keyframes play32 {
from { background-position: 0px; }
to { background-position: -2400px; }
}
In the steps(75), the number has to match the amount of 'frames' your sprite contains, otherwise the animation will cut off or some frames will repeat.
I use prefix-free to eliminate the need for vendor prefixes. You can either use this, or prefix the code manually.

So, I was doing it wrong:
.animate {
background-image: url(image-strip-with-a-11-block);
width: 53px;
height: 78px;
background-position: 0, 0;
animation:play 1s infinite steps(10);
}
#keyframes play {
0% { background-position: 0px; }
25% { background-position: 100px, 0px; }
50% { background-position: 200px, 0px; }
75% { background-position: 300px, 0px; }
100% { background-position: 400px, 0px; }
}
Should be instead:
.animate {
background-image: url(image-strip-with-a-11-block);
width: 53px;
height: 78px;
background-position: 0, 0;
animation:play 1s infinite steps(10);
}
#keyframes play {
from { background-position: 0px; }
to { background-position: -500px; }
}

Related

Is there any way to animate transform-origin in combination with transform: scale?

So I have an image viewer which has a zoom functionality, which works via the transform: scale() property.
Animating the zoom is no problem with transition: transform .3s.
To make the zoom on the mousewheel go to where the mousewheel is pointed, I calculated the correct position to set the new origin, but when I set it, it just jumps there with no animation.
What I have tried:
Setting transition for the transform-origin property → Doesn't work
Doing it manually in JS with setTimeout and slowly setting the transform-origin at the right position → plays the zoom animation and then jumps
Is there any way to animate both transform: scale() and transform-origin in one go?
Dupe
As the last question has been closed as a duplicate of How to have multiple CSS transitions on an element?, here is a snippet, to show you that this is not my question.
const img = document.querySelector('#container img');
let on = true;
const toggleEffect = () => {
if(on) {
img.style.transform = 'scale(2.5)';
img.style.transformOrigin = '80% 80%';
} else {
img.style.transform = 'scale(1.4)';
img.style.transformOrigin = '20% 20%';
}
on = !on;
};
#container {
width: 500px;
height: 300px;
overflow: hidden;
background-color: red;
}
#container img {
height: 100%;
width: 100%;
object-fit: contain;
transform: scale(1.4);
transform-origin: 20% 20%;
transition: transform .3s, transform-origin .3s;
}
<div id="container">
<img src="https://images.unsplash.com/photo-1482066490729-6f26115b60dc?ixlib=rb-1.2.1&auto=format&fit=crop&w=2004&q=80"/>
</div>
<button onclick="toggleEffect()">Toggle</button>
EDIT: Technically this is a duplicated. (Chrome Bug in some versions)
- Using both transition:
body, div {
width: 100%;
height: 100vh;
overflow: hidden;
}
div {
background-color: gray;
width: auto;
display: flex;
justify-content: center;
align-items: center;
font-size: 30px;
transform: scale(1.1);
transform-origin: 50% -30px -100px;
transition: transform-origin .2s ease-in-out, transform 4s ease-in-out;
}
div:hover {
transform: scale(1.7);
transform-origin: 100px 100px;
}
<div>Test</div>
- Using animation with#keyframes:
body,div {
width: 100%;
height: 100vh;
}
div {
width: auto;
display: flex;
justify-content: center;
align-items: center;
transform-origin: 0 0 0;
animation: scale-origin 3s infinite;
font-size: 30px;
}
#keyframes scale-origin {
0% {
transform: scale(.5);
transform-origin: 100px 100px 1000px;
}
100% {
transform: scale(1.1);
transform-origin: left 500px -30px
}
}
<div>Test</div>
For me the only way to get around this bug was to ensure a redraw of the element on each "animation" (in this case transition) frame as you can clearly see via getComputedStyle that the transform-origin is correctly transitioned!
Basically I added eventlisteners for the transitionstart and transitionend and on each animationframe toggle some style attribute that enforces a redraw (f.e. in my case margin-left from 0 to 1 to 0px until the animation is finished)
function forceRedraw(ts) {
this.style.marginLeft = this.style.marginLeft == '1px' ? '0px':'1px';
if (this.classList.contains('transitioning'))
requestAnimationFrame(forceRedraw.bind(this));
}
In my example I transition rotation and the transform-origin (from top left to bottom left) at the same time.
https://codepen.io/ftav/pen/QWvYEPj
Depending on which element you modify this might have more or less of a performance impact. It works fine for me. I just wish they would fix the bug and this workaround could go away.

ReactJS Click and Hold Button

I'm creating a React App which is able to shut down physical devices (like power sources etc.)
For every device, I have a shutdown button which needs to be pressed and hold for 3 seconds to activate. In addition to that, I need a animation that shows the remaining time of this 3 seconds to the user: which exactly looks like :
http://sonsoleslp.github.io/react-click-n-hold/
However, I am getting errors when I import the CSS to my CSS file that is
#-webkit-keyframes fill {
to {
background-size: 100% 0;
}
}
#keyframes fill {
to {
background-size: 100% 0;
}
}
.cnh_holding button {
background: -webkit-linear-gradient( white , white) rgb(255,215,235) no-repeat 0 0;
background: linear-gradient( white , white) rgb(255,215,235) no-repeat 0 0;
mix-blend-mode: multiply;
background-size: 100% 100%;
-webkit-animation: fill 2s forwards;
animation: fill 2s forwards;
}
Whole CSS code is up there.
I tried changing the CSS but animation does not work this time. Is there any suggestion?
It works if you add from{} before to{}
#-webkit-keyframes fill {
from {background-size: 100% 100%;}
to {
background-size: 100% 0;
}
}
#keyframes fill {
from {background-size: 100% 100%;}
to {
background-size: 100% 0;
}
}
.cnh_holding button {
background: -webkit-linear-gradient( white , white) rgb(255,215,235) no-repeat 0 0;
background: linear-gradient( white , white) rgb(255,215,235) no-repeat 0 0;
mix-blend-mode: multiply;
background-size: 100% 100%;
-webkit-animation: fill 2s forwards;
animation: fill 2s forwards;
}
<div class="cnh_holding"><button>CLICK</button></div>

When background image scaled, it starts to flicker in Chrome

I have a div with a background image on it. When it has simple transform scale animation, it starts to flicker in Google Chrome and Opera.
Here is a simple exmple:
http://codepen.io/anon/pen/bWpNYq
CSS:
body {
height: 100vh;
overflow: hidden
}
div {
width: 100%;
height: 100%;
background-color: #f00;
background-position: 50% 50%;
background-image: url(".....jpg");
background-size: cover;
}
Script:
TweenLite.set('div', {
backfaceVisibility: 'hidden',
perspective: 1000
});
TweenLite.fromTo('div', 10, {
scale: 1.1
}, {
scale: 1
});
When the image is a simple img element, the same scale animation works fine. The transition is smooth:
http://codepen.io/anon/pen/pPyvdp
The examples use GASP for animations. I need a solution which use GSAP to scale the div with better result.
Do you any idea how to make it smooth with background image?
Try this:
Add transition: all 1s linear; so it scale smoothly.
body {
height: 100vh;
overflow: hidden
}
div {
width: 100%;
height: 100%;
background-position: 50% 50%;
background-image: url("https://smartslider3.com/wp-content/uploads/2015/10/slide52.jpg");
background-size: cover;
transition: all 1s linear;
}
Hey maybe you can try out this css animation. For better browser support add
-webkit-animation
-moz-animation
-o-animation
body {
height: 100vh;
overflow: hidden
}
div {
width: 100%;
height: 100%;
background-position: 50% 50%;
background-image: url("https://smartslider3.com/wp-content/uploads/2015/10/slide52.jpg");
background-size: cover;
-webkit-animation: animate 5s forwards;
animation: animate 5s forwards;
}
#-webkit-keyframes animate {
0% { transform: scale(1); }
100% { transform: scale(1.1); }
}
#keyframes animate {
0% { transform: scale(1); }
100% { transform: scale(1.1); }
}
<div>
</div>
CSS3 allows you to add native transition to your transformations. Try to use code below:
document.body.addEventListener('click', function(){
var div = document.getElementById('img');
div.style.transform = 'scale(.5)';
})
body {
height: 100vh;
overflow: hidden
}
div {
width: 100%;
height: 100%;
background-position: 50% 50%;
background-image: url("https://smartslider3.com/wp-content/uploads/2015/10/slide52.jpg");
background-size: cover;
transition: transform 30s;
}
<div id="img"></div>
It uses css property "transition" and starts transition on body click.
Just use css, way better. If you open up your inspector you'll see that your tweenlite code is setting/ updating the style attribute of your div very fast with this piece of code: transform: translate3d(0px, 0px, 0px) scale(1.00212, 1.00212);.
This is JS calculating something and then telling CSS what to do (very basic explanation). CSS can do this on it's own. Why do you want to stick with your GSAP engine so badly?

How to make a permanent change background-position in js?

I know how to run the animation from point A to point B, so to speak, but do not know how to run continuously in a circle. Below is a small code prepared:
.bg {
display: block;
position: absolute;
width: 100%;
height: 100%;
background: url(http://www.dejurka.ru/wp-content/uploads/2015/06/watercolor-patterns4.jpg) top left/30%;
animation: bg 2s cubic-bezier(0, -0.02, 1, 0.99);
}
#keyframes bg {
0% {
background-position: left -100px;
}
100% {
background-position: left 0px;
}
}
<div class="bg"></div>
help with script
If by:
run continuously in a circle
You mean run animation in a loop, then you can add the infinite animation-iteration-count property. In the shortcode you can just add infinite to your animation property. See demo:
.bg {
display: block;
position: absolute;
width: 100%;
height: 100%;
background: url(http://www.dejurka.ru/wp-content/uploads/2015/06/watercolor-patterns4.jpg) top left/30%;
animation: bg 2s cubic-bezier(0, -0.02, 1, 0.99) infinite;
}
#keyframes bg {
0% {
background-position: left -100px;
}
100% {
background-position: left 0px;
}
}
<div class="bg"></div>
Edit: jQuery Solution
With jQuery you can use the animate() function to achieve the same effect.
// bg animation function
function bgAnimate(speed) {
// define bg div
var el = $('.bg');
// get current background y-axis position and convert to integer (strips `px`)
var posY = parseInt(el.css("background-position-y"));
// animate element
el.animate({
'background-position-y': posY + 100 // add 100px
},{
duration: speed,
easing: 'linear',
complete: function() {
bgAnimate(speed); // repeat aniamtion (loop)
}
});
}
bgAnimate(1000); // call function
html, body {padding: 0;margin: 0;}
.bg {
display: block;
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
background-image: url(http://www.dejurka.ru/wp-content/uploads/2015/06/watercolor-patterns4.jpg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="bg"></div>

Zoom only a specific portion of an image in pure CSS

I have a div with a width of 800 and a height of 300 pixels.
I also have an .svg image that's set as the background-image of this div, and using css3 animations I make this image scroll left to right, indefinitely (it's a landscape) and wrapping.
I would like to put a circle in the middle of this div, and make the inside of this circle "zoom" the background. I'd love to have this pure CSS.
I've tried some masking and clipping, but nothing seemed to do the trick.
Is this possible with the current CSS specifications? A JavaScript solution would also be acceptable.
Here's an image showing what I mean:
If you look closely, you can see a circle in the middle, which should zoom the clouds behind it, as if looking through a magnifying glass.
Trying to get it reusing the same animation, without extra elements:
CSS
.test {
position: absolute;
width: 600px;
height: 400px;
left: 0px;
background-image: url(http://placekitten.com/1000/400);
background-size: 1000px;
-webkit-animation: base linear 20s infinite;
background-position-x: 0px;
background-position-y: 50%;
}
.test:after {
content: "";
position: absolute;
left: 200px;
width: 200px;
top: 100px;
height: 200px;
border-radius: 50%;
background: inherit;
-webkit-transform: scale(1.1);
-webkit-animation: inherit;
-webkit-animation-delay: -4s;
}
#-webkit-keyframes base {
0% { background-position-x: 0px; }
100% { background-position-x: -1000px; }
}
The trick is to set the animation in sync delaying it; just calculate the equivalence in time of the x offset.
fiddle
throw your zoom div into the pic div and give it a background image of a larger version of the same image.

Categories

Resources