Sitemap
Mateusz Kirmuć

Mateusz Kirmuć

Create a simple loader using only CSS & HTML

4 min readJun 26, 2024

--

Hello. In this article, I would like to show you how to create a simple spinning loader using only HTML and CSS (SCSS). Let’s get started!

Press enter or click to view image in full size

Creating a track for the spinner.

Let’s start by defining the components of our loader. It consists of a spinner (a moving element that cycles periodically) and a circle track on which it moves. The track is nothing more than a block-level element with equal width and height (a square). It has a border of a specified width, rounded using theborder-radius: 100%property. This way, the border forms the circle visible below.

<div class="track"></div>
.track {
width: 200px;
height: 200px;
border: 10px solid #ADD8E6;
border-radius: 100%;
}

Adding the spinner.

In our example, the spinner will be a curved segment with a thickness equal to the thickness of the track and a length equal to ¼ of its circumference. Its curvature must match the curvature of the track on which it moves.

Get Mateusz Kirmuć’s stories in your inbox

Join Medium for free to get updates from this writer.

To create such a segment, we can create a square block-level element with dimensions equal to ½ of the track’s width/height. Then, we need to define the border of two adjacent sides and round the corner between them using the border-radius property.

<div class="spinner"></div>
.spinner {
width: 100px;
height: 100px;
border-top: 10px solid #A9B5EC;
border-right: 10px solid #A9B5EC;
border-top-right-radius: 100%;
}

Finally, we have to place the spinner on the track. We can do this using the position: absolute property. Optionally, it’s worth defining the spinner element as a pseudo-element to limit the number of elements in the DOM. In that case, we can also change the class name of the track element to .loader.

.loader {
width: 200px;
height: 200px;
position: relative;
border: 10px solid #ADD8E6;
border-radius: 100%;

&::after {
content: '';
width: 100px;
height: 100px;
border-top: 10px solid #A9B5EC;
border-right: 10px solid #A9B5EC;
border-top-right-radius: 100%;
position: absolute;
right: -10px;
top: -10px;
}
}

Pay attention to the values of the topand rightproperties. According to the definition of these properties, we need to consider the thickness of the track’s border using the absolute positioning of the spinner.

Adding the animation.

Since we have already prepared the track and placed the spinner on it, we can proceed with implementing the animation. This is a simple process that involves changing the rotation of the track element using CSS animation. This way, we create the impression that the spinner itself is moving.

@keyframes spinning {
from {rotate: 0}
to {rotate: 360deg}
}

.loader {
width: 200px;
height: 200px;
position: relative;
border: 10px solid #ADD8E6;
border-radius: 100%;
// apply animation:
animation-name: spinning;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-timing-function: linear;

&::after {
content: '';
width: 100px;
height: 100px;
border-top: 10px solid #A9B5EC;
border-right: 10px solid #A9B5EC;
border-top-right-radius: 100%;
position: absolute;
right: -10px;
top: -10px;
}
}

Notice how we animate track rotation from 0 deg to 360 deg angle. The loader must spin, so this animation must be repeated infinitely using iteration-count: infinite.

Customizing the loader and organizing the code.

The finished loader can be customized to suit our needs. We can change various factors such as the initial position of the spinner, the animation timing function, the direction and speed of rotation, or the thickness and color of the track/spinner.

Using SCSS variables will make any modifications much easier and help organize the code. Below is the final result of a loader with a changed initial position and animation timing function.

$radius: 100px;
$trackWidth: 10px;
$trackColor: #ADD8E6;
$spinnerColor: #A9B5EC;
$startAngle: -45deg;

@keyframes spinning {
from {rotate: $startAngle}
to {rotate: $startAngle + 360deg}
}

.loader {
width: 2*$radius;
height: 2*$radius;
position: relative;
border: $trackWidth solid $trackColor;
border-radius: 100%;
animation-name: spinning;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-timing-function: ease;

&::after {
content: '';
width: $radius;
height: $radius;
border-top: $trackWidth solid $spinnerColor;
border-right: $trackWidth solid $spinnerColor;
border-top-right-radius: 100%;
position: absolute;
right: -$trackWidth;
top: -$trackWidth;
}
}

Thank you for reading this short article. If you want to read more content like this you can follow my medium or twitter account. Also, feel free to give me any form of feedback. I’d love to hear any comments from you. See you soon in my next article!

--

--