Learn More

Try out the world’s first micro-repo!

Learn More

Using CSS to Create a Skeleton Screen

Using CSS to Create a Skeleton Screen

The web has recently undergone improvements that benefit both consumers and developers. Because new methods of enhancing user experiences continue to emerge over time, user experience is a major focus that goes beyond present metrics.

Skeleton displays are one component of UX improvement. In this article, we’ll be covering the purpose of skeleton loaders, their significance, and how to create one for a website using React and basic CSS.

What is a Skeleton Screen?

An animated placeholder known as a "skeleton screen" simulates a website's design while data is being loaded. Skeleton screens inform the user that some content is loading while also, and perhaps more crucially, indicating whether an image, text, card or other type of data is loading.

Because the user is aware of the type of content loading before it manifests, the page appears to load more quickly. Perceived performance is what we're talking about here.

Here are some illustrations of skeleton displays from Medium and Facebook:

A Medium skeleton screen.
Medium home feed loading state
A Facebook skeleton screen.
Facebook home feed loading state

The gray shapes indicate how the data will be shown once it has loaded. These images are replaced once the data from the server actually arrives.

Skeleton loaders seldom improve efficiency or loading speed. They exist solely to provide the visitor with something to look at and the impression that the website is loading more quickly.

Notable Qualities of Skeleton Loaders

  • They seem to move more quickly and are easier to utilize. A better user experience and higher conversion rates are both provided by improved perceived performance.
  • They give the impression of quickness and quick loading.
  • Users have no indication of what is loading or how long it will take with spinners and loaders, which can be a problem.
  • Since the load time is unknown, using spinners or loaders puts the user in a state of uncertainty.
  • Users might be tempted to move on rather than wait through skeleton screens.

Build a Skeleton Loader with React

For the purpose of this article's tutorial, we'll build a page that lists blog articles as cards. The final product will resemble the following:

The skeleton screen:

A skeleton screen for the Pieces blog.

The actual site after loading:

The Pieces blog once it's fully loaded.

Setting up a React Project

We'll begin by putting up a React project with the code below in order to use Google Charts in our React application:

npx create-react-app react-skeleton

Next, let’s change the working directory to the folder established by the previous command with the following code:

cd react-react-skeleton

Next, we’ll open the folder in our preferred text editor. Now that our app is configured, it's time to add and remove unnecessary boilerplate from it. In the /src folder, let’s make a components folder, and in the root directory, we’ll make a server folder.

We have a server folder because we're going to create a structure that resembles a database so we can store information about the blogs. We won't be entering any backend, so don't be concerned. With JSON Server, we’ll create a phony REST API.

Next, let’s create a file named db.json or data.json in the /server folder and fill it with some random information typically found on a blog, such as an avatar, author name, thumbnail, title, and description.

The contents of our db.json file should resemble something like the image below.

N.B.: An altered version of data is used in this tutorial due to its enormous size, but you can tweak it to your own style as much as you want.

//db.json

{
"blogs" : [
{
"title" : "Using regression testing to produce working software",
"thumbnail" : "https://blog.pieces.com/hero_Z1Aauk4.webp",
"avatar" : "https://blog.pieces.com/authors/avatars/goodness-woke.jpg",
"author" : "Goodness Woke",
"description" : "Lorem ipsum dolor sit amet, consectetur adipisci"
},
{
"title" : "Using regression testing to produce working software",
"thumbnail" : "https://blog.pieces.com/hero_Z1Aauk4.webp",
"avatar" : "https://blog.pieces.com/authors/avatars/goodness-woke.jpg",
"author" : "Goodness Woke",
"description" : "Lorem ipsum dolor sit amet, consectetur adipisci"
},
{
"title" : "Using regression testing to produce working software",
"thumbnail" : "https://blog.pieces.com/hero_Z1Aauk4.webp",
"avatar" : "https://blog.pieces.com/authors/avatars/goodness-woke.jpg",
"author" : "Goodness Woke",
"description" : "Lorem ipsum dolor sit amet, consectetur adipisci"
},
{
"title" : "Using regression testing to produce working software",
"thumbnail" : "https://blog.pieces.com/hero_Z1Aauk4.webp",
"avatar" : "https://blog.pieces.com/authors/avatars/goodness-woke.jpg",
"author" : "Goodness Woke",
"description" : "Lorem ipsum dolor sit amet, consectetur adipisci"
},
{
"title" : "Using regression testing to produce working software",
"thumbnail" : "https://blog.pieces.com/hero_Z1Aauk4.webp",
"avatar" : "https://blog.pieces.com/authors/avatars/goodness-woke.jpg",
"author" : "Goodness Woke",
"description" : "Lorem ipsum dolor sit amet, consectetur adipisci"
},
{
"title" : "Using regression testing to produce working software",
"thumbnail" : "https://blog.pieces.com/hero_Z1Aauk4.webp",
"avatar" : "https://blog.pieces.com/authors/avatars/goodness-woke.jpg",
"author" : "Goodness Woke",
"description" : "Lorem ipsum dolor sit amet, consectetur adipisci"
}
]
}

We need to run the above file using the JSON Server package so that we can add endpoints to it and conduct operations like POST, GET, DELETE, etc.

To do that, let’s open a new terminal and run json-server -watch server/db.json --port 8000. If it runs successfully, then the terminal should start the server on port 8000, and we should start watching for any changes. By copying and pasting http://localhost:8000 in a browser, we’ll see that the JSON file has been hosted on localhost. We can also see the blog resources on http://localhost:8000/blogs.

Creating a Fetch Function in App.js

Let's first retrieve the data from our local server. The data will be shown using a template that we’ll generate after successfully retrieving the data and handling any fetch failures.

In our app.js:

import { useState, useEffect } from 'react';
import Blogs from './components/blogs';
import Skeleton from './components/skeleton';
const App = () => {
const [blogs, setBlogs] = useState(null);
const [error, setError] = useState(false);
const [loading, setLoading] = useState(true);
useEffect(() => {
setTimeout(() => {
fetch(' http://localhost:8000/blogs')
.then(response => {
if(!response.ok){
throw Error('Sorry, some error occurred while fetching your blogs.');
}
return response.json();
})
.then(data => {
setBlogs(data);
setLoading(false);
setError(false);
})
.catch(err => {
console.log(err.message);
setError(true);
})
}, 4000)
})
return(
<div>
<img className='imagess' src='https://assets.website-files.com/6143afec68f55570f449ef97/6227bdf760fad5f7510a3411_black_logo.svg'></img>
<h1>The Pieces Blog</h1>
{blogs && <Blogs blogs = {blogs} /> }
<div className="container">
{loading && [1,2,3,4,5,6,7].map((n) => <Skeleton key={n}/>)}
</div>
{error && <div className='container'><span className='error'>Error connecting to the server. Connection failed.</span></div>}
</div>
)
}
export default App;

Creating a Blog and Skeleton Components

To continue, we’ll create our blogs.jsx and skeleton.jsx components. In the blogs.jsx, we pass in blogs as a prop, and then go further to create a template for the different properties of our blog, like blog.title, blog.description, etc. While in the skeleton components, we created a function to return a div that places our blog, avatar, title, author, etc., in the right location, and in the correct order:

//blogs.js
const Blogs = ({blogs}) => {
return(
<div className="container">
{blogs.map(blog => (
<div className="blog">
<header>
<div className="avatar">
<img src={blog.avatar} alt="black and white photo of smiling man infront of laptop" />
</div>
<div className="author">
<p className="name">{blog.author}</p>
</div>
</header>
<main className="image">
<img src={blog.thumbnail} alt="black screen with code over it" />
</main>
<footer>
<p className="title">{blog.title}</p>
<p className="text">{blog.description}</p>
</footer>
</div>
))}
</div>
);
}
export default Blogs;

//skeleton.js

const Skeleton = () => {
return(
<div className="skeleton-blog">
<header>
<div className="skeleton-avatar">
</div>
<div className="skeleton-author">
</div>
</header>
<main className="skeleton-image">
</main>
<footer className="skeleton-footer">
</footer>
</div>
);
};
export default Skeleton;

Styling Our Skeleton Card

We removed the styling from index.css so that we could substitute with our very own CSS style. You can check out the complete files and folders here.

This is just a grid layout with a typeface. When the Blog component is imported inside the App component, our blog site should now appear as follows:

The skeleton screen disappearing as the blog loads.

Use Cases of Skeleton Loader

  • Use to alert viewers that something is loading when several elements are loading simultaneously.
  • Use when data loading takes longer than three seconds.
  • Use on heavily visited websites.
  • Use for a lengthy or background process.

Conclusion

We now understand what skeleton loading is, how it improves user experience by giving the appearance of speedy data loading, and how to put it into practice. The tutorial's source code is available here. Feel free to modify it, style it to be whatever you like, and add code enhancements.

Resources

Github Repo

Table of Contents

CSS

React

More from Pieces
Subscribe to our newsletter
Join our growing developer community by signing up for our monthly newsletter, The Pieces Post.

We help keep you in flow with product updates, new blog content, power tips and more!
Thank you for joining our community! Stay tuned for the next edition.
Oops! Something went wrong while submitting the form.