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;
}
}
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.
I would like to make a background animation. Previously I used the following simple CSS solution:
#splash {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
width: 100vw;
height: 100vh;
position: absolute;
top: 0;
left: 0;
border-top: 2em solid #232323;
border-bottom: 2em solid #232323;
background-image: url("../img/splash.jpg");
background-size: cover;
background-position: 0 100%;
animation: moveSplash 15s ease-in-out infinite alternate;
-moz-animation: moveSplash 15s ease-in-out infinite alternate;
-webkit-animation: moveSplash 15s ease-in-out infinite alternate;
/* Safari 4.0 - 8.0 */
transition: opacity .5s;
z-index: 1;
}
#keyframes moveSplash {
from {
background-position-y: 100%;
background-position-x: 0%;
}
to {
background-position-y: 0%;
background-position-x: 100%;
}
}
Which worked perfectly:
whenever the screen was wider than taller, the background picture started to move from the bottom to the top, and it had the same width as the window's
whenever the screen was taller than wider, the background picture started to move from the left to the right, and it had the same height as the window's
HOWEVER, there was one major problem with this method: the animation was very jumpy, that's why I started playing with transition and transform: translate(), but then I could not make the image perfectly fitting.
Is there any workaround out there to achieve a smooth background-image animation keeping it cover-sized?
ANOTHER SOLUTION COULD BE to set image's width and height to 100%, and object-fit to cover. After this I would need to get the computed new dimensions of the image by Javascript or jQuery, however, I have tried .width, .naturalWidth, .offsetWidth, .clientWidth, and they returns 0. When I try this:
var oImg = document.getElementById('splash');
window.getComputedStyle(oImg).transformOrigin.split(' ')[0].replace('px', '')
window.getComputedStyle(oImg).transformOrigin.split(' ')[1].replace('px', '')
I get the window's dimensions (since the object's width and height are set to 100%), not the resized image's new size. If I could get the new size of the image, I could make a calculation where I find the max X and Y values.
Any idea how could I make this animation work smoothly?
Instead of performing the animation on the background-image itself, which is slow, I would suggest animating the entire element.
From what I can see you're trying to animate the background diagonally? Not horizontally and not vertically?
#keyframes moveSplash {
from {
transform: translateY(100%);
transform: translateX(0%);
}
to {
transform: translateY(0%);
transform: translateX(100%);
}
}
If you can't make the image fit the div perfectly when using translate, then that is perhaps what your question really should've been about, because it's kind of "unconventional" to perform the transition on the background-image (because it's slow) and not the entire element (which makes better use of the available memory, and therefor, again – is faster).
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?
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.