← Back toCSS animation

Skeleton loading

Written byPhuoc Nguyen
25 Aug, 2023
Have you ever visited a website and seen a blank page or a section that seems to be loading, only to be replaced with content a moment later? If so, you may have witnessed a skeleton loading animation. This technique is used to improve the user experience by indicating that content is loading and to prevent users from perceiving a delay or lag.
In this post, we'll explore a few ways to create this skeleton loading effect.

Using SVG animations

The SVG element below uses a linear gradient to animate a circle that's within its clip path.
While it works, there are some drawbacks. For one, it's not reusable. If you want to create different shapes for the skeleton, you'll need to duplicate the entire SVG element every time.
Using frameworks can improve reusability. For example, we can create a React component to wrap the SVG. This component includes configurable props such as the dimensions (`height` and `width`) and the animated background (`backgroundColor`) and foreground (`foregroundColor`) colors.
In the code example given, the `Skeleton` component can only accept SVG elements as its `children`. Unfortunately, it's not possible to display regular HTML elements. Additionally, you have to manually calculate the boundary and position the children SVG element very carefully to ensure they're displayed where you want them. Frankly, it's a bit of a hassle.
<circle cx={20} cy={20} r={20} />
<rect x={50} y={0} rx={3} ry={3} width={300} height={8} />
<rect x={50} y={15} rx={3} ry={3} width={200} height={8} />
<rect x={50} y={30} rx={3} ry={3} width={100} height={8} />
It's not practical to build a complex skeleton with many sub-elements. For example, think about creating a preview for a table. Instead, we can use a CSS-based solution to solve these issues. Let's move on to the next section to learn more.

Animating the opacity

In this approach, we're using the animation property to create a pulsating effect. The animation is called `pulse` and lasts for 2 seconds, with a smooth ease-in-out timing function. It repeats infinitely, so the effect continues as long as needed.
The `pulse` animation uses keyframes to change the element's opacity over time, giving it that cool pulsing look.
Let's go back to the demonstration we saw earlier. You can create different shapes for free, and then you have full control over how they look and where they go. It's all up to you!

Sliding the placeholder

Now for the final approach. Firstly, we'll use a pseudo-element to create a fake placeholder element that sits inside the original skeleton element and is positioned absolutely. This placeholder element will also take up the full size of the skeleton.
.skeleton {
position: relative;

.skeleton::before {
/* Make it empty */
content: '';

/* Position absolutely */
position: absolute;
left: 0;
top: 0;

/* Take the full dimension */
height: 100%;
width: 100%;
At first, the placeholder sits to the left outside its container. Then, every 2 seconds, it moves to the right while filling up with a light background color. This creates the loading effect that we all know and love.
And hey, if you want to get fancy with the colors, you can use the `linear-gradient` function to produce a gradient effect.
:root {
--skeleton-duration: 2s;

.skeleton::before {
background: linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.05), transparent);
transform: translateX(-100%);
animation: slide var(--skeleton-duration) ease-in-out infinite;

@keyframes slide {
0% {
transform: translateX(-100%);
100% {
transform: translateX(100%);
In the final demonstration, you can choose to show the sliding effect by selecting the corresponding option. This will allow you to see how the placeholder slides from left to right within the skeleton. Additionally, you can adjust the duration of the animation to make it run faster or slower.
If you found this post helpful, please consider giving the repository a star on GitHub or sharing the post on your favorite social networks 😍. Your support would mean a lot to me!

Questions? 🙋

Do you have any questions about front-end development? If so, feel free to create a new issue on GitHub using the button below. I'm happy to help with any topic you'd like to learn more about, even beyond what's covered in this post.
While I have a long list of upcoming topics, I'm always eager to prioritize your questions and ideas for future content. Let's learn and grow together! Sharing knowledge is the best way to elevate ourselves 🥷.
Ask me questions

Recent posts ⚡

Newsletter 🔔

If you're into front-end technologies and you want to see more of the content I'm creating, then you might want to consider subscribing to my newsletter.
By subscribing, you'll be the first to know about new articles, products, and exclusive promotions.
Don't worry, I won't spam you. And if you ever change your mind, you can unsubscribe at any time.
Phước Nguyễn