<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ loaders - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ loaders - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 26 Jun 2026 22:47:37 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/loaders/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Create Filling CSS Loaders Using One Element ]]>
                </title>
                <description>
                    <![CDATA[ In a previous article, I showed you how to create two types of CSS loaders: a spinner and a progress bar. In this article, you’ll learn about another variation called a filling CSS loader. I think a demo is worth thousands of words, so check out this... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/filling-css-loaders/</link>
                <guid isPermaLink="false">6719336f56c24fb7d4fc62b3</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ loaders ]]>
                    </category>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Temani Afif ]]>
                </dc:creator>
                <pubDate>Wed, 23 Oct 2024 17:33:35 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729637821745/50ff0461-350c-441c-9726-b838d3ef0a5c.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In <a target="_blank" href="https://www.freecodecamp.org/news/how-to-create-a-css-only-loader">a previous article</a>, I showed you how to create two types of CSS loaders: a spinner and a progress bar. In this article, you’ll learn about another variation called a filling CSS loader.</p>
<p>I think a demo is worth thousands of words, so check out this Codepen:</p>
<div class="embed-wrapper"><iframe height="450" style="width:100%;height:450px" src="https://codepen.io/t_afif/embed/preview/ExqvRXO/77e4af243170fc28a0c8193a55b7ffe5?default-tab=result" title="Embedded content" loading="lazy">
  See the Pen <a href="https://codepen.io/t_afif/pen/ExqvRXO/77e4af243170fc28a0c8193a55b7ffe5">
  Untitled</a> by Temani Afif (<a href="https://codepen.io/t_afif">@t_afif</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe></div>

<p>In the above Pen, I’m showing you four different CSS filler-style loaders – but we can make even more. You can check out <a target="_blank" href="https://css-loaders.com/filling/">this collection</a> I created to see more than 20 different loaders.</p>
<p>You might think the article is going to be super long – I mean, how long will it take to explain how to create 20 different CSS loaders?</p>
<p>Well don’t worry – this tutorial will be super quick, because I’ll show a few CSS tricks that help you create as many variation as you want. The loaders look different, but all of them rely on the same techniques. By simply adjusting a few setting you can get a whole new loader.</p>
<h2 id="heading-the-initial-loader-configuration">The Initial Loader Configuration</h2>
<p>Like all <a target="_blank" href="https://css-loaders.com/">the CSS Loaders</a> I create, the HTML code is a simple as a single element. Nothing more! Here’s what it looks like:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"loader"</span>&gt;</span>Loading<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Then we apply the following CSS:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.loader</span> {
  <span class="hljs-attribute">font-weight</span>: bold;
  <span class="hljs-attribute">text-transform</span>: uppercase;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#0000</span>; <span class="hljs-comment">/* or transparent */</span>
  <span class="hljs-attribute">-webkit-text-stroke</span>: <span class="hljs-number">1px</span> <span class="hljs-number">#000</span>;
}
</code></pre>
<p>Nothing fancy so far. We make the text transparent and we add a black stroke to it. Here’s what that looks like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729506785632/fe01d18e-6d7d-4d49-a5d0-ef6766c51241.png" alt="The &quot;loading&quot; text with a black stroke and transparent color" class="image--center mx-auto" width="476" height="190" loading="lazy"></p>
<p>The <code>-webkit-text-stroke</code> is still tagged as experimental, but it has <a target="_blank" href="https://caniuse.com/mdn-css_properties_-webkit-text-stroke">good browser support</a> so you should be able to use it without any issues. This said, it’s always good to test your code in different browsers to make sure everything works fine.</p>
<h2 id="heading-how-to-fill-the-text-with-colors">How to Fill the Text with Colors</h2>
<p>Now it’s time to fill our text (that’s why this technique is called the Filling CSS loaders!). To do this, we are going to rely on gradients and <code>background-clip: text</code>. Here’s the code:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.loader</span> {
  <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">conic-gradient</span>(#<span class="hljs-number">000</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span>);
  <span class="hljs-attribute">background-position</span>: left;
  <span class="hljs-attribute">background-size</span>: <span class="hljs-number">40%</span> <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">background-repeat</span>: no-repeat;
  <span class="hljs-attribute">background-clip</span>: text;
}
</code></pre>
<p>Or the shorthand version if you prefer more compact code:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.loader</span> {
  <span class="hljs-attribute">background</span>: 
    <span class="hljs-built_in">conic-gradient</span>(#<span class="hljs-number">000</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span>) text
    left/<span class="hljs-number">40%</span> <span class="hljs-number">100%</span> no-repeat;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729507914013/b8991ffe-0b81-4ae0-a356-c102023c2f6c.png" alt="the difference between with and without background-clip: text" class="image--center mx-auto" width="873" height="190" loading="lazy"></p>
<p>The above figure illustrates the difference between using or not using <code>background-clip: text</code>. It’s pretty clear that the left result is what we are aiming for. We are limiting the background coloration to only the text instead of the whole element.</p>
<p>The <code>conic-gradient(#000 0 0)</code> looks strange, right? It lets you have a one-color gradient. I wrote a small tip about it that I invite you to read to understand why we’re using that particular syntax in this article, “<a target="_blank" href="https://css-tip.com/one-color-gradient/">How to correctly define a one-color gradient</a>“.</p>
<h2 id="heading-how-to-create-the-filling-loaders">How to Create the Filling Loaders</h2>
<p>Believe it or not, we’re almost done because we have everything we need to make the CSS loaders. For the first loader, we simply animate the <code>background-size</code> as follows:</p>
<pre><code class="lang-css"><span class="hljs-selector-id">#l1</span> {
  <span class="hljs-attribute">animation</span>: l1 <span class="hljs-number">1s</span> linear infinite;
}
<span class="hljs-keyword">@keyframes</span> l1 {  <span class="hljs-comment">/*  width  height */</span>
  0% {<span class="hljs-attribute">background-size</span>: <span class="hljs-number">0%</span>   <span class="hljs-number">100%</span>}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">background-size</span>: <span class="hljs-number">120%</span> <span class="hljs-number">100%</span>}
}
</code></pre>
<p>We start with a width equal to <code>0%</code> until we reach a width equal to <code>120%</code>. I could have used <code>100%</code>, but I want the full coloration to stay longer so I am using a value bigger than <code>100%</code>. As for the height (the second value of the <code>background-size</code>), it remains at <code>100%</code>.</p>
<p>The second loader uses the same animation, but instead of a linear timing function, we use <code>steps()</code> to have a discrete animation.</p>
<pre><code class="lang-css"><span class="hljs-selector-id">#l2</span> {
  <span class="hljs-attribute">font-family</span>: monospace;
  <span class="hljs-attribute">animation</span>: l2 <span class="hljs-number">2s</span> <span class="hljs-built_in">steps</span>(<span class="hljs-number">8</span>, jump-none) infinite;
}
<span class="hljs-keyword">@keyframes</span> l2 {
  0% {<span class="hljs-attribute">background-size</span>: <span class="hljs-number">0%</span>           <span class="hljs-number">100%</span>}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">background-size</span>: <span class="hljs-number">100%</span> <span class="hljs-number">100%</span>}
}
</code></pre>
<p>The text contains 7 characters so we use 8 steps (<code>N + 1</code>). I am also using a monospace font to make sure all the characters have the same width. In case you are wondering about the <code>jump-none</code> value, read the following: <a target="_blank" href="https://css-tip.com/steps/">How to correctly use steps() with animations</a>.</p>
<p><a target="_blank" href="https://css-tip.com/steps/">That’s basically the main trick. By animat</a>ing the background properties, we create different kinds of loaders. It’s either the <code>background-size</code> like the previous ones or the <code>background-position</code> like the below:</p>
<div class="embed-wrapper"><iframe height="400" style="width:100%;height:400px" src="https://codepen.io/t_afif/embed/preview/bGXogOx/59e12d693e164ac69804a554bbac8588?default-tab=result" title="Embedded content" loading="lazy">
  See the Pen <a href="https://codepen.io/t_afif/pen/bGXogOx/59e12d693e164ac69804a554bbac8588">
  Untitled</a> by Temani Afif (<a href="https://codepen.io/t_afif">@t_afif</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe></div>

<p>Can you figure out how they work before checking my code? This will be your first homework!</p>
<h2 id="heading-how-to-use-multiple-gradients">How to Use Multiple Gradients</h2>
<p>Using one gradient is enough to create a lot of variations – but we can do even more if we introduce multiple gradients. If you check the fourth loader of the first demo, you’ll see that I’m using seven gradients – one gradient per character.</p>
<pre><code class="lang-css"><span class="hljs-selector-id">#l4</span> {
  <span class="hljs-attribute">font-family</span>: monospace;
  <span class="hljs-attribute">--g</span>: <span class="hljs-built_in">conic-gradient</span>(#<span class="hljs-number">000</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span>) no-repeat text;
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">var</span>(--g) <span class="hljs-number">0</span>,<span class="hljs-built_in">var</span>(--g) <span class="hljs-number">1ch</span>,<span class="hljs-built_in">var</span>(--g) <span class="hljs-number">2ch</span>,<span class="hljs-built_in">var</span>(--g) <span class="hljs-number">3ch</span>,<span class="hljs-built_in">var</span>(--g) <span class="hljs-number">4ch</span>,<span class="hljs-built_in">var</span>(--g) <span class="hljs-number">5ch</span>,<span class="hljs-built_in">var</span>(--g) <span class="hljs-number">6ch</span>;
  <span class="hljs-attribute">background-position-y</span>: bottom;
  <span class="hljs-attribute">animation</span>: l4 <span class="hljs-number">3s</span> infinite;
}
<span class="hljs-keyword">@keyframes</span> l4 {
  0%     {<span class="hljs-attribute">background-size</span>: <span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   }
  14<span class="hljs-selector-class">.28</span>% {<span class="hljs-attribute">background-size</span>: <span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   }
  28<span class="hljs-selector-class">.57</span>% {<span class="hljs-attribute">background-size</span>: <span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   }
  42<span class="hljs-selector-class">.85</span>% {<span class="hljs-attribute">background-size</span>: <span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   }
  57<span class="hljs-selector-class">.14</span>% {<span class="hljs-attribute">background-size</span>: <span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   }
  71<span class="hljs-selector-class">.43</span>% {<span class="hljs-attribute">background-size</span>: <span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   ,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   }
  85<span class="hljs-selector-class">.71</span>% {<span class="hljs-attribute">background-size</span>: <span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">0</span>   }
  100%   {<span class="hljs-attribute">background-size</span>: <span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>,<span class="hljs-number">1ch</span> <span class="hljs-number">100%</span>}
}
</code></pre>
<p>I’m using the same gradient, so we consider a CSS variable <code>--g</code> to avoid repetition. Then, I call that variable 7 times inside the background property. All the gradients have the same Y position (<code>bottom</code>) but a different X position. That’s why you see the <code>0, 1ch, 2ch, …,6ch</code>.</p>
<p>Now if you check the animation, I’m simply animating the height of each gradient individually. At <code>0%</code>, all of them have a height equal to <code>0</code>. Then I update their height one by one until all of them are at <code>100%</code>. The width doesn’t change – it’s always equal to <code>1ch</code> (the width of one character).</p>
<p>It may look difficult at first glance, but if you think about it one gradient at a time, it’s pretty simple.</p>
<p>What about the third loader, you might ask? For that one, I will rely on <a target="_blank" href="https://css-generators.com/wavy-shapes/">my online generator for wavy shapes</a> to generate the gradient configuration:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729635835522/2f8726a3-e6bb-4949-8846-8408dad56a64.png" alt="Screenshot of the wavy shape generator" class="image--center mx-auto" width="1292" height="517" loading="lazy"></p>
<p>Then I animate the <code>background-position</code> like below:</p>
<pre><code class="lang-css"><span class="hljs-selector-id">#l3</span> {
  <span class="hljs-attribute">background</span>:
    <span class="hljs-built_in">radial-gradient</span>(<span class="hljs-number">1.13em</span> at <span class="hljs-number">50%</span> <span class="hljs-number">1.6em</span>,#<span class="hljs-number">000</span> <span class="hljs-number">99%</span>,#<span class="hljs-number">0000</span> <span class="hljs-number">101%</span>) <span class="hljs-built_in">calc</span>(<span class="hljs-number">50%</span> - <span class="hljs-number">1.6em</span>) <span class="hljs-number">0</span>/<span class="hljs-number">3.2em</span> <span class="hljs-number">100%</span>,
    <span class="hljs-built_in">radial-gradient</span>(<span class="hljs-number">1.13em</span> at <span class="hljs-number">50%</span> -<span class="hljs-number">0.8em</span>,#<span class="hljs-number">0000</span> <span class="hljs-number">99%</span>,#<span class="hljs-number">000</span> <span class="hljs-number">101%</span>) <span class="hljs-number">50%</span> .<span class="hljs-number">8em</span>/<span class="hljs-number">3.2em</span> <span class="hljs-number">100%</span> repeat-x;
  <span class="hljs-attribute">background-clip</span>: text;
  <span class="hljs-attribute">animation</span>: l3 <span class="hljs-number">2s</span> linear infinite;
}
<span class="hljs-keyword">@keyframes</span> l3 {
  0% {<span class="hljs-attribute">background-position</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">50%</span> - <span class="hljs-number">1.6em</span>) <span class="hljs-number">0</span>,     <span class="hljs-number">50%</span>          .<span class="hljs-number">8em</span>}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">background-position</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">50%</span> + <span class="hljs-number">1.6em</span>) <span class="hljs-number">0</span>,<span class="hljs-built_in">calc</span>(<span class="hljs-number">50%</span> + <span class="hljs-number">3.2em</span>) .<span class="hljs-number">8em</span>}
}
</code></pre>
<p>This one is probably a bit trickier, but it’s another example to illustrate all the possibilities. From the simple gradient configuration to the most complex one, we can create as many loaders as we want.</p>
<p>What about creating your own CSS loader? You can use what you have learned from the article and try to create a loader that is not part of <a target="_blank" href="https://css-loaders.com/filling/">my collection</a>. The best way to learn is to practice – so give it a try!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By creating some cool loaders, we went through a bunch of CSS tricks related to gradients and backgrounds. Even if creating loaders is not your goal, you can always re-use the same tricks to do something else.</p>
<p>Don’t forget to check my <a target="_blank" href="https://css-tip.com/">CSS Tip blog</a> where I am sharing cool CSS tricks and demos.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
