I would like to bring some more interactive elements into my webpage.
What i've seen before on some website's, is that the background image zoom's in slowly and back out. So that it looks more like a living thing.
I've been searching on the internets and here. But i dont know how this technique is done exactly and i dont know the name for this kind of effect.
I also think this should be fairly easy to achiev this with some CSS3 and HTML5.
The questions are:
Is there a name for this effect and what is it called?
Can it be done with pure CSS?
Is there a sample online availble for the basics?
Here is the html i had in mind:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test page</title>
<style>
body {
background-image: url("http://wallpapercave.com/wp/LXR5gFx.png");
background-size: 100% auto;
}
</style>
</head>
<body>
</body>
</html>
The goal is to let the background image zooming in slowly and back out. Like it is breathing.
There is mainly 2 different ways, using either animation or transition.
animation is normally better when one want something running all the time, and transition is more efficient for e.g. hover effects.
Here is a start using animation.
Stack snippet
html, body {
height: 100%;
margin: 0
}
#keyframes breath {
0% { background-size: 100% auto; }
50% { background-size: 140% auto; }
100% { background-size: 100% auto; }
}
#bkg{
width: 100%;
height: 100%;
animation: breath 4s linear infinite;
background: url("http://wallpapercave.com/wp/LXR5gFx.png") center center no-repeat;
}
<div id="bkg"></div>
And here is another using transition and :hover.
Stack snippet
html, body {
height: 100%;
margin: 0
}
#bkg {
width: 180px;
height: 180px;
position: relative;
overflow: hidden;
}
#bkg::before {
content: '';
position: absolute;
left: 0; top: 0;
width: 100%;
height: 100%;
background-size: cover;
background-image: url("http://wallpapercave.com/wp/LXR5gFx.png");
background-position: center;
background-repeat: no-repeat;
transition: transform .5s linear;
}
#bkg:hover::before{
transform: scale(1.3);
}
<div id="bkg"></div>
What you are looking for is called keyframes.
This is the code in the following example.
#keyframes zoom {
0% { transform:scale(1,1); }
50% { transform:scale(1.2,1.2); }
100% {
transform:scale(1,1);
}
}
Css transform has properties which can br run "frame by frame", in the above, we want the picture to be zoomed by the factor 1.2 on the x and y axis by the time 50% of the animation have passed.
We start at no zoom, zoom it by 20% and then we go back tot he original state.
And here is how we add this to the class:
animation: zoom 30s infinite;
just add that to your class and it will run. There are more parameters, but this gets complicated for someone who is unfamiliar with, thus, an easy example.
Here the link to the codepen in action
http://codepen.io/damianocel/pen/QyqRgw
You want to use a separate element with transform(), for three reasons:
It will use the GPU to render the element
It will be more performant in terms of FPS more on that
Animating the body background will cause the entire page to repaint on every frame
Also, animating the background-position will create a juggle effect, as the browser will try to round the position to the nearest pixel.
With a transform: scale() on the other hand, the browser will position the element with subpixel rendering, resulting in a way smoother movement.
#keyframes breath {
from {
transform: scale(1);
}
to {
transform: scale(1.05)
}
}
div{
width: 100vw;
height: 100vh;
animation: breath 2s ease-in-out alternate infinite;
background: url("https://www.placecage.com/800/600");
background-size: cover;
}
body {
margin: 0;
}
<div></div>
Related
in this code:
#p1 {
background-image: url(backimgs/first/1.jpg), url(backimgs/first/2.jpg);
background-color: #05080d;
background-position: left top, left bottom;
background-size: 100% 35%, 100% 65%;
}
I want when the page shows up, first show backimgs/first/1.jpg then after 1 sec show backimgs/first/2.jpg. how can I do it?
You can't animate background-images. You can change it, but there won't be any smooth transition:
#p1 {
background-image: url(backimgs/first/1.jpg), url(backimgs/first/2.jpg);
background-color: #05080d;
background-position: left top, left bottom;
background-size: 100% 35%, 100% 65%;
animation: change-bg;
animation-duration: 1s;
}
#keyframes change-bg {
0% {
background-image: url(backimgs/first/1.jpg), url(backimgs/first/2.jpg);
background-size: 100% 35%, 100% 65%;
}
100% {
background-image: url(backimgs/first/2.jpg), url(backimgs/first/1.jpg);
background-size: 100% 65%, 100% 35%;
}
}
If you want a smooth transition - you can use ::before and ::after with a background and animate the opacity of them. Let me know with a comment if you need more info on this aproach, I'll edit the post and show, how it's done.
You mention 'transition' in the title so you will need to control the two parts of the background separately.
To enable this, this snippet removes the backgrounds from the element itself, instead putting them onto two pseudo elements. The before pseudo element having the first image as background and the after pseudo element having the second one.
Separating the components in this way means we can animate the opacities, the first pseudo element going from opacity 0 to opacity 1 in the first second.
Note however that a little hack has been added to ths snippet. As the animation on the before pseudo element is to happen on load then there needs to be some method of waiting for the background image to load before the animation starts else there is a danger it will be part way through, or even finished, before the image is actually available.
I do not know the wider context of how you are testing for load being complete so have just put a delay in here for demo purposes. You'll need to decide what to do to avoid this inital load situation.
* {
margin: 0;
padding: 0;
}
#p1 {
/* added for this demo */
display: inline-block;
width: 100vw;
height: 100vh;
position: relative;
}
#p1::before,
#p1::after {
content: '';
position: absolute;
z-index: -1;
width: 100%;
left: 0;
display: inline-block;
background-color: #05080d;
background-size: cover;
background-repeat: no-repeat no-repeat;
background-position: center center;
animation: fadein 1s linear;
animation-fill-mode: forwards;
opacity: 0;
}
#p1::before {
top: 0;
height: 35%;
background-image: url(https://picsum.photos/id/1018/1024/768);
animation-delay: 1s;
/* a hack to ensure it is loaded before start the animation */
}
#p1::after {
bottom: 0;
height: 65%;
background-image: url(https://picsum.photos/id/1015/1024/768);
animation-delay: 2s;
}
#keyframes fadein {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<div id="p1"></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>
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 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 * :)
I am trying to use a CSS3 Step Animation to change from one image to another using a simple 2 image sprite sheet. I can't seem to get the second image to load in place of the first image. I have looked at other examples and I really can't see where I am going wrong. So if anyone could help it would be much appreciated. Thanks.
CODEPEN DEMO
<div class="character">
<div class="beak"></div>
</div>
#keyframes newquestion-beak {
from { background-position: 0px 0; }
to { background-position: -100px 0; }
}
.character > div {
background-repeat: no-repeat;
height: 100px;
width: 100px;
position: absolute;
top: 0;
left: 0;
}
.character .beak {
background-image: url(http://s22.postimg.org/6mb37v5sh/compiled_beaks.png);
animation: newquestion-beak .8s steps(2) infinite;
}
Your background positioning wasn't right. Try:
#keyframes newquestion-beak {
from { background-position: -100px 0; }
to { background-position: 100px 0; }
}
Running demo on CodePen
Using "steps(2)" in the animation seems to only move the image halfway. Doubling the 'to' background-position works for me, using Chrome.
Demo with change.