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?
Related
I have a reproduction of the issue I'm facing below:
.rect {
transform: rotateZ(45deg);
background-color: #ddd;
position: absolute;
width: 300px;
height: 200px;
animation: 3s linear 0s infinite normal none running widen;
}
#keyframes widen {
from { width: 300px; }
to { width: 500px; }
}
<div class="rect"></div>
Notice how as the rectangle gets wider, its position also changes. It is true that the element's programmatic position isn't changing, but visually on the screen it appears it is.
I am only looking to widen it without having it visually appear to move. That is, the right side of the rectangle should simply extrude out an additional 200 pixels. Is this possible?
Looking around, it seems like setting the transform-origin from center to top left accomplishes this effect, but unfortunately my rectangle's origin of rotation is around its center. Perhaps the solution is to temporarily set it in some way while the effect is occurring..
An easy way to do this is to wrap the grey rectangle div in another div that does the rotating. That way the width and rotation can be controlled independently.
If other transformations need to be applied as well, this approach gives you control over the order the transformations will be applied.
.rect {
transform: rotateZ(45deg);
}
.widen {
background-color: #ddd;
width: 300px;
height: 200px;
animation: 3s linear 0s infinite normal none running widen;
}
#keyframes widen {
from {
width: 300px;
}
to {
width: 500px;
}
}
<div class="rect">
<div class="widen" />
</div>
That squish effect is expected, but for this scenario I'd suggest not animating the size properties anyway since it's going to push your natural DOM flow around with if there's other elements. Instead try scale transform, see below.
.rect {
transform: rotate(45deg);
background-color: #ddd;
position: absolute;
width: 300px;
height: 200px;
transform-origin: center left;
animation: 3s linear widen infinite;
}
/*
#keyframes widen {
from { width: 300px; }
to { width: 500px; }
}
*/
#keyframes widen {
to { transform: rotate(45deg) scaleX(2);
}
<div class="rect"></div>
It looks like it is moving because of the angle. If you want it to grow proportionally, add height to the animation.
Example 1:
.rect {
transform: rotateZ(45deg);
background-color: #ddd;
position: relative;
width: 300px;
height: 200px;
animation: 3s linear 0s infinite normal none running widen;
}
#keyframes widen {
from { width: 300px; height: 200px; }
to { width: 500px; height: 400px; }
}
<div class="rect"></div>
If we remove the rotation, it won't look like it is moving.
Example 2:
.rect {
background-color: #ddd;
position: relative;
width: 300px;
height: 200px;
animation: 3s linear 0s infinite normal none running widen;
}
#keyframes widen {
from { width: 300px; }
to { width: 500px; }
}
<div class="rect"></div>
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.
Ok, my goal is to animate the background image with it sliding up from the bottom when the page loads and once the animation is over set its position to fixed. As far as I can tell the code I've written should work perfectly (I'm pretty new though), but when the animation ends and the javascript adds the position property to the background image, it disappears completely and everything below it moves up to take its place. Can anybody tell me what's wrong with my code?
HTML:
<div style="background-image: url(/resources/css/img/Logo\ Cropped.jpg);" class="background__img--hero"></div>` (set inside the header)
CSS:
#keyframes slideUp {
from {
margin-top: 700px;
}
to {
margin-top: 0px;
}
}
.background__img--hero {
background-size: cover;
background-position: center;
height: 100vh;
animation: slideUp 2s ease-out;
}
Javascript:
document.querySelector('.background__img--hero').addEventListener('animationend', posFix);
function posFix() { document.querySelector('.background__img--hero').style.position = 'fixed'; };
At your .background__img--hero, just add these:
.background__img--hero {
background-size: cover;
background-position: center;
height: 100vh;
width: 100%;
animation: slideUp 2s 1 ease-out forwards;
}
or any width you want your image to have
To animate the position of a position:fixed element, don't animate margins, but animate the position itself (in this cas top), like
#keyframes slideUp {
from {
top: 700px;
}
to {
top: 0px;
}
}
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; }
}
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.