I want to use a responsive div with a scrolling background image.
In the example I showed it small and large. I want the entire scroll to be constant - so the small div should take x seconds and the large div should also take x seconds (rather than the small one taking less time to complete a whole image pan than the larger one).
I've tried using percentage values in background-position-x but it stops the animation.
.offset {
background-image: url('https://upload.wikimedia.org/wikipedia/commons/c/c4/PM5544_with_non-PAL_signals.png');
background-size: 100%;
animation: slideLeft768px 5s linear infinite;
}
.div1 {
width: 76.8px;
height: 57.6px;
}
.div2 {
width: 768px;
height: 576px;
}
#keyframes slideLeft768px {
0% {
background-position-x: 768px;
}
100% {
background-position-x: 0px;
}
}
<div class="offset div1"></div>
<div class="offset div2"></div>
====================
This is based on Temani Afif's answer:
.offset {
background-image: url('https://upload.wikimedia.org/wikipedia/commons/c/c4/PM5544_with_non-PAL_signals.png');
background-size: 100%;
animation: slideLeft 5s linear infinite;
width: var(--p);
--p: 40vw;
height: 30vw;
}
.div1 {
--p: 12vw;
height: 9vw;
}
#keyframes slideLeft {
0% {
background-position-x: var(--p);
}
100% {
background-position-x: 0px;
}
}
<div class="offset div1"></div>
<div class="offset div2"></div>
I made it only use responsive units so it adjusts when you resize the window.
You can consider CSS variable to make the animation dynamic:
.offset {
background-image: url('https://upload.wikimedia.org/wikipedia/commons/c/c4/PM5544_with_non-PAL_signals.png');
background-size: 100%;
animation: slideLeft768px 5s linear infinite;
width: var(--p);
}
.div1 {
--p: 76.8px;
height: 57.6px;
}
.div2 {
--p:768px;
height: 576px;
}
#keyframes slideLeft768px {
0% {
background-position: var(--p,0px) 0px;
}
100% {
background-position: 0px 0px;
}
}
<div class="offset div1"></div>
<div class="offset div2"></div>
And since your are using the same image with known dimension you can optimize your code like below:
.offset {
background-image: url('https://upload.wikimedia.org/wikipedia/commons/c/c4/PM5544_with_non-PAL_signals.png');
background-size: 100%;
animation: slideLeft768px 5s linear infinite;
width: calc(768px * var(--p,1));
height: calc(576px * var(--p,1));
}
.div1 {
--p: 0.1;
}
.div2 {
--p:0.2;
}
#keyframes slideLeft768px {
0% {
background-position: calc(768px * var(--p,1)) 0px;
}
100% {
background-position: 0px 0px;
}
}
<div class="offset div1"></div>
<div class="offset div2"></div>
<div class="offset" style="--p:0.8"></div>
You can also check this answer (https://stackoverflow.com/a/51734530/8620333) to understand why percentage value won't work and how to make it working.
The trick is to use a percentage for the background-position. Since setting the background-size to 100% makes this impossible, we need to set it to another value.
A trick is to use the padding for this. Create a padding right the same dimension than the width. Making the background origin the paddin box, and clip tghe content box, now we can set the size to 50%. Visually, nothing will change. (In case that the extra padding is a problem, you could set a negative margin or a clip-path). And now, the background-position can be moved in percentages:
.offset {
background-image: url('https://upload.wikimedia.org/wikipedia/commons/c/c4/PM5544_with_non-PAL_signals.png');
background-size: 50%;
background-origin: border-box;
background-clip: content-box;
animation: slideLeft768px 5s linear infinite;
}
.div1 {
width: 76.8px;
padding-right: 76.8px;
height: 57.6px;
}
.div2 {
width: 768px;
padding-right: 768px;
height: 576px;
}
#keyframes slideLeft768px {
0% {
background-position-x: 100%;
}
100% {
background-position-x: 0%;
}
}
<div class="offset div1"></div>
<div class="offset div2"></div>
Related
I have an image of a butterfly, something like this.
I am trying to figure out if there is any way to make it look like its wings are opening and closing with a 3D CSS transform/translate or animation, but without having to split the image up into parts (it can be a background image of a div though if that helps).
Yes, using background applied to two elements where each one will show only one half and then you simply rotate both on the Y axis.
.box {
width:300px;
margin:20px;
display:flex;
perspective:500px;
}
.box::before,
.box::after{
content:"";
padding-top:56%; /* ratio based on your image */
flex:1; /* half the main element size */
background-image:url(https://i.imgur.com/DgMoHC5.jpg);
background-size:200% 100%; /* twice bigger than the pseudo element to get half the image*/
animation:left 1s linear infinite alternate;
transform-origin:right;
}
.box::after {
background-position:right; /* get the right part of the image */
animation-name:right;
transform-origin:left;
}
#keyframes left{
to {transform:rotateY(60deg)}
}
#keyframes right{
to {transform:rotateY(-60deg)}
}
<div class="box"></div>
A more realistic animation with some translation:
.box {
width: 300px;
margin: 20px;
display: flex;
perspective: 500px;
}
.box::before,
.box::after {
content: "";
padding-top: 56%;
flex: 1;
background-image: url(https://i.imgur.com/DgMoHC5.jpg);
background-size: 200% 100%;
animation: left 0.5s linear infinite alternate;
transform-origin: right;
}
.box::after {
background-position: right;
animation-name: right;
transform-origin: left;
}
#keyframes left {
from {
transform: translateZ(80px) rotateY(-30deg)
}
to {
transform:translateZ(0px) rotateY(50deg)
}
}
#keyframes right {
from {
transform: translateZ(80px) rotateY(30deg)
}
to {
transform:translateZ(0px) rotateY(-50deg)
}
}
<div class="box"></div>
I want to create a shine loading animation which will appear on multiple elements with different background colors.
Currently, I'm using background-image gradient and I'm animating the background-position using vw units, but it's not scalable, my elements will have different lengths.
Is there a way I can animate background-image with percentage units?
The animation created
body {
background: black;
}
header {
width: 100%;
height: 50px;
background-color: rebeccapurple;
background-image: linear-gradient(
to right,
transparent 0%,
rgba(255,255,255,0.3) 50%,
transparent 100%
);
background-repeat: no-repeat;
background-position: -100vw;
animation: shine 2s infinite;
}
#keyframes shine {
0% {
background-position: -100vw;
}
100% {
background-position: 100vw;
}
}
<header></header>
An idea is to make the size of the gradient to be 3 times bigger than the container and color the middle part of it then you slide it from left to right:
body {
background: black;
}
.box {
height: 50px;
margin:5px;
background:
linear-gradient(90deg,#0000 33%,rgba(255,255,255,0.3) 50%,#0000 66%)
rebeccapurple;
background-size:300% 100%;
animation: shine 2s infinite;
}
#keyframes shine {
0% {
background-position: right;
}
/*100% {
background-position: left; it's the default value, no need to define it
}*/
}
<div class="box"></div>
<div class="box" style="width:60%"></div>
<div class="box" style="width:40%"></div>
Another alternative for a different animation:
body {
background: black;
}
.box {
height: 50px;
margin:5px;
background:
repeating-linear-gradient(90deg,#0000 0,rgba(255,255,255,0.3) 25%,#0000 50%)
rebeccapurple;
background-size:200% 100%;
animation: shine 1s infinite linear;
}
#keyframes shine {
0% {
background-position: right;
}
}
<div class="box"></div>
<div class="box" style="width:60%"></div>
<div class="box" style="width:40%"></div>
Related question: Using percentage values with background-position on a linear-gradient
I'm working with css animation with steps...my problem is:
when step() == (frame length -1) everything is fluid exept that I can't see the last frame
when step() == frame length I can't still see the last frame and animation is messy...
I'm looking for a way to use background 100% (or at least an explanation of why it doesn't work), for I can use it with sprites with differents number of frames and just use step() to adjust to the actual sprite..
Demo:
#sprite1, #sprite2, #sprite3 {
height: 41px;
width: 41px;
background: url('https://img4.hostingpics.net/thumbs/mini_756487pacanim2.png') 0 center;
}
#sprite1 {
animation: sprite 1s steps(3) infinite;
}
#sprite2 {
animation: sprite 1s steps(4) infinite;
}
#sprite3 {
animation: sprite2 1s steps(4) infinite;
}
#keyframes sprite {
100% { background-position: right center; }
}
#keyframes sprite2 {
100% { background-position: 164px center; }
}
Case1: <br>
<div id="sprite1"></div>
Case2:
<div id="sprite2"></div>
What it should be:
<div id="sprite3"></div>
Required. Percentage of the animation duration.
Legal values:
0-100%
from (same as 0%)
to (same as 100%)
Note: You can have many keyframes-selectors in one animation.
sprit image 4 one start on 50% so i gave. check below sample code.
#sprite1, #sprite2, #sprite3 {
height: 41px;
width: 41px;
background: url('https://img4.hostingpics.net/thumbs/mini_756487pacanim2.png') 0 center;
}
#sprite1 {
animation: sprite 1s steps(3) infinite;
}
#sprite2 {
animation: sprite3 1s steps(3) infinite;
}
#sprite3 {
animation: sprite2 1s steps(4) infinite;
}
#keyframes sprite {
60% { background-position: right center; }
}
#keyframes sprite2 {
100% { background-position: 164px center; }
}
#keyframes sprite3 {
50% { background-position: right center; }
}
Case1: <br>
<div id="sprite1"></div>
Case2:
<div id="sprite2"></div>
What it should be:
<div id="sprite3"></div>
You need to change the initial position to be background-position:-33% center; instead of background-position: 0 center;
in this case the four steps will work like this:
step1: background-position: -33% center; which will display img4
step2: background-position: 0% center; which will display img1
step3: background-position: 33% center;which will display img2
step4: background-position: 66% center;which will display img3
#sprite1 {
height: 41px;
width: 41px;
background: url('https://img4.hostingpics.net/thumbs/mini_756487pacanim2.png') -33% center;
}
#sprite1 {
animation: sprite 1s steps(4) infinite;
}
#keyframes sprite {
100% { background-position: right center; }
}
<div id="sprite1"></div>
Try this:
10 = frames/steps;
For Edge you have to calculate the percentage;
#keyframes sprite{
100%{
background-position: calc(100% / (10 - 1) * 10) 0;
background-position: 111.111% 0;/* Edge/IE */
}
}
#container {
width: 50px;
height: 72px;
animation: container 1s linear infinite;
}
#keyframes container {
50% {
width: 72px;
height: 50px;
}
}
#sprite {
width: 100%;
height: 100%;
background-color: red;
background-image: url(http://i.imgur.com/xtk0SCC.png);
background-position: 0% 0;
background-size: calc(100% * 10) 100%;
background-repeat: no-repeat;
animation: sprite 1s steps(10) infinite;
}
#keyframes sprite {
100% {
background-position: calc(100% / (10 - 1) * 10) 0;
background-position: 111.111% 0;/* Edge/IE */
}
}
<div id="container">
<div id="sprite"></div>
</div>
I'm trying to implement a full-screen infinite scrolling background effect, which must extend on the entire height and width of the viewport.
Here's the demo.
The solution I've tried was to take a wrapper element that has 100vh and 100vw of the viewport, then place 2 divs inside it, 100% of its height, that have the same background-image and background-size: cover property. The size of the image I've used is: 1,920px × 808px.
Then I've applied the following animation on the wrapper element:
#keyframes infiniteScrollBg {
0% {
transform: translateY(0%);
}
100%{
transform: translateY(-100%);
}
}
But the problem is that on some viewport sizes, the images are not repeating correctly (because of background-size: cover property):
.
Here's the full code I've tried:
<div class="animated-scene">
<div class="animated-scene__frame animated-scene__frame-1"></div>
<div class="animated-scene__frame animated-scene__frame-2"></div>
</div>
And the css:
.animated-scene {
width: 100vw;
height: 100vh;
position: fixed;
min-height: 400px;
animation: infiniteScrollBg 50s linear infinite;
}
.animated-scene__frame {
width: 100%;
height: 100%;
background-size: cover;
background-color: #4277a3;
background-image: url('https://andreivictor.ro/codepen/fullscreen-infinite-scroll-bg/fullscreen-bg');
}
Do you have any idea on how could I implement this effect?
Thanks for your help.
For scrolling background, I used background-position instead of using additional element and animate it using transform css properties.
Why you might asked?
Pattern will be seamlessly stitched by the browsers
cleaner HTML code. We just need one element to do this.
The only const doing this method is you need to know the dimension of image you are using.
Example :
/*
specify the scroll x (or y) with the width (or height) of the images
In this case, the image dimension is :
width: 1920px;
height: 808px;
*/
#keyframes bgScroll {
0% {
background-position : 0px 0px
}
100% {
background-position : 0px -808px
}
}
.scrollingBG {
display:block;
width:100vw;
height:100vh;
background-image:url("https://andreivictor.ro/codepen/fullscreen-infinite-scroll-bg/fullscreen-bg.jpg");
animation: bgScroll 20s linear infinite;
}
<div class='scrollingBG'></div>
I have used an image element just to use the auto height of it.
Then I use a backgroiund on a pseudo that gives the ability to repeat itself as many times as needed
I have set 2 different containers with different aspect ratios to more easily check the result on different screens
.container {
border: solid 1px black;
overflow: hidden;
position: absolute;
}
#ctn1 {
width: 300px;
height: 150px;
}
#ctn2 {
width: 200px;
height: 350px;
left: 320px;
}
.inner {
width: 100%;
position: relative;
animation: scroll 5s infinite linear;
}
.inner:after {
content: "";
height: 500%;
width: 100%;
position: absolute;
background-image: url(https://i.stack.imgur.com/FlK9o.jpg);
background-size: 100% 20%;
}
.img {
width: 100%;
}
#keyframes scroll {
from {transform: translateY(-100%);}
to {transform: translateY(-200%);}
}
<div class="container" id="ctn1">
<div class="inner">
<img class="img" src="https://i.stack.imgur.com/FlK9o.jpg">
</div>
</div>
<div class="container" id="ctn2">
<div class="inner">
<img class="img" src="https://i.stack.imgur.com/FlK9o.jpg">
</div>
</div>
A better solution with media query used to change the way the image is used.
Notice that background-size: cover is needed when both the aspect ratio of the image and the window is unknown. Since you know the aspect ratio of your image, you can control the display with a media query based on it.
Now, when it's needed, the image will adapt not to the width of the container, but to the height of it
#media screen and (max-aspect-ratio: 4/3) {
.inner {
height: 100%;
width: auto !important;
}
.img {
height: 100%;
width: auto !important;
}
}
.container {
border: solid 1px black;
display: inline-block;
overflow: hidden;
}
#ctn1 {
width: 300px;
height: 150px;
}
#ctn2 {
width: 200px;
height: 350px;
}
.inner {
width: 100%;
position: relative;
animation: scroll 5s infinite linear;
display: inline-block;
}
.inner:after {
content: "";
height: 500%;
width: 100%;
left: 0px;
position: absolute;
background-image: url(https://i.stack.imgur.com/FlK9o.jpg);
background-size: 100% 20%;
}
.img {
width: 100%;
}
#keyframes scroll {
from {transform: translateY(-100%);}
to {transform: translateY(-200%);}
}
<div class="container" id="ctn1">
<div class="inner">
<img class="img" src="https://i.stack.imgur.com/FlK9o.jpg">
</div>
</div>
<div class="container" id="ctn2">
<div class="inner">
<img class="img" src="https://i.stack.imgur.com/FlK9o.jpg">
</div>
</div>
The issue is with aspect ratio. You're setting the aspect ratio to the view window, and not the image size. So your image ends up getting cut off at the view window aspect.
I worked around in your codepen by changing .animated-scene__frame to this:
.animated-scene__frame {
width: 100%;
height:200vh; //easy way - increase height in animated div to prevent image cutoff. Ideally should be done through javascript using like a 3x multiple of the height of the image. Then just rely on background-repeat during the animation :)
background-size:contain;
background-color: #4277a3;
background-image: url('https://andreivictor.ro/codepen/fullscreen-infinite-scroll-bg/fullscreen-bg-slide1.jpg');
}
I would recommend to just extend the picture 3 times, with:
#keyframes infiniteScrollBg {
0% {
transform: translateY(0%);
}
100%{
transform: translateY(-66.66%);
}
}
Use some image editor and create a large image with the same pattern, take a look of this site that I made site, there you will find some infinite background pattern
You must use background-position property.
Here's fixed example http://codepen.io/azamat7g/pen/BRwRVV
Full code:
#keyframes infiniteScrollBg {
0% {
transform: translateY(0%);
}
100%{
transform: translateY(-100%);
}
}
.animated-scene {
width: 100vw;
height: 100vh;
position: fixed;
min-height: 400px;
animation: infiniteScrollBg 50s linear infinite;
}
.animated-scene__frame {
width: 100%;
height: 100%;
background-size: cover;
background-position: bottom left;
background-color: #4277a3;
background-image: url('https://andreivictor.ro/codepen/fullscreen-infinite-scroll-bg/fullscreen-bg-slide1.jpg');
}
.bottom{
background-position: top left;
}
<div class="animated-scene">
<div class="animated-scene__frame animated-scene__frame-1"></div>
<div class="animated-scene__frame animated-scene__frame-2 bottom"></div>
</div>
I am simply trying to reverse the direction my pure css horizontal image slider is sliding. I have tried altering the key frame animation portion with opposite direction, with both - position and toggling left to right, all my attempts do is allow one slide to slide in the correct direction and then just blank white space due to my images float: left;
Here is live jsFiddle. And here is a Jsfiddle of my attempt and how it's rendering (ie. not working. it slides through one image in the correct direction, but not the rest)
Also, my code below.
Mark-Up:
<div class="slider3">
<figure>
<img src="http://img00.deviantart.net/a251/i/2007/347/c/8/drunk_santa_by_yakuks.png">
<img src="http://img00.deviantart.net/a251/i/2007/347/c/8/drunk_santa_by_yakuks.png">
<img src="http://img00.deviantart.net/a251/i/2007/347/c/8/drunk_santa_by_yakuks.png">
<img src="http://img00.deviantart.net/a251/i/2007/347/c/8/drunk_santa_by_yakuks.png">
</figure>
</div>
CSS:
.slider3 {
width: 100%;
max-width: 960px;
overflow: hidden;
}
.slider3 figure img {
width: 25%;
float: left;
background: red;
}
.slider3 figure{
width: 400%;
position: relative;
margin:0;
padding: 0;
animation: 10s slide infinite;
-webkit-animation: 10s slide infinite;
}
#-webkit-keyframes slide {
0% { left:0%; }
16% { left:0%; }
33% { left:-100%; }
49% { left:-100%; }
66% { left:-200%; }
82% { left:-200%; }
100% { left:-300%; }
}
Actually you don't have to do any modifications other than add animation-direction: reverse to the list of rules (or you can set it as a value in the animation shorthand). As you'd have guessed, adding this property-value pair would reverse the flow of your animation.
When you place 4 images on a page (with float: left and 100% width for each), the 1st image is at 0%, the 2nd is at 100%, 3rd at 200% and 4th at 300%. What your current animation does is - start with the left: 0% which means the first image is in view. After sometime the left offset is set as -100% and what this means is that the second image which was at 100% on the page will now get displayed (as 100% - 100% = 0% and so it lands in the viewing area). Similarly the 3rd and 4th also gets shown.
Now to reverse the animation, you need the left offset to start at -300% so that the fourth image is visible first and then it slides towards the right instead of slide towards the left. Note: If you want the first image in the DOM to show up first then change float:left to right for .slider3 figure img.
With fourth image in DOM appearing first: (float: left)
.slider3 {
width: 100%;
max-width: 960px;
overflow: hidden;
}
.slider3 figure img {
width: 25%;
float: left;
background: red;
}
.slider3 figure {
width: 400%;
position: relative;
margin: 0;
padding: 0;
animation: 10s slide infinite reverse backwards;
-webkit-animation: 10s slide infinite reverse backwards;
}
#-webkit-keyframes slide {
0% {
left: 0%;
}
16% {
left: 0%;
}
33% {
left: -100%;
}
49% {
left: -100%;
}
66% {
left: -200%;
}
82% {
left: -200%;
}
100% {
left: -300%;
}
}
#keyframes slide {
0% {
left: 0%;
}
16% {
left: 0%;
}
33% {
left: -100%;
}
49% {
left: -100%;
}
66% {
left: -200%;
}
82% {
left: -200%;
}
100% {
left: -300%;
}
}
<div class="slider3">
<figure>
<img src="http://lorempixel.com/200/200/nature/1">
<img src="http://lorempixel.com/200/200/nature/2">
<img src="http://lorempixel.com/200/200/nature/3">
<img src="http://lorempixel.com/200/200/nature/4">
</figure>
</div>
With first image in DOM appearing first: (float: right)
.slider3 {
width: 100%;
max-width: 960px;
overflow: hidden;
}
.slider3 figure img {
width: 25%;
float: right;
background: red;
}
.slider3 figure {
width: 400%;
position: relative;
margin: 0;
padding: 0;
animation: 10s slide infinite reverse backwards;
-webkit-animation: 10s slide infinite reverse backwards;
}
#-webkit-keyframes slide {
0% {
left: 0%;
}
16% {
left: 0%;
}
33% {
left: -100%;
}
49% {
left: -100%;
}
66% {
left: -200%;
}
82% {
left: -200%;
}
100% {
left: -300%;
}
}
#keyframes slide {
0% {
left: 0%;
}
16% {
left: 0%;
}
33% {
left: -100%;
}
49% {
left: -100%;
}
66% {
left: -200%;
}
82% {
left: -200%;
}
100% {
left: -300%;
}
}
<div class="slider3">
<figure>
<img src="http://lorempixel.com/200/200/nature/1">
<img src="http://lorempixel.com/200/200/nature/2">
<img src="http://lorempixel.com/200/200/nature/3">
<img src="http://lorempixel.com/200/200/nature/4">
</figure>
</div>
You'd notice that I have added a backwards also to the animation short-hand property. This stands for animation-fill-mode and it makes the element hold the state as at its last keyframe until the time the animation starts. If this isn't added there will be a snap at the start where the first image will display before immediately changing to 4th (no slide) with float:left and vice-versa for float: right.
Amr Aly's second answer will work (and there are other possible ways too) but there is absolutely no reason to make it so complex.