惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
S
Schneier on Security
T
The Exploit Database - CXSecurity.com
Webroot Blog
Webroot Blog
AI
AI
P
Palo Alto Networks Blog
Attack and Defense Labs
Attack and Defense Labs
WordPress大学
WordPress大学
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
Spread Privacy
Spread Privacy
T
Tor Project blog
罗磊的独立博客
小众软件
小众软件
S
Security Affairs
酷 壳 – CoolShell
酷 壳 – CoolShell
量子位
Apple Machine Learning Research
Apple Machine Learning Research
T
Threatpost
NISL@THU
NISL@THU
博客园_首页
PCI Perspectives
PCI Perspectives
大猫的无限游戏
大猫的无限游戏
IT之家
IT之家
N
News and Events Feed by Topic
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Forbes - Security
Forbes - Security
博客园 - 叶小钗
D
Darknet – Hacking Tools, Hacker News & Cyber Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
L
LINUX DO - 热门话题
T
Threat Research - Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
腾讯CDC
Security Latest
Security Latest
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Cloudflare Blog
A
About on SuperTechFans
爱范儿
爱范儿
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
TaoSecurity Blog
TaoSecurity Blog
宝玉的分享
宝玉的分享
G
GRAHAM CLULEY
雷峰网
雷峰网
F
Full Disclosure
I
Intezer
Cloudbric
Cloudbric
博客园 - 三生石上(FineUI控件)
U
Unit 42

CSS Articles by Temani Afif

Get Ready For the Powerful CSS border-shape Property! | CSS-Tricks Let’s Play With Gap Decorations! How to Control Infinite CSS Animations (Part 2 of 2) How to Control Infinite CSS Animations (Part 1 of 2) Two Circles, One Arrow, and Anchor Positioning Making a Responsive Pyramidal Grid With Modern CSS | CSS-Tricks How to Create a CSS-only Elastic Text Effect Making Complex CSS Shapes Using shape() | CSS-Tricks Responsive Hexagon Grid Using Modern CSS | CSS-Tricks Responsive List of Avatars Using Modern CSS (Part 2) | CSS-Tricks Responsive List of Avatars Using Modern CSS (Part 1) | CSS-Tricks Perfectly Pointed Tooltips: To The Corners Perfectly Pointed Tooltips: All Four Sides Perfectly Pointed Tooltips: A Foundation Sequential linear() Animation With N Elements | CSS-Tricks Infinite Marquee Animation using Modern CSS Better CSS Shapes Using shape() — Part 4: Close and Move | CSS-Tricks Drawing CSS Shapes using corner-shape Better CSS Shapes Using shape() — Part 3: Curves | CSS-Tricks Better CSS Shapes Using shape() — Part 2: More on Arcs | CSS-Tricks Better CSS Shapes Using shape() — Part 1: Lines and Arcs | CSS-Tricks Creating Blob Shapes using clip-path: shape() Creating Flower Shapes using clip-path: shape() Custom progress element using the attr() function A CSS-Only Star Rating Component and More! (Part 2) | CSS-Tricks A CSS-Only Star Rating Component and More! (Part 1) | CSS-Tricks How to Create Wavy Boxes Using CSS Full-Bleed Layout with Modern CSS Fancy Menu Navigation Using Anchor Positioning | CSS-Tricks How to Create a Zig-Zag Box Using CSS How to Create Zig-Zag CSS Loaders Using One Element Custom Progress Element Using Anchor Positioning & Scroll-Driven Animations How to Create Filling CSS Loaders Using One Element How to Create Curved-Edge and Rounded-Edge Shapes Using CSS CSS Tricks That Use Only One Gradient | CSS-Tricks How to create Shapes with Inner Curves using CSS Mask Custom Range Slider Using Anchor Positioning & Scroll-Driven Animations How to Get the Width/Height of Any Element in Only CSS How Keyboard Navigation Works in a CSS Game How To Create Cut-Out Shapes using The clip-path property The Modern Guide For Making CSS Shapes — Smashing Magazine css-shape.com: The Ultimate Collection of CSS-only Shapes ⚡️ Sliding 3D Image Frames In CSS — Smashing Magazine CSS Tricks To Master The clip-path Property Creating Wavy Circles with Fancy Animations in CSS Modern CSS Tooltips And Speech Bubbles (Part 2) — Smashing Magazine Do you need a Tooltip or a Speech Bubble? I have created 100 using CSS 😲 Modern CSS Tooltips And Speech Bubbles (Part 1) — Smashing Magazine Creating Flower Shapes using CSS Mask & Trigonometric Functions CSS Shapes: The Triangle The Complex But Awesome CSS border-image Property — Smashing Magazine CSS Tricks to add 3D Effects to your Text CSS Responsive Multi-Line Ribbon Shapes (Part 2) — Smashing Magazine CSS Responsive Multi-Line Ribbon Shapes (Part 1) — Smashing Magazine I have made 100+ CSS-only Ribbon Shapes | The Perfect Collection 🎀 How to create a CSS-only infinite scroll animation Re-Creating The Pop-Out Hover Effect With Modern CSS (Part 2) — Smashing Magazine Re-Creating The Pop-Out Hover Effect With Modern CSS (Part 1) — Smashing Magazine How to Create CSS Ribbon Shapes with a Single Element CSS Shapes: The Ribbon Revealing Images With CSS Mask Animations — Smashing Magazine css-loaders.com: The Biggest Collection of Loading Animations (more than 500 🤯) How To Define An Array Of Colors With CSS — Smashing Magazine CSS effects on images II Shines, Perspective, And Rotations: Fancy CSS 3D Effects For Images — Smashing Magazine What's your Lucky CSS Pattern? Check It Now! How to Add a CSS Reveal Animation to Your Images Modern Layouts using CSS Grid I created 100+ unique CSS patterns | The best collection 🤩 How to Create a Custom Range Slider Using CSS CSS Shapes: The Heart CSS Shapes: Polygon & Starburst A Text Reveal Animation using CSS CSS Tip: learn CSS the easy way! How to build a CSS-only accordion How to create Breadcrumb Navigation with CSS Different Ways to Get CSS Gradient Shadows | CSS-Tricks A CSS-only responsive Stepper component A Fancy Hover Effect For Your Avatar | CSS-Tricks How to make a zoom effect using CSS Creating a Custom Cursor using CSS CSS Infinite 3D Sliders | CSS-Tricks CSS Infinite Slider Flipping Through Polaroid Images | CSS-Tricks How to create a responsive sidebar menu using CSS CSS Infinite and Circular Rotating Image Slider | CSS-Tricks Making Static Noise From a Weird CSS Gradient Bug | CSS-Tricks CSS Grid and Custom Shapes, Part 3 | CSS-Tricks Fancy Image Decorations: Outlines and Complex Animations | CSS-Tricks Fancy Image Decorations: Masks and Advanced Hover Effects | CSS-Tricks Fancy Image Decorations: Single Element Magic | CSS-Tricks How to create an infinite image slider using CSS How to Create Wavy Shapes & Patterns in CSS | CSS-Tricks How I Made a Pure CSS Puzzle Game | CSS-Tricks How to create a Tooltip/Speech Bubble using CSS CSS Grid and Custom Shapes, Part 2 | CSS-Tricks CSS Grid and Custom Shapes, Part 1 | CSS-Tricks Zooming Images in a Grid Layout | CSS-Tricks How to create a CSS-only loader with one element Exploring CSS Grid’s Implicit Grid and Auto-Placement Powers | CSS-Tricks How to create background pattern using CSS & conic-gradient
Single Element Loaders: The Spinner | CSS-Tricks
Temani Afif · 2022-06-10 · via CSS Articles by Temani Afif

Making CSS-only loaders is one of my favorite tasks. It’s always satisfying to look at those infinite animations. And, of course, there are lots of techniques and approaches to make them — no need to look further than CodePen to see just how many. In this article, though, we will see how to make a single element loader writing as little code as possible.

I have made a collection of more than 500 single div loaders and in this four-part series, I am going to share the tricks I used to create many of them. We will cover a huge number of examples, showing how small adjustments can lead to fun variations, and how little code we need to write to make it all happen!

For this first article, we are going to create a one of the more common loader patterns: spinning bars:

Here’s the approach

A trivial implementation for this loader is to create one element for each bar wrapped inside a parent element (for nine total elements), then play with opacity and transform to get the spinning effect.

My implementation, though, requires only one element:

<div class="loader"></div>

…and 10 CSS declarations:

.loader {
  width: 150px; /* control the size */
  aspect-ratio: 1;
  display: grid;
  mask: conic-gradient(from 22deg, #0003, #000);
  animation: load 1s steps(8) infinite;
}
.loader,
.loader:before {
  --_g: linear-gradient(#17177c 0 0) 50%; /* update the color here */
  background: 
    var(--_g)/34% 8%  space no-repeat,
    var(--_g)/8%  34% no-repeat space;
}
.loader:before {
  content: "";
  transform: rotate(45deg);
}
@keyframes load {
  to { transform: rotate(1turn); }
}

Let’s break that down

At first glance, the code may look strange but you will see that it’s more simple than what you might think. The first step is to define the dimension of the element. In our case, it’s a 150px square. We can put aspect-ratio to use so the element stays square no matter what.

.loader {
  width: 150px; /* control the size */
  aspect-ratio: 1; /* make height equal to width */
}

When building CSS loaders, I always try to have one value for controlling the overall size. In this case, it’s the width and all the calculations we cover will refer to that value. This allows me to change a single value to control the loader. It’s always important to be able to easily adjust the size of our loaders without the need to adjust a lot of additional values.

Next, we will use gradients to create the bars. This is the trickiest part! Let’s use one gradient to create two bars like the below:

background: linear-gradient(#17177c 0 0) 50%/34% 8% space no-repeat;
Showing a space between two gradient lines for a single element loader.

Our gradient is defined with one color and two color stops. The result is a solid color with no fading or transitions. The size is equal to 34% wide and 8% tall. It’s also placed in the center (50%). The trick is the use of the keyword value space — this duplicates the gradient, giving us two total bars.

From the specification:

The image is repeated as often as will fit within the background positioning area without being clipped and then the images are spaced out to fill the area. The first and last images touch the edges of the area.

I am using a width equal to 34% which means we cannot have more than two bars (3*34% is greater than 100%) but with two bars we will have empty spaces (100% - 2 * 34% = 32%). That space is placed in the center between the two bars. In other words, we use a width for the gradient that is between 33% and 50% to make sure we have at least two bars with a little bit of space between them. The value space is what correctly places them for us.

We do the same and make a second similar gradient to get two more bars at the top and bottom, which give us a background property value of:

background: 
 linear-gradient(#17177c 0 0) 50%/34% 8%  space no-repeat,
 linear-gradient(#17177c 0 0) 50%/8%  34% no-repeat space;

We can optimize that using a CSS variable to avoid repetition:

--_g: linear-gradient(#17177c 0 0) 50%; /* update the color here */
background: 
 var(--_g)/34% 8%  space no-repeat,
 var(--_g)/8%  34% no-repeat space;

So, now we have four bars and, thanks to CSS variables, we can write the color value once which makes it easy to update later (like we did with the size of the loader).

To create the remaining bars, let’s tap into the .loader element and its ::before pseudo-element to get four more bars for a grand total of eight in all.

.loader {
  width: 150px; /* control the size */
  aspect-ratio: 1;
  display: grid;
}
.loader,
.loader::before {
  --_g: linear-gradient(#17177c 0 0) 50%; /* update the color here */
  background: 
    var(--_g)/34% 8%  space no-repeat,
    var(--_g)/8%  34% no-repeat space;
}
.loader::before {
  content: "";
  transform: rotate(45deg);
}

Note the use of display: grid. This allows us to rely on the grid’s default stretch alignment to make the pseudo-element cover the whole area of its parent; thus there’s no need to specify a dimension on it — another trick that reduces the code and avoid us to deal with a lot of values!

Now let’s rotate the pseudo-element by 45deg to position the remaining bars. Hover the following demo to see the trick:

Setting opacity

What we’re trying to do is create the impression that there is one bar that leaves a trail of fading bars behind it as it travels a circular path. What we need now is to play with the transparency of our bars to make that trail, which we are going to do with CSS mask combined with a conic-gradient as follows:

mask: conic-gradient(from 22deg,#0003,#000);

To better see the trick, let’s apply this to a full-colored box:

The transparency of the red color is gradually increasing clockwise. We apply this to our loader and we have the bars with different opacity:

Radial gradient plus, spinner bars equals spinner bars with gradients.

In reality, each bar appears to fade because it’s masked by a gradient and falls between two semi-transparent colors. It’s hardly noticeable when this runs, so it’s sort of like being able to say that all the bars have the same color with a different level of opacity.

The rotation

Let’s apply a rotation animation to get our loader. Note, that we need a stepped animation and not a continuous one that’s why I am using steps(8). 8 is nothing but the number of the bars, so that value can be changed depending on how many bars are in use.

.loader {
  animation: load 3s steps(8) infinite;
}

/* Same as before: */
@keyframes load {
  to { transform: rotate(1turn) }
}

That’s it! We have our loader with only one element and a few lines of CSS. We can easily control its size and color by adjusting one value.

Since we only used the ::before pseudo-element, we can add four more bars by using ::after to end with 12 bars in total and almost the same code:

We update the rotation of our pseudo-elements to consider 30deg and 60deg instead of 45deg while using an twelve-step animation, rather than eight. I also decreased the height to 5% instead of 8% to make the bars a little thinner.

Notice, too, that we have grid-area: 1/1 on the pseudo-elements. This allows us to place them in the same area as one another, stacked on top of each other.

Guess what? We can reach for the same loader using another implementation:

Can you figure out the logic behind the code? Here is a hint: the opacity is no longer handled with a CSS mask but inside the gradient and is also using the opacity property.

Why not dots instead?

We can totally do that:

If you check the code, you will see that we’re now working with a radial gradient instead of a linear one. Otherwise, the concept is exactly the same where the mask creates the impression of opacity, but we made the shapes as circles instead of lines.

Below is a figure to illustrate the new gradient configuration:

Showing placement of dots in the single-element loader.

If you’re using Safari, note that the demo may be buggy. That’s because Safari currently lacks support for the at syntax in radial gradients. But we can reconfigure the gradient a bit to overcome that:

.loader,
.loader:before,
.loader:after {
  background:
    radial-gradient(
      circle closest-side,
      currentColor 90%,
      #0000 98%
    ) 
    50% -150%/20% 80% repeat-y,
    radial-gradient(
      circle closest-side,
      currentColor 90%,
      #0000 98%
    ) 
    -150% 50%/80% 20% repeat-x;
}

More loader examples

Here is another idea for a spinner loader similar to the previous one.

For this one, I am only relying on background and mask to create the shape (no pseudo-elements needed). I am also defining the configuration with CSS variables to be able to create a lot of variations from the same code — another example of just the powers of CSS variables. I wrote another article about this technique if you want to more details.

Note that some browsers still rely on a -webkit- prefix for mask-composite with its own set of values, and will not display the spinner in the demo. Here is a way to do it without mast-composite for more browser support.

I have another one for you:

For this one, I am using a background-color to control the color, and use mask and mask-composite to create the final shape:

Different steps for applying a master to a element in the shape of a circle.

Before we end, here are some more spinning loaders I made a while back. I am relying on different techniques but still using gradients, masks, pseudo-element, etc. It could be a good exercise to figure out the logic of each one and learn new tricks at the same time. This said, if you have any question about them, the comment section is down below.

Wrapping up

See, there’s so much we can do in CSS with nothing but a single div, a couple of gradients, pseudo-elements, variables. It seems like we created a whole bunch of different spinning loaders, but they’re all basically the same thing with slight modifications.

This is only the beginning. In this series, we will be looking at more ideas and advanced concepts for creating CSS loaders.