Recreating Google Gemini Loading Animation in CSS & Tailwind
I want to give a sincere appreciation to the person who designed the Gemini loading animation. It is such a clean animation that I had to attempt to implement myself. It won’t be a exact match but close enough for my purpose. Here is the animation taken from Google Gemini implemented in CSS and Tailwind for my people :
(Refresh for the initial animation)
First in regular CSS
The animation is composed of two keyframes: expanding
and moving
.
-
expanding
keyframe is responsible for the initial sliding animation. We set the scaleX to 0 (meaning it is not visible on the X-axis) and opacity to 0 (to create a fade in effect ). I chose to scale it because if you do it by width, every loading bar would essentially have the same width. By scaling it, it would return back to its original width set. -
moving
keyframe is responsible for the loading gradient effect. It basically moves the background gradient from left to right on a infinite loop. Thebackground-size
is set at200%
because if you only do 100%, you can see a skipping/jumping effect in the gradient. The animation begins with thebackground-position
at0%
and moves to-200%
because we want the loading animation to look like its moving to the right (by moving to the left). It’s a little counterintuitive to think about it but basically we are setting the current position of the background to the start of the loading bar. At 0%, it’s the very left of the gradient. At 50%, the middle of the gradient is now at the start of the loading bar (which is on the left). By doing the negative, it would now appear on the right!
The .loading-bar
then applies the two keyframes above, with expanding
running only once and moving
running infinitely with a 1s
delay at the start
/* This keyframe will create the initial slide animation */
@keyframes expanding {
0% {
transform: scaleX(0);
opacity: 0;
}
100% {
transform: scaleX(1);
opacity: 1;
}
}
/* This keyframe will create the loading gradient effect */
@keyframes moving {
0% {
background-position: 0 0;
}
100% {
background-position: -200% 0;
}
}
.loading-bar {
height: 1.25rem;
transform-origin: left; /* Without this, you'll notice the `expanding` animation starts expanding from the middle instead of shooting out from the left */
animation: expanding 0.4s 0.7s forwards linear, moving 1s 1s infinite forwards linear;
border-radius: 0.125rem;
background-image: linear-gradient(to right, #eff6ff 30%, #2563eb60 60%, #eff6ff);
background-size: 200% auto;
opacity: 0; /* The `expanding` animation will fade in the loading bar */
animation-delay: 100ms;
}
<div class="loading-bar"></div>
Now TailwindCSS!
In your tailwind config, add this:
const config = {
// .... other configs
theme: {
extend: {
// .... other configs
keyframes: {
expanding: {
"0%": { transform: "scaleX(0)", opacity: "0" },
"100%": { transform: "scaleX(1)", opacity: "100%" },
},
moving: {
"0%": { backgroundPosition: "0 0" },
"100%": { backgroundPosition: "-200% 0" },
},
},
animation: {
loading: "expanding 0.4s 0.7s forwards linear, moving 1s 1s infinite forwards linear",
},
},
},
};
<!-- Only one loading bar demo -->
<div
className="h-5 w-3/5 origin-left animate-loading rounded-sm bg-gradient-to-r from-blue-50 from-40% via-blue-500/60 to-blue-50 to-70% bg-[length:200%] opacity-0"
></div>
The example above I created looks likes this if you want to copy in tailwindcss
<div class="flex h-32 gap-4 p-5 fade-in-25 md:gap-6">
<div class="size-9 shrink-0 rounded-full bg-gray-100"></div>
<div class="flex w-full max-w-3xl flex-col gap-4 rounded-lg pt-2">
<div
class="h-5 w-10/12 origin-left animate-loading bg-[length:200%] rounded-sm bg-gradient-to-r from-blue-50 from-30% via-blue-600/60 to-blue-50 bg-2x opacity-0"
></div>
<div
class="h-5 w-full origin-left animate-loading bg-[length:200%] rounded-sm bg-gradient-to-r from-blue-500/60 via-slate-100 via-30% to-blue-500/60 to-60% bg-2x opacity-0 "
></div>
<div
class="duration-600 h-5 w-3/5 origin-left animate-loading bg-[length:200%] rounded-sm bg-gradient-to-r from-blue-50 from-40% via-blue-500/60 to-blue-50 to-70% bg-2x opacity-0 "
></div>
</div>
</div>