This question already has answers here:
Using percentage values with background-position on a linear-gradient
(2 answers)
How to animate background-position using percentages when background-size is 100%?
(1 answer)
Closed 4 months ago.
I'm trying to have an animated linear-gradient work vertically, but for some reason it only works when I use a value in px instead of % for the background-position in the keyframes. A percentage would be way better since the width/height of the element is going to change, therefore the background-position should follow.
If the gradient is oriented 90deg, it works but obviously it renders horizontally instead of vertically.
Here is the code :
div {
width: 50px;
height: 150px;
background: linear-gradient(0deg, yellow, orange, red, violet, purple, blue, yellow);
animation: color 5s linear infinite;
margin: 50px auto;
}
#keyframes color {
0% {
background-position: 0%;
}
100% {
background-position: 200%; /* doesn't work */
/*background-position: 0 -150px; -> works fine but not ideal */
}
}
<div></div>
I tried negative value and other background-position variations, without success.
Here is a pen with the code : https://codepen.io/petruhaand1/pen/jOKMrWB
Using aspects from this answer to a similar question, got it working somewhat:
div {
width: 50px;
height: 150px;
margin: 50px auto;
overflow: hidden;
position: relative;
z-index: 0;
}
div:before {
content: "";
position: absolute;
z-index: -1;
top: 0;
left: 0;
right: 0;
background: linear-gradient( 0deg, yellow, orange, red, violet, purple, blue, yellow) top/100% 50%;
bottom: 0;
animation: color 5s linear infinite;
}
#keyframes color {
0% {
background-position: top;
}
100% {
background-position: bottom;
}
}
<div></div>
Related
This question already has an answer here:
How can I apply css transitions to a background image change?
(1 answer)
Closed 3 months ago.
I created a CSS keyframes animation with 5 frames where the background image would fade and change to the next image. The animation works like its supposed to in all cycles except during the first cycle where it glitches before each transition. How to fix this?
HTML:
<div class="container"></div>
CSS:
#keyframes animation1 {
0%, 15%{background-image: url("https://i.imgur.com/IzY1cRC.jpeg");}
20%, 35%{background-image: url("https://i.imgur.com/Bq4PJjC.jpeg");}
40%, 55%{background-image: url("https://i.imgur.com/43idGF1.jpg");}
60%, 75%{background-image: url("https://i.imgur.com/OMa9YYH.jpg");}
80%, 95%{background-image: url("https://i.imgur.com/CTLFd8t.jpg");}
100%{background-image: url("https://i.imgur.com/IzY1cRC.jpeg");}
}
.container{
height: 300px;
width: 550px;
background-image: url("https://i.imgur.com/IzY1cRC.jpeg");
background-position: center center;
background-repeat: no-repeat;
background-size: 100% 100%;
animation-name: animation1;
animation-duration: 25s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
Extremely grateful for any help this has been hindering a couple of projects for a good time.
The first time the animation plays, images will not be loaded yet, the browser will fetch only when they're actually needed.
While the image is loading, the default background will be displayed (in this case, transparent, which will ultimately show the white background of the body)
You can 'pre-load' the images. So the browser already had the image data in cache when it's needed for the animation. There's different techniques for pre-loading. A straightforward way is to add an invisible element that requires all the images used in the animation.
In the example below, we add an 'invisible' :after element that loads all images.
.container::after {
position: absolute;
width: 0;
height: 0;
overflow: hidden;
z-index: -1;
content: url(https://i.imgur.com/IzY1cRC.jpeg) url(https://i.imgur.com/Bq4PJjC.jpeg) url(https://i.imgur.com/43idGF1.jpg) url(https://i.imgur.com/OMa9YYH.jpg) url(https://i.imgur.com/CTLFd8t.jpg) url(https://i.imgur.com/IzY1cRC.jpeg);
}
#keyframes animation1 {
0%,
15% {
background-image: url("https://i.imgur.com/IzY1cRC.jpeg");
}
20%,
35% {
background-image: url("https://i.imgur.com/Bq4PJjC.jpeg");
}
40%,
55% {
background-image: url("https://i.imgur.com/43idGF1.jpg");
}
60%,
75% {
background-image: url("https://i.imgur.com/OMa9YYH.jpg");
}
80%,
95% {
background-image: url("https://i.imgur.com/CTLFd8t.jpg");
}
100% {
background-image: url("https://i.imgur.com/IzY1cRC.jpeg");
}
}
.container {
height: 300px;
width: 550px;
background-image: url("https://i.imgur.com/IzY1cRC.jpeg");
background-position: center center;
background-repeat: no-repeat;
background-size: 100% 100%;
animation-name: animation1;
animation-duration: 25s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
<div class="container"></div>
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>
This question already has answers here:
How to Animate Gradients using CSS
(5 answers)
Closed 1 year ago.
I have a div where the background is divided as follows:
div {
width: 200px;
height: 50px;
background: linear-gradient(135deg, gray 0%, gray 70%, blue 70%, blue 85%, red 85%);
}
div:hover {
animation: animate .5s ease forwards;
}
#keyframes animate {
0% {
background: linear-gradient(135deg, gray 0%, gray 70%, blue 70%, blue 85%, red 85%);
}
100% {
background: linear-gradient(135deg, gray 0%, gray 50%, blue 50%, blue 75%, red 75%);
}
}
<div></div>
As you can see, I would like the stripes in the background to shift on hover (and, indeed, shift back on leave).
I saw all the tutorials suggesting to use background-size and background-position but as I need the proportions to actually change, I don't know that that is the solution here.
I'd like the gradient proportion to animate smoothly, instead of just clipping like they do in the above snippet.
As you have disovered, linear gradients as you have them don't animate.
One simple way of getting a similar but smooth effect is to use scale, which is animatable.
This snippet draws the linear-gradient on a pseudo element and transitions the scale on that, having put the transform origin to the bottom right hand corner. The div has overflow set to hidden.
div {
width: 200px;
height: 50px;
overflow: hidden;
position: relative;
}
div::before {
content: '';
position: absolute;
top: 0;
left: 0;
display: inline-block;
width: 100%;
height: 100%;
transform: scale(1);
transform-origin: right bottom;
transition: transform .5s ease;
background: linear-gradient(135deg, gray 0%, gray 70%, blue 70%, blue 85%, red 85%);
z-index: -1;
}
div:hover::before {
transform: scale(1.5);
}
<div>SOME CONTENT</div>
Take a look at the second and third answers from this post. By animating the opacity of two different gradients or using css variables alongside a transition, you should be able to get the desired result.
I've set up an example of the second method using your code:
#property --gb { /* grey/blue */
syntax: '<percentage>';
inherits: false;
initial-value: 70%;
}
#property --br { /* blue/red */
syntax: '<percentage>';
inherits: false;
initial-value: 85%;
}
div {
--gb: 70%;
--br: 85%;
width: 200px;
height: 50px;
transition: --gb 2s, --br 2s;
background: linear-gradient(135deg, gray 0%, gray var(--gb), blue var(--gb), blue var(--br), red var(--br));
}
div:hover {
--gb: 50%;
--br: 75%;
}
<div></div>
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 have an element with multiple (two) backgrounds
div
{
background: url("bg1.png"), url("bg2.png");
transition: background 1s;
}
div:hover
{
background-position: 0 -20px, 0 -200px;
}
Here, both backgrounds will move in the same time.
How can I have different transition time on them ?
I guess one solution would be to use #keyframes to delay one of the backgrounds animation but I wondered if there was any other way.
Here's a little FIDDLE that might help you.
Relevant CSS:
.testdiv {
width: 200px;
height: 300px;
background-color: red;
background: url("http://upload.wikimedia.org/wikipedia/commons/9/95/Tux-small.png"),
url("http://www.twitip.com/wp-content/uploads/2008/11/twitter-button-small.png");
background-repeat: repeat-x, repeat;
}
.testdiv:hover {
background-position: 0 -20px, 0 -200px;
}