I wanted to ask, what is wrong with this CSS code? It is used to animate background image - zoom effect.
#media (min-width: 1000px) {
.anim-on {
background-size: 110% 110%;
background-position: center center;
animation: shrink 12s infinite alternate;
}
.anim-out {
background-size: 120% 120%;
background-position: center center;
animation: small 6s infinite alternate;
}
#keyframes shrink {
0% {
background-size: 110% 110%;
}
100% {
background-size: 100% 100%;
}
}
#keyframes small {
0% {
background-size: 100% 100%;
}
100% {
background-size: 110% 110%;
}
}
}
This code generates nice effect, but i saw, that on slower machines, affect is bad.
What is wrong? Or maybe someone has better idea, how create this effect, in better technique?
Background size is a visual property and so any change to its value would cause repainting to occur. Painting is a very expensive operation and is bound to have an impact on the performance in low end machines. One way to overcome this would be to use CSS transform (scale to be precise) instead of background-size change to produce the animation.
Snippet which will cause performance impact:
The below snippet uses the same animation as in the question. When you run this snippet and inspect it using Chrome Dev tools (by enabling "Show Paint Rects" option), you'd see that both images have a paint rect associated with them (green or red colored box) and that as the animation is happening the box keeps blinking (or stays as-is). This indicates that a repaint is happening often and thus it impacts performance.
.anim-on,
.anim-out {
height: 200px;
width: 200px;
background: url(http://lorempixel.com/200/200/nature/1);
}
.anim-on {
background-size: 110% 110%;
background-position: center center;
animation: shrink 12s infinite alternate;
}
.anim-out {
background-size: 120% 120%;
background-position: center center;
animation: small 6s infinite alternate;
}
#keyframes shrink {
0% {
background-size: 110% 110%;
}
100% {
background-size: 100% 100%;
}
}
#keyframes small {
0% {
background-size: 100% 100%;
}
100% {
background-size: 110% 110%;
}
}
/* Just for demo */
div {
float: left;
margin-right: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='anim-on'></div>
<div class='anim-out'></div>
Snippet which will cause lesser performance impact:
In the below snippet, I have added the background-image to a pseudo-element and then used scale transform on it to produce the zoom-in/out effect. The parent's overflow: hidden setting prevents the animation from affecting its size. If you inspect this with Chrome Dev tools you'd see that the green or red colored box appears only once when the page is loaded and goes away. This indicates that there is no further repaint is happening during the animation itself and hence it is better from a performance point of view. You'd also notice that this animation is more smoother than the earlier one.
.anim-on,
.anim-out {
position: relative;
height: 200px;
width: 200px;
overflow: hidden;
}
.anim-on:after,
.anim-out:after {
position: absolute;
content: '';
height: 100%;
width: 100%;
top: 0px;
left: 0px;
background: url(http://lorempixel.com/200/200/nature/1);
}
.anim-on:after {
animation: shrink 12s infinite alternate;
}
.anim-out:after {
animation: small 6s infinite alternate;
}
#keyframes shrink {
0% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
#keyframes small {
0% {
transform: scale(1);
}
100% {
transform: scale(1.1);
}
}
/* Just for demo */
div {
float: left;
margin-right: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='anim-on'></div>
<div class='anim-out'></div>
You can find more information about the various CSS properties and how a change to their value will impact the rendering process in the CSS Triggers website.
You can find more information about the rendering process and how using transform (as opposed to few other properties) results in a performance improvement in the below articles/sites:
HTML5 Rocks - Accelerated Rendering in Chrome
GPU Accelerated Compositing in Chrome.
Google Developers - Rendering Performance.
I edited Henry code, now css is reusable, so user can add background image to element via CMS, and css code will do the rest:
.anim {
position: relative;
height: 100vh;
width: 100%;
overflow: hidden;
**background-size: 0px!important;**
}
.anim:after {
position: absolute;
content: '';
height: 100%;
width: 100%;
top: 0px;
left: 0px;
background-size: cover !important;
**background: inherit;**
z-index: -1;
}
.anim:after {
animation: shrink 12s infinite alternate;
}
#keyframes shrink {
0% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
#keyframes small {
0% {
transform: scale(1);
}
100% {
transform: scale(1.1);
}
}
<section class="anim" style="background: url('images/1.png');"></section>
Thanks * :)
Related
I was wondering why my background image is not repeating when I have background repeat set to repeat. I am using bootstrap, that is why there is a col-lg-6 there. I am a new to coding and I wanted to test my skills by making an exact copy of another website. This is the website. If you go to that, you can see exactly want I want.
.image-div {
overflow: hidden;
}
#float {
height: 100%;
width: 100%;
background:url(https://assets.maccarianagency.com/the-front/web-screens/home/home-hero-bg-dark.png);
background-repeat: repeat;
-webkit-animation: moving-img 7s infinite linear;
animation: moving-img 7s infinite linear;
}
#keyframes moving-img {
0% {
transform: translate(0px, 0px) rotate(-15deg) scale(1);
}
100% {
transform: translate(-400px, -600px) rotate(-15deg) scale(1);
}
}
<div class="col-lg-6 image-div" style="height: 80vh; width: 50vw;">
<div id="image"></div>
</div>
One way of thinking of this is that there is a continuous scroll upwards on the image div, and then we rotate that div 15%.
First therefore we need to get a continuous scroll. This can be achieved by putting both a before and after pseudo element on the image div which have the required background. These then both get animated upwards, one starting at top: 0 one starting at top: 100%. That way the scroll is continuous - the after pseudo element follows up immediately after the before one.
So far so good, but when we rotate the image div, there are gaps where the parent div shows through. So we make the before and after pseudo elements twice the size in both directions, get their background images repeated and adjust their positions so they always cover the parent div. The parent is also given overflow: hidden so we don't see the extra bits.
Here is a working snippet. Note that the choice of having the background images 30% of width is arbitrary - change it to what you want.
Note also that the website that is to be copied has a bug, though minor. Every so often you see a slight jerk in the scrolling. We have overcome that problem here by having the two sets of background animate independently so as the second one gets to the top, the first takes on opacity 0 for a split second as it repositions itself back to the top. This fools us into thinking it's all continuous. That website has also put a 'sloping' white over part of the div but that was not part of the question asked here.
.container {
}
.image-div {
position: relative;
overflow: hidden;
}
#image {
position: absolute;
transform: rotate(-15deg) translateX(-25%) translateY(-25%);
height: 200%;
width: 200%;
overflow: hidden;
}
#image::before, #image::after {
content: '';
position: absolute;
height: 100%;
width: 100%;
background-size: 30% auto;
background-image:url(https://assets.maccarianagency.com/the-front/web-screens/home/home-hero-bg-dark.png);
background-repeat: repeat repeat;
-webkit-animation: moving-img 7s infinite linear;
animation: moving-img 7s infinite linear;
z-index: 1;
}
#image::after {
top:100%;
}
#keyframes moving-img {
0% {
transform: translate(0px, 0px);
opacity: 1;
}
99.95% {
transform: translateY(-100%);
opacity: 1;
}
100% {
transform: translate(0, 0);
opacity: 0;
}
}
<div class="col-lg-6 image-div" style="height: 80vh; width: 50vw;">
<div id="image"></div>
</div>
Try below code. Let me know if you succeed.
<style>
.image-div {
overflow: hidden;
}
#float {
height: 100%;
width: 100%;
background:url(https://assets.maccarianagency.com/the-front/web-screens/home/home-hero-bg-dark.png);
background-repeat: repeat;
-webkit-animation: moving-img 7s infinite linear;
animation: moving-img 7s infinite linear;
}
#keyframes moving-img {
0% {
transform: translate(0px, 0px) rotate(-15deg) scale(1);
}
100% {
transform: translate(-400px, -600px) rotate(-15deg) scale(1);
}
}
</style>
<div class="col-lg-6 image-div" style="height: 80vh; width: 50vw;">
<div id="float"></div>
</div>
I've been trying to get a marquee effect with a fog image to work for several days now. I tried several tutorials (videos and written ones), but the effect keeps visibly skipping/restarting and the effect is not seamless. The image itself is 1000px wide and is loopable. The two fog images are different and move at a different speed to have a better effect.
I did manage to get it to work with text, with the help of another tutorial, but the img version still poses problems. To clarify: The images are displayed, they move properly, but at some point the animation restarts/skips/jumps instead of seamlessly repeating the images.
My current version looks like the following (its a vue project):
.fog-container {
top: 0;
height: 100%;
overflow: hidden;
position: absolute;
width: 100%;
z-index: 0;
}
.fog-img {
height: 100%;
position: absolute;
width: 300vw;
}
.fog-img-first {
animation: marquee 120s linear infinite;
background-position: center;
background-repeat: repeat;
background-size: contain;
}
.fog-img-second {
animation: marquee 60s linear infinite;
background-position: center;
background-size: contain;
background-repeat: repeat;
}
#keyframes marquee {
0% {
transform: translate3d(0, 0, 0);
}
100% {
transform: translate3d(-200vw, 0, 0);
}
}
<v-main>
<div class="fog-container">
<div
:style="{'background-image':
`url(${require('./assets/pictures/background/fog_1.png')})`}"
class="fog-img fog-img-first"
/>
<div
:style="{'background-image':
`url(${require('./assets/pictures/background/fog_2.png')})`}"
class="fog-img fog-img-second"
/>
</div>
</v-main>
The animation is moving linearly from left to right but starts abruptly once the animation time is over. Tried with reducing to 1s and increasing the time to 15s. And even increased the keyframes but still doesn't work. Please help:
.grid-item-2 {
grid-column: 1 / span 2;
grid-row: 1;
background-image: url(Building_1.png);
margin-left: 100px;
margin-top: 53px;
width: 90%;
background-repeat: repeat-x;
animation: Buildings 2s linear infinite;
}
#keyframes Buildings {
0% { background-position: 0% 100%; }
25% { background-position: 25% 75%; }
50% { background-position: 50% 50%; }
75% { background-position: 75% 25%; }
100% { background-position: 100% 0; }
}
<div class="grid-item grid-item-2"></div>
The problem with the jumping is that you need to adapt the background image to the size of the div element, which can be hard if you want to have a responsive site. The code below is the best I can come up with, where I loop between -100% and 200%, making the image start outside the element and then end outside the other side of the element, creating the illusion that it continues. I would honestly replace repeat-x with just repeat.
I added a background color just to make the element more visible.
.grid-item-2 {
grid-column: 1 / span 2;
grid-row: 1;
background-image: url("https://picsum.photos/id/737/300/200.jpg");
/* margin-left: 100px;
margin-top: 53px; */
width: 90%;
background-repeat: repeat-x;
background-size: 50% 50%;
animation: Buildings 3s linear infinite;
background-color: #000; /* just to show case the element better */
height: 90vh;
}
#keyframes Buildings {
0% { background-position: -100% 200%; }
100% { background-position: 200% -100%; }
}
<div class="grid-item-2">
</div>
Getting rid of the intermediary keyframes would make it smoother. You only need the frames at 0% and 100%. When you set the animation timing function to linear, it will automatically make sure that all the keyframes that you defined are met. The animation should look something like this...
#keyframes Buildings {
0% {
background-position: 0% 100%;
}
100% {
background-position: 100% 0;
}
}
I'm working on a simple CSS animation and came across a curious problem.
When animating several small divs, if I zoom in or out on Chrome/Firefox the heights of the divs becomes inconsistent - despite them all sharing the same size styles.
Is there any way to address this using CSS? I want the bars to maintain a consistent height without regard to the zoom level. I realize this is something of an edge case, but want to cover as many bases as possible!
Example is here.
HTML
<div class='animation-box animate'>
<div class="animation-bar"></div>
<div class="animation-bar"></div>
<div class="animation-bar"></div>
<div class="animation-bar"></div>
</div>
CSS
.animation-box {
width: 100px;
}
.animation-bar {
animation-duration: 3s;
animation-iteration-count: infinite;
animation-name: bargraph;
animation-timing-function: linear;
background-color: #0d97c1;
height: 3px;
margin: 2px;
}
#keyframes bargraph {
0% {
width: 100%;
}
50% {
width: 10%;
}
100% {
width: 100%;
}
}
What about a simplification with only one element and less of code:
.animation-bar {
animation: bargraph 1.5s infinite linear alternate;
width: 100px;
height: 25px;
background-image: linear-gradient(#0d97c1 50%, transparent 50%);
background-position:0 0;
background-size: 100% 5px;
background-repeat: repeat-y;
}
#keyframes bargraph {
0% {
background-size: 100% 5px;
}
100% {
background-size: 10% 5px;
}
}
<div class="animation-bar"></div>
This is a problem of subpixel rendering. The issue here is that when you are zooming, the space between two bars will have to snap to a given pixel on your screen.
If you have a 3px margin # 150% zoom, the computed space is 4,5px. Meaning that the zoomed space on screen will be inconsistently rendered at 4 or 5px.
On a regular CPU computed dom, your bar will be placed at the closest value, producing those weird gaps.
What you could do to minimize the effect is applying some GPU rendered CSS (opposed to the regular CPU rendering) which is way better at rendering subpixel graphics.
One way of doing that is applying transforms.
.animation-box {
width: 55px;
margin: 0 15px 0 -5px;
}
.animation-bar {
animation: bargraph 1s infinite linear;
transform-origin: top left;
height: 3px;
background-color: #0d97c1;
margin-bottom: 3px;
}
#keyframes bargraph {
0% {
transform: scaleX(1);
}
25% {
transform: scaleX(.8);
}
50% {
transform: scaleX(.6);
}
75% {
transform: scaleX(.8);
}
100% {
transform: scaleX(1);
}
}
<div class='animation-box animate'>
<div class="animation-bar"></div>
<div class="animation-bar"></div>
<div class="animation-bar"></div>
<div class="animation-bar"></div>
</div>
I recommend an excellent article on Smashing Magazine on that topic : CSS GPU Animation: Doing It Right
I am trying to create a ken-burns like effect for image panning - and have seen multiple examples of how to do so. but my resultant code is not working on iOS and is choppy on windows larger screens.
I am using background position - and would like to use transfrom instead - which seems to work better on iOS browsers.
#-webkit-keyframes pan {
0% { background-position: 0% 0%; }
25% { background-position: 100% 100%; }
50% { background-position: 100% 0%; }
75% { background-position: 100% 100%; }
100% { background-position: 0 0; }
}
#keyframes pan {
0% { background-position: 0% 0%; }
25% { background-position: 100% 100%; }
50% { background-position: 100% 0%; }
75% { background-position: 100% 100%; }
100% { background-position: 0 0; }
}
.back {
background: url(big.png) no-repeat;
-webkit-animation: pan 80s ease-in 1s infinite;
animation: pan 80s ease-in 1s infinite;
}
The above works in general browser but is choppy. I have tried to increase the intervals etc. - but it also does not quite work on iOS.
how would I convert the above code to use transform or translate css-property instead ? I understand it is better/faster for performance and smoothness.
thanks