Only one CSS animation bar at any point of time - html

I am using CSS animation to show an indeterminate progress bar. Refer code below. If you'll notice there are 2 moving gradient at any point of time, i.e. when the 1st one reaches 50% of the width, 2nd one starts. I know that I have defined the css that way using webkit-background-size(50% and 100%). However what I am not able to do is make sure that there should be only 1 moving part at any point of time - i.e. once the animation reaches the right end of the div only then it should start it from the left end. Any pointers on this?
Refer https://jsfiddle.net/AnuragSinha/nuokygpe/1/ and corresponding code below.
#-webkit-keyframes moving-gradient {
0% { background-position: left bottom; }
100% { background-position: right bottom; }
}
.loading-gradient {
width: 200px;
height: 30px;
background: -webkit-linear-gradient(
left,
#e9e9e9 50%,
#eeefef 100%
) repeat;
-webkit-background-size: 50% 100%;
-webkit-animation-name: moving-gradient;
-webkit-animation-duration: 1s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
}
<div class="loading-gradient" style="width: 200px; height: 30px"> </div>

Instead of making the gradient 50% make it 200% and define 2 gradient coloration inside it. Doing so each part of the gradient will cover exactly 100% of the element width then you can animation it from left to right.
.loading-gradient {
width: 200px;
height: 30px;
background: linear-gradient(to left,
#e9e9e9 0% 25%, #eeefef 50%, /* first one take the half*/
#e9e9e9 50% 75%, #eeefef 100%); /* second one take the other half*/
background-size: 200% 100%;
animation: moving-gradient 1s linear infinite;
}
#keyframes moving-gradient {
0% {
background-position: right;
}
/*100% {
background-position: left; /* No need to define this since it's the default value*/
}*/
}
<div class="loading-gradient" style="width: 200px; height: 30px"> </div>
Since the gradient is now having a size bigger than the container, you need to do the opposite animation (from right to left).
More details: Using percentage values with background-position on a linear gradient
Here is another idea where you can consider pseudo element and translate animation:
.loading-gradient {
width: 200px;
height: 30px;
position:relative;
z-index:0;
overflow:hidden;
}
.loading-gradient:before {
content:"";
position:absolute;
z-index:-1;
top:0;
right:0;
width:200%;
bottom:0;
background: linear-gradient(to left, #e9e9e9 50%, #eeefef 100%);
background-size: 50% 100%;
animation: moving-gradient 1s linear infinite;
}
#keyframes moving-gradient {
100% {
transform: translate(50%);
}
}
<div class="loading-gradient" style="width: 200px; height: 30px"> </div>

Related

CSS keyframes animation glitching in first cycle but running smoothly in following cycles [duplicate]

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>

How to set transition for 2 backgrounds in an element?

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>

CSS: Animate Partial Linear Gradient Background [duplicate]

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>

CSS animation not smooth enough

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;
}
}

Background-size:100% is slightly less than 100%

Please consider the following HTML and CSS :
HTML
<ul class="test1">
<li><div>Lorem ipsum</div></li>
<li><div>dolor sit amet</div></li>
</ul>
<ul class="test2">
<li><div>Lorem ipsum</div>
</li><li><div>dolor sit amet</div></li>
</ul>
CSS
.test1 div {height:100px;}
.test2 div {height:200px;}
li
{
display: inline-block;
width:100px;
transition:background-position 0.2s ease;
background-image: linear-gradient(to bottom, rgba(255,255,255,0) 50%, #F60 50%);
background-size: 100% 200%;
background-position : top left;
}
li:hover{color: #fff;background-position: bottom left;}
cfr jsfiddle
With a background being 200% of the height, and the top 50% of that background being transparent, that would mean that without hovering, all we can see is a transparent background. However, with this configuration I still can see a slight orange (#F60) line at the bottom, that being the bottom color of my "gradient" background.
If I want to fix this, I must specify background-size in pixels, and in that case I need to put background size as being (element size + 1 px)*2 . Could someone explain what causes this ? This is quite a problem as I would like to use this effect on blocks of a non-fixed height so percentage height is mandatory...
So here is a more involved answer that uses CSS animations: DEMO
Basically, I created colored DIV elements that have a 0% height. On hover of the parent li they grow to 100% height. The tricky part was preventing the return (shrink) animation from playing on page load: solved this by applying a white background to the overlaying text and fading it out after the initial page load completes (hideinit animation).
Added some classes and another DIV to the HTML markup:
<ul class="test1">
<li><div class="text">Lorem ipsum</div><div class="orange"></div></li>
<li><div class="text">dolor sit amet</div><div class="orange"></div></li>
</ul>
The updated CSS:
* I left off the webkit vendor prefixed styles for brevity, they are included in the Fiddle
li {
float: left;
list-style: none;
width:100px;
height: 100%;
position: relative;
}
li:hover div.orange{
animation: grow 1s 1 forwards;
}
li div.orange {
position: absolute;
bottom: 0;
background: orange;
height: 0%;
width: 100%;
z-index: -1;
animation: shrink 1s 1 forwards;
}
li div.text {
padding: 5px;
width: 100%;
height: 100%;
animation: hideinit 1s 1 forwards;
}
#keyframes grow {
from {height: 0%;}
to {height: 100%;}
}
#keyframes shrink {
from {height: 100%;}
to {height: 0%;}
}
#keyframes hideinit {
0% {background: white;}
98% {background: white;}
100% {background: none;}
}
I know that other answers already suggested increasing the background-size height to 201%, and that you had issues with items larger than, lets say 300px, but I tried 202% and was able to increase the size of the div up to 900px with no orange line appearing.
So in summary:
li {
display: inline-block;
width:100px;
transition:background-position 0.2s ease;
background-image: linear-gradient(to bottom, rgba(255,255,255,0) 50%, #F60 50%);
background-size: 100% 202%;
background-position : top left;
}
Best of luck!
to remove the line at the bottom you are having add:
li{
background-attachment: fixed;
}
JSFiddle
In response to dreamgt's comment I added some extra time to the animation. From:
transition:background-position 0.2s ease;
To:
transition:background-position 0.5s ease;
New JSFiddle
increase the height by an additional 1%
li {
display: inline-block;
width:100px;
transition:background-position 0.2s ease;
background-image: linear-gradient(to bottom, rgba(255,255,255,0) 50%, #F60 50%);
background-size: 100% 201%; /* <----------- increased height to 201% */
background-position : top left;
}
DEMO