<?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[ animations - 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[ animations - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 16:30:46 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/animations/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Create Zig-Zag CSS Loaders Using One Element ]]>
                </title>
                <description>
                    <![CDATA[ In a previous article, I showed you how to create filling CSS loaders collection where each loader was built using a single HTML element. Here, you’ll learn more about loaders by creating the Zig-Zag collection. Here is an overview of what you’ll be ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/zig-zag-css-loaders/</link>
                <guid isPermaLink="false">673e738139346c3d3174676e</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Temani Afif ]]>
                </dc:creator>
                <pubDate>Wed, 20 Nov 2024 23:40:49 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732045303831/af9240a9-6a25-4b13-a397-102ee098db78.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In <a target="_blank" href="https://www.freecodecamp.org/news/filling-css-loaders">a previous article</a>, I showed you how to create filling CSS loaders collection where each loader was built using a single HTML element. Here, you’ll learn more about loaders by creating <a target="_blank" href="https://css-loaders.com/zig-zag/">the Zig-Zag collection</a>.</p>
<p>Here is an overview of what you’ll be building:</p>
<div class="embed-wrapper"><iframe height="500" style="width:100%;height:500px" src="https://codepen.io/t_afif/embed/preview/RwXdvKj/83804c95907793e888c3036d7dd29251?default-tab=result" title="Embedded content" loading="lazy">
  See the Pen <a href="https://codepen.io/t_afif/pen/RwXdvKj/83804c95907793e888c3036d7dd29251">
  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>You can also check <a target="_blank" href="https://css-loaders.com/zig-zag/">my online collection</a> to see up to 20 variations using a zig-zag shape.</p>
<p>We won’t study all the variations but I will show you a few tricks that’ll help you create as many variations as you want.</p>
<h2 id="heading-how-to-create-a-zig-zag-shape">How to Create a Zig-Zag Shape</h2>
<p>The first step is to create a zig-zag shape. For this, you can grab the code from my CSS shape website: <a target="_blank" href="https://css-shape.com/zig-zag-line/">https://css-shape.com/zig-zag-line/</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731707755150/f1782db9-fa7f-472e-b771-cfc1c2046e0c.png" alt="Zig-Zag shape from css-shape.com" class="image--center mx-auto" width="1150" height="456" loading="lazy"></p>
<p>You can adjust the different variables to get the zig-zag you want. In our case, I will use an easier version with no variables.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.loader</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">47px</span>; <span class="hljs-comment">/* control the size */</span>
  <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">5</span>;
  <span class="hljs-attribute">background</span>:
   <span class="hljs-built_in">conic-gradient</span>(from <span class="hljs-number">135deg</span> at top,#<span class="hljs-number">000</span> <span class="hljs-number">90deg</span>,#<span class="hljs-number">0000</span> <span class="hljs-number">0</span>) top,
   <span class="hljs-built_in">conic-gradient</span>(from <span class="hljs-number">135deg</span> at top,#<span class="hljs-number">0000</span> <span class="hljs-number">90deg</span>,#<span class="hljs-number">000</span> <span class="hljs-number">0</span>) bottom;
  <span class="hljs-attribute">background-size</span>: <span class="hljs-number">20%</span> <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">background-repeat</span>: repeat-x;
}
</code></pre>
<p>And here is a figure to illustrate how those gradients create the shape:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731708477342/bbe3e0b6-24a2-498d-992b-4ee152b0d74c.png" alt="Color gradients created by the code" class="image--center mx-auto" width="838" height="292" loading="lazy"></p>
<p>The first gradient created the red part while the second one created the green part. We have two triangle shapes that repeat horizontally.</p>
<p>Since we have five repetitions, I used <code>aspect-ratio: 5</code> and <code>20% (100%/5)</code> in the <code>background-size</code>. You can make it more generic by introducing a variable to control the number of repetitions but as I said previously, I am going to keep things simple.</p>
<p>I want to point out that when using gradients, you can achieve the same result by using different syntaxes. For example, I can update the previous code with the following:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.loader</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">47px</span>; <span class="hljs-comment">/* control the size */</span>
  <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">5</span>;
  <span class="hljs-attribute">background</span>:
   <span class="hljs-built_in">conic-gradient</span>(from <span class="hljs-number">135deg</span> at top   ,#<span class="hljs-number">000</span> <span class="hljs-number">90deg</span>,#<span class="hljs-number">0000</span> <span class="hljs-number">0</span>),
   <span class="hljs-built_in">conic-gradient</span>(from -<span class="hljs-number">45deg</span> at bottom,#<span class="hljs-number">000</span> <span class="hljs-number">90deg</span>,#<span class="hljs-number">0000</span> <span class="hljs-number">0</span>) <span class="hljs-number">12.5%</span> <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">background-size</span>: <span class="hljs-number">20%</span> <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">background-repeat</span>: repeat-x;
}
</code></pre>
<p>It’s still the same output but with a different syntax for the second gradient. Did you notice the repeated part within the gradients? That part controls the coloration and we can define it as a variable to avoid repetition and be able to update the color only once in the code.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.loader</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">47px</span>; <span class="hljs-comment">/* control the size */</span>
  <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">5</span>;
  <span class="hljs-attribute">--c</span>:<span class="hljs-number">#000</span> <span class="hljs-comment">/* the color */</span> <span class="hljs-number">90deg</span>,<span class="hljs-number">#0000</span> <span class="hljs-number">0</span>;
  <span class="hljs-attribute">background</span>:
   <span class="hljs-built_in">conic-gradient</span>(from <span class="hljs-number">135deg</span> at top   ,var(--c)),
   <span class="hljs-built_in">conic-gradient</span>(from -<span class="hljs-number">45deg</span> at bottom,var(--c)) <span class="hljs-number">12.5%</span> <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">background-size</span>: <span class="hljs-number">20%</span> <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">background-repeat</span>: repeat-x;
}
</code></pre>
<p>Now we have our zig-zag shape and we are ready to animate it.</p>
<h2 id="heading-how-to-animate-the-zig-zag-shape">How to Animate the Zig-Zag Shape</h2>
<p>Since we’re using a background, we’ll animate the <code>background-position</code> to get our first loader. The idea is to move the gradients horizontally and create an infinite movement.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.loader</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">47px</span>; <span class="hljs-comment">/* control the size */</span>
  <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">5</span>;
  <span class="hljs-attribute">--c</span>:<span class="hljs-number">#000</span> <span class="hljs-comment">/* the color */</span> <span class="hljs-number">90deg</span>,<span class="hljs-number">#0000</span> <span class="hljs-number">0</span>;
  <span class="hljs-attribute">background</span>:
   <span class="hljs-built_in">conic-gradient</span>(from <span class="hljs-number">135deg</span> at top   ,var(--c)),
   <span class="hljs-built_in">conic-gradient</span>(from -<span class="hljs-number">45deg</span> at bottom,var(--c)) <span class="hljs-number">12.5%</span> <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">background-size</span>: <span class="hljs-number">20%</span> <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">background-repeat</span>: repeat-x;
  <span class="hljs-attribute">animation</span>: loading .<span class="hljs-number">8s</span> infinite linear;
}

<span class="hljs-keyword">@keyframes</span> loading {
  0%   {<span class="hljs-attribute">background-position</span>: <span class="hljs-number">0</span>   <span class="hljs-number">0</span>,<span class="hljs-number">12.5%</span> <span class="hljs-number">100%</span>}
  100% {<span class="hljs-attribute">background-position</span>: <span class="hljs-number">25%</span> <span class="hljs-number">0</span>,<span class="hljs-number">37.5%</span> <span class="hljs-number">100%</span>}
}
</code></pre>
<p>Note how we increased the X value of the <code>background-position</code> by <code>25%</code>. In case you are wondering what the logic behind that value is, here is the formula:</p>
<p><code>0.2 / (1 - 0.2) = .25 = 25%</code></p>
<p><code>.2</code> corresponds to the <code>20%</code> used inside the <code>background-size</code>.</p>
<div class="embed-wrapper"><iframe height="300" style="width:100%" src="https://codepen.io/t_afif/embed/preview/poMBgQO/5ddc67ad2324e68680f9d1071e46dc96?default-tab=result" title="Embedded content" loading="lazy">
  See the Pen <a href="https://codepen.io/t_afif/pen/poMBgQO/5ddc67ad2324e68680f9d1071e46dc96">
  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>We have our first loader! Actually, two loaders because we can easily change the direction of the movement by adding <code>animation-direction: reverse</code>.</p>
<p>Let’s try a different animation: using <code>clip-path</code> and the <code>inset()</code> value. We can easily adjust this technique to create many variations.</p>
<p>Let’s start with a basic example:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.loader</span> {
  <span class="hljs-comment">/* same code as previously */</span>
  <span class="hljs-attribute">animation</span>: loading .<span class="hljs-number">8s</span> infinite linear;
}
<span class="hljs-keyword">@keyframes</span> loading {
  0%   {<span class="hljs-attribute">clip-path</span>: <span class="hljs-built_in">inset</span>(<span class="hljs-number">0</span> <span class="hljs-number">100%</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span>)}
  100% {<span class="hljs-attribute">clip-path</span>: <span class="hljs-built_in">inset</span>(<span class="hljs-number">0</span> <span class="hljs-number">0</span>    <span class="hljs-number">0</span> <span class="hljs-number">0</span>)}
}
</code></pre>
<p>The <code>inset()</code> value creates a rectangle where only the part inside it will be visible. For this, we define a distance from each side of the element (top, right, bottom, left).</p>
<p>Logically, <code>inset(0 0 0 0)</code> shows the whole element since all the distances are equal to 0, but <code>inset(0 100% 0 0)</code> completely hides the element since the right value is equal to 100%. So it will touch the opposite edge, creating an empty rectangle.</p>
<p>By animating that right value from <code>100%</code> to <code>0</code> we create a reveal animation. Another loader variation!</p>
<div class="embed-wrapper"><iframe height="300" style="width:100%" src="https://codepen.io/t_afif/embed/preview/WNVWrVy/f6214a24e77a0ad6694d3a5bf93d2a23?default-tab=result" title="Embedded content" loading="lazy">
  See the Pen <a href="https://codepen.io/t_afif/pen/WNVWrVy/f6214a24e77a0ad6694d3a5bf93d2a23">
  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>If you inspect the code of the second animation, you will see that I did the same thing but with the left side.</p>
<p>We can also have a sliding effect if we animate both the left and right values while keeping their difference constant.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.loader</span> {
  <span class="hljs-comment">/* same code as previously */</span>
  <span class="hljs-attribute">animation</span>: loading .<span class="hljs-number">8s</span> infinite linear;
}
<span class="hljs-keyword">@keyframes</span> loading {
  0%   {<span class="hljs-attribute">clip-path</span>: <span class="hljs-built_in">inset</span>(<span class="hljs-number">0</span> <span class="hljs-number">60%</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span>  )}
  100% {<span class="hljs-attribute">clip-path</span>: <span class="hljs-built_in">inset</span>(<span class="hljs-number">0</span> <span class="hljs-number">0</span>   <span class="hljs-number">0</span> <span class="hljs-number">60%</span>)}
}
</code></pre>
<p>The right value animates from <code>60%</code> to <code>0</code> and the left one from <code>0</code> to <code>60%</code>, so we have a constant difference equal to <code>60%</code> which will create the illusion of a sliding rectangle. Another cool loader!</p>
<div class="embed-wrapper"><iframe height="300" style="width:100%" src="https://codepen.io/t_afif/embed/preview/wvVZGwy/71a0f6a7bf177c51252230d7e272fb57?default-tab=result" title="Embedded content" loading="lazy">
  See the Pen <a href="https://codepen.io/t_afif/pen/wvVZGwy/71a0f6a7bf177c51252230d7e272fb57">
  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>By trying different combinations of <code>inset()</code> values, you can get a lot of CSS loaders. Give it a try! You can also check <a target="_blank" href="https://css-loaders.com/zig-zag/">my online collection</a> and try to identify the variations that use <code>clip-path: inset()</code>.</p>
<h2 id="heading-how-to-create-a-discrete-animation">How to Create a Discrete Animation</h2>
<p>To achieve a discrete animation, you can use the <code>steps()</code> timing function instead of <code>linear</code>. Let’s start with the first example using <code>steps(2)</code>.</p>
<div class="embed-wrapper"><iframe height="300" style="width:100%" src="https://codepen.io/t_afif/embed/preview/YzmbzGL/28874aa2a6066deb4d06fdbefaaade62?default-tab=result" title="Embedded content" loading="lazy">
  See the Pen <a href="https://codepen.io/t_afif/pen/YzmbzGL/28874aa2a6066deb4d06fdbefaaade62">
  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>We can do the same with almost all the variations. Let’s try with the ones that use <code>clip-path: inset()</code>.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.loader</span> {
  <span class="hljs-comment">/* same code as previously */</span>
  <span class="hljs-attribute">animation</span>: loading .<span class="hljs-number">8s</span> infinite <span class="hljs-built_in">steps</span>(<span class="hljs-number">5</span>);
}
<span class="hljs-keyword">@keyframes</span> loading {
  0%   {<span class="hljs-attribute">clip-path</span>: <span class="hljs-built_in">inset</span>(<span class="hljs-number">0</span> <span class="hljs-number">100%</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span>)}
  100% {<span class="hljs-attribute">clip-path</span>: <span class="hljs-built_in">inset</span>(<span class="hljs-number">0</span> <span class="hljs-number">0</span>    <span class="hljs-number">0</span> <span class="hljs-number">0</span>)}
}
</code></pre>
<p>We have five repetitions so let’s see what we’ll get with <code>steps(5)</code>.</p>
<div class="embed-wrapper"><iframe height="300" style="width:100%" src="https://codepen.io/t_afif/embed/preview/JjgqjNr/9a6b43cda41ed9ec9cb49ea9bdaabb56?default-tab=result" title="Embedded content" loading="lazy">
  See the Pen <a href="https://codepen.io/t_afif/pen/JjgqjNr/9a6b43cda41ed9ec9cb49ea9bdaabb56">
  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>At the moment, it’s not good because we don’t see all the repetition. The animation stops at 4 repetitions, but we need to see the whole element (5 repetitions). The count starts from 0 so what we really need is 6 steps instead of 5 to show all the repetitions.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.loader</span> {
  <span class="hljs-comment">/* same code as previously */</span>
  <span class="hljs-attribute">animation</span>: loading .<span class="hljs-number">8s</span> infinite <span class="hljs-built_in">steps</span>(<span class="hljs-number">6</span>);
}
<span class="hljs-keyword">@keyframes</span> loading {
  0%   {<span class="hljs-attribute">clip-path</span>: <span class="hljs-built_in">inset</span>(<span class="hljs-number">0</span> <span class="hljs-number">100%</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span>)}
  100% {<span class="hljs-attribute">clip-path</span>: <span class="hljs-built_in">inset</span>(<span class="hljs-number">0</span> <span class="hljs-number">0</span>    <span class="hljs-number">0</span> <span class="hljs-number">0</span>)}
}
</code></pre>
<div class="embed-wrapper"><iframe height="300" style="width:100%" src="https://codepen.io/t_afif/embed/preview/RwXmKje/df2744eb1e707246a628b22ce96c7e4c?default-tab=result" title="Embedded content" loading="lazy">
  See the Pen <a href="https://codepen.io/t_afif/pen/RwXmKje/df2744eb1e707246a628b22ce96c7e4c">
  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>Even with 6 steps, the result is still not good but don’t worry, it’s not a bug. The default behavior of <code>steps()</code> gives us that output but we can update it to get the expected output:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.loader</span> {
  <span class="hljs-comment">/* same code as previously */</span>
  <span class="hljs-attribute">animation</span>: loading .<span class="hljs-number">8s</span> infinite <span class="hljs-built_in">steps</span>(<span class="hljs-number">6</span>,jump-none);
}
<span class="hljs-keyword">@keyframes</span> loading {
  0%   {<span class="hljs-attribute">clip-path</span>: <span class="hljs-built_in">inset</span>(<span class="hljs-number">0</span> <span class="hljs-number">100%</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span>)}
  100% {<span class="hljs-attribute">clip-path</span>: <span class="hljs-built_in">inset</span>(<span class="hljs-number">0</span> <span class="hljs-number">0</span>    <span class="hljs-number">0</span> <span class="hljs-number">0</span>)}
}
</code></pre>
<p>If you’re not familiar with <code>jump-none</code>, it’s a value that can fix most of your issues when working with <code>steps()</code>. I wrote a short article about it if you want more details: “<a target="_blank" href="https://css-tip.com/steps/">How to correctly use steps() with animations</a>“</p>
<div class="embed-wrapper"><iframe height="300" style="width:100%" src="https://codepen.io/t_afif/embed/preview/JjgqEpO/5433bef4c1b86de39837108b68ca8eba?default-tab=result" title="Embedded content" loading="lazy">
  See the Pen <a href="https://codepen.io/t_afif/pen/JjgqEpO/5433bef4c1b86de39837108b68ca8eba">
  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>Our animation looks perfect now! We can also make it an 11-step animation (<code>5×2 + 1</code>) and get another cool loader.</p>
<div class="embed-wrapper"><iframe height="300" style="width:100%" src="https://codepen.io/t_afif/embed/preview/vYowgRV/47df83689104665da6997c41a5825efb?default-tab=result" title="Embedded content" loading="lazy">
  See the Pen <a href="https://codepen.io/t_afif/pen/vYowgRV/47df83689104665da6997c41a5825efb">
  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>Even the sliding effect can have its discrete variation.</p>
<div class="embed-wrapper"><iframe height="300" style="width:100%" src="https://codepen.io/t_afif/embed/preview/bGXyZpO/799d03f2d573655e6522476418c6006a?default-tab=result" title="Embedded content" loading="lazy">
  See the Pen <a href="https://codepen.io/t_afif/pen/bGXyZpO/799d03f2d573655e6522476418c6006a">
  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 why I am using 4 and 7 steps? I’ll let you do the calculation as a small exercise.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This article showed you how to create zig-zag shapes, how to animate them using <code>clip-path</code>, and how to make a discrete animations. You can also consider more tricks like using both pseudo-elements to have two shapes.</p>
<p>I didn’t explore all the variations but you now have the recipe to create most of them!</p>
<p>You can explore <a target="_blank" href="https://css-loaders.com/zig-zag/">my Zig-Zag loaders collection</a> to study other variations and try to create your own loader. It’s a good opportunity to practice what you have learned from this article.</p>
 ]]>
                </content:encoded>
            </item>
        
            <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>
        
            <item>
                <title>
                    <![CDATA[ How to Set up Swiper Element in a React Application ]]>
                </title>
                <description>
                    <![CDATA[ Carousels or image sliders are an integral part of many web applications. They help you group multiple elements in a single view.  Using carousels, you can implement image slides, video slides, text slides, interactive image galleries, product catalo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-set-up-swiper-element-in-a-react-application/</link>
                <guid isPermaLink="false">66c5f68e1bceda0ea5c3977e</guid>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Alex Anie ]]>
                </dc:creator>
                <pubDate>Mon, 19 Feb 2024 16:25:55 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/How-to-Set-up-Swiper-Element-in-React-Application-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Carousels or image sliders are an integral part of many web applications. They help you group multiple elements in a single view. </p>
<p>Using carousels, you can implement image slides, video slides, text slides, interactive image galleries, product catalogs, team profiles, and more.</p>
<p><a target="_blank" href="https://swiperjs.com/">Swiper.js</a> comes with powerful functionalities that make it easy to create functional, reusable carousel components with stunning effects and functionality. You can enable zooming in and out from images, horizontal and vertical image scrolling, parallax slide effects, and infinite loop slides, just to mention a few.           </p>
<p>In this tutorial, we’ll be focusing on the new version of Swiper, 11.0.6, and the new Swiper Element that is recommended for building slides in Swiper.js. </p>
<p>By the end of this guide, you should be able to implement the new Swiper Element from Swiper.js to create responsive, dynamic slides with pre-made effects in your React project.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-swiperjs">What is Swiper.js?</a></li>
<li><a class="post-section-overview" href="#heading-installations">Installations</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-swiper">How to Set Up Swiper</a><ul>
<li><a class="post-section-overview" href="#heading-node-modules">Node Modules</a></li>
<li><a class="post-section-overview" href="#heading-swiper-custom-elements-from-cdn">Swiper Custom Elements from CDN</a></li>
<li><a class="post-section-overview" href="#heading-swiper-custom-elements">Swiper Custom Elements</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-swiper-parameters-as-attributes">Swiper Parameters as Attributes</a></li>
<li><a class="post-section-overview" href="#heading-responsive-breakpoints-in-swiper-element">Responsive Breakpoints in Swiper Element</a></li>
<li><a class="post-section-overview" href="#heading-pagination-and-navigation">Pagination and Navigation</a></li>
<li><a class="post-section-overview" href="#heading-lazy-loading-images">Lazy Loading Images</a></li>
<li><a class="post-section-overview" href="#heading-effects-in-swiper-element">Effects in Swiper Element</a></li>
<li><a class="post-section-overview" href="#heading-vertical-sliders">Vertical Sliders</a></li>
<li><a class="post-section-overview" href="#heading-how-to-style-swiper-element">How to Style Swiper Element</a><ul>
<li><a class="post-section-overview" href="#heading-reset-swiper-custom-styles">Reset Swiper Custom Styles</a></li>
<li><a class="post-section-overview" href="#heading-create-a-new-class-name">Create a New Class Name</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-how-to-build-a-custom-slider-element">How to Build a Custom Slider Element</a></li>
<li><a class="post-section-overview" href="#heading-summary">Summary</a></li>
<li><a class="post-section-overview" href="#heading-references">References</a></li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you get started, you'll need to have basic knowledge of <a target="_blank" href="https://react.dev/">React.js</a>.</p>
<p>If you need a refresher, you can check out this <a target="_blank" href="https://www.freecodecamp.org/news/react-beginner-handbook/">React handbook for beginners</a>.</p>
<h2 id="heading-what-is-swiperjs">What is Swiper.js?</h2>
<p>Swiper is a free, modern JavaScript library for building touch sliders (Carousels) with hardware transitions and amazing native behaviors. </p>
<p>Swiper is built for mobile websites, mobile web apps, and mobile native/hybrid apps. Swiper also comes with great support and functionalities for Desktop websites and web applications. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Untitled.png" alt="Migrating from Swiper React Component to Swiper Element Guide" width="600" height="400" loading="lazy"></p>
<p>As of the time of writing, Swiper <em>v11.0.6</em> recommends migrating to <a target="_blank" href="https://swiperjs.com/element">Swiper Element</a> instead of <a target="_blank" href="https://swiperjs.com/react">Swiper React Components</a>, which will likely be removed in future versions. In this tutorial, we’ll be focusing on Swiper Element and its use cases. </p>
<h2 id="heading-installations">Installations</h2>
<p>To get started, generate some React boilerplate code with <a target="_blank" href="https://vitejs.dev/guide/">Vite.js</a>. Next, navigate to the project directory in your Terminal and type the command below to install Swiper.js:</p>
<pre><code class="lang-bash">npm i swiper
</code></pre>
<p>Next, type the command below to launch your React.js boilerplate code:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>Click on the port URL on the Terminal to open up your React boilerplate code on the browser. </p>
<h2 id="heading-how-to-set-up-swiper">How to Set Up Swiper</h2>
<p>To use Swiper in a React project, you can use the following methods.</p>
<h3 id="heading-node-modules">Node Modules</h3>
<p>If you install Swiper via <code>npm i swiper</code>, then <code>import</code> the custom element from <em>node_modules</em> and register it. </p>
<pre><code class="lang-jsx">├─ main.jsx

<span class="hljs-comment">// import function to register Swiper custom elements</span>
<span class="hljs-keyword">import</span> { register } <span class="hljs-keyword">from</span> <span class="hljs-string">'swiper/element/bundle'</span>;
<span class="hljs-comment">// register Swiper custom elements</span>
register();
</code></pre>
<p>This should be done once directly on the <code>main.jsx</code> file to install it globally.</p>
<h3 id="heading-swiper-custom-elements-from-cdn">Swiper Custom Elements from CDN</h3>
<p>To enable Swiper Element, include the CDN link in the script tag as indicated below:</p>
<pre><code class="lang-jsx">├─ index.html
&lt;head&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/swiper@11/swiper-element-bundle.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
&lt;/head&gt;
</code></pre>
<p>Do this once directly on the <code>index.html</code> file to enable it globally.</p>
<h2 id="heading-swiper-custom-elements">Swiper Custom Elements</h2>
<p>If you’ve successfully set up Swiper Element, and call the <code>register()</code> method. To create a slider, you'll need to use <code>&lt;swiper-container&gt;</code> and <code>&lt;swiper-slide&gt;</code> from Swiper.js.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Usage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">swiper-container</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide1<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide2<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide3<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide4<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide5<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-container</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  )
}
</code></pre>
<p>The code above shows how to structure slides using Swiper Custom Elements. </p>
<ul>
<li><code>&lt;swiper-container&gt;</code>: This is the parent element that serves as a container to the <code>&lt;swiper-slide&gt;</code> Custom Element and other HTML Elements that make up the slides. Any Element that is nested inside the <code>&lt;swiper-container&gt;</code> Custom Element is treated as a slide.</li>
<li><code>&lt;swiper-slide&gt;</code>: This is the direct child of the <code>&lt;swiper-container&gt;</code> Custom Element. The <code>&lt;swiper-slide&gt;</code> serves as the individual slide of the slider components.</li>
</ul>
<p>For clarity purposes, I have added some custom CSS styles to make it visually appealing and easy to understand. Copy the code below: 👇</p>
<pre><code class="lang-css">*,*<span class="hljs-selector-pseudo">::before</span>, *<span class="hljs-selector-pseudo">::after</span> {
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">box-sizing</span>: border-box;
    <span class="hljs-attribute">font-family</span>: calibri;
}

<span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">justify-content</span>: center;
}

<span class="hljs-selector-tag">swiper-container</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">800px</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">200px</span>;
    <span class="hljs-attribute">line-height</span>: <span class="hljs-number">200px</span>;
    <span class="hljs-attribute">text-align</span>: center;
}

<span class="hljs-selector-tag">swiper-slide</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">4</span> <span class="hljs-number">47</span> <span class="hljs-number">46</span>);
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">25px</span>;
}

<span class="hljs-selector-tag">swiper-slide</span><span class="hljs-selector-pseudo">:nth-child(2)</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">15</span> <span class="hljs-number">118</span> <span class="hljs-number">110</span>);
}

<span class="hljs-selector-tag">swiper-slide</span><span class="hljs-selector-pseudo">:nth-child(3)</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">45</span> <span class="hljs-number">212</span> <span class="hljs-number">191</span>);
}

<span class="hljs-selector-tag">swiper-slide</span><span class="hljs-selector-pseudo">:nth-child(4)</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">153</span> <span class="hljs-number">246</span> <span class="hljs-number">228</span>);
}

<span class="hljs-selector-tag">swiper-slide</span><span class="hljs-selector-pseudo">:nth-child(5)</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">34</span> <span class="hljs-number">197</span> <span class="hljs-number">94</span>);
}
</code></pre>
<p>Your code should look just like this in your browser:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Swiper_custome_Elements.gif" alt="Slide shows created slider with Swiper Element" width="600" height="400" loading="lazy"></p>
<h2 id="heading-swiper-parameters-as-attributes">Swiper Parameters As Attributes</h2>
<p><a target="_blank" href="https://swiperjs.com/element">Parameters</a> in Swiper are <em>key</em> and <em>value</em> or <em>key</em>, <em>subkey</em>, and <em>value</em> pairs as indicated below.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> swiper = <span class="hljs-keyword">new</span> Swiper(<span class="hljs-string">'.swiper'</span>, {
  <span class="hljs-attr">scrollbar</span>: {
    <span class="hljs-attr">el</span>: <span class="hljs-string">'.swiper-scrollbar'</span>,
    <span class="hljs-attr">draggable</span>: <span class="hljs-literal">true</span>,
  },
<span class="hljs-attr">mousewheel</span>: {
    <span class="hljs-attr">invert</span>: <span class="hljs-literal">true</span>,
  },
<span class="hljs-attr">slidesPerView</span>: <span class="hljs-number">3</span>,
<span class="hljs-attr">spaceBetween</span>: <span class="hljs-number">20</span>,
<span class="hljs-attr">scrollbar</span>: {
    <span class="hljs-attr">clickable</span>: <span class="hljs-literal">true</span>,
});
</code></pre>
<p>The above code is valid if we are working directly on the <a target="_blank" href="https://codesandbox.io/p/sandbox/p3f7rh?file=%2Findex.html%3A58%2C33">index.html</a> file and we're using the <code>swiper</code> and <code>swiper-slide</code> classes on div elements. </p>
<p>For Swiper Custom Elements, you can write the same code as follows: 👇</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Usage</span>(<span class="hljs-params"></span>) </span>{
<span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
    👉  <span class="hljs-tag">&lt;<span class="hljs-name">swiper-container</span> <span class="hljs-attr">slides-per-view</span>=<span class="hljs-string">"3"</span> <span class="hljs-attr">space-between</span>=<span class="hljs-string">"20"</span> <span class="hljs-attr">scrollbar-clickable</span>=<span class="hljs-string">"true"</span> <span class="hljs-attr">mousewheel-invert</span>=<span class="hljs-string">"true"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide1<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide2<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide3<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide4<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide5<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-container</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
)
}
</code></pre>
<p>All Swiper parameters are written in the form of <a target="_blank" href="https://www.freecodecamp.org/news/snake-case-vs-camel-case-vs-pascal-case-vs-kebab-case-whats-the-difference/#kebab-case">kebab-case</a> attributes on the <code>&lt;swiper-container&gt;</code> Custom Elements.</p>
<p>Parameters with <em>subkeys</em> and <em>values</em> are written as a single attribute and value. For example, <code>scrollbar-clickable=”true”</code> is a parameter with subkey <em>(clickable)</em> now written as a single attribute with a value. </p>
<p>If you run the code above, you should get the same result as below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Parameter_as_value.gif" alt="swiper.js sliders with three-column views" width="600" height="400" loading="lazy"></p>
<p>From the browser out, we’ve been able to split the view to <em>three-column</em> views instead of the <em>one-column</em> view we previously had. We were able to do this using the <code>slide-per-view</code> attribute parsed to the <code>&lt;swiper-container&gt;</code> Custom Element. For the full available list of parameters, see the <a target="_blank" href="https://swiperjs.com/swiper-api#parameters">Swiper APIs</a>.</p>
<h2 id="heading-responsive-breakpoints-in-swiper-element">Responsive Breakpoints in Swiper Element</h2>
<p>Swiper Custom Element requires attributes to parse parameter objects. Where complex object properties are required in the case of breakpoints, we can use <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify">JSON.stringify()</a> to convert objects to strings, making the breakpoints object properties readable values to the <code>&lt;swiper-container&gt;</code>.</p>
<p>Consider the code example below:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Usage</span>(<span class="hljs-params"></span>) </span>{
<span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">swiper-container</span> <span class="hljs-attr">breakpoints</span>=<span class="hljs-string">{</span>
            <span class="hljs-attr">JSON.stringify</span>({

                <span class="hljs-attr">640:</span>{
                    <span class="hljs-attr">slidesPerView:</span> <span class="hljs-attr">1</span>,
                    <span class="hljs-attr">spaceBetween:</span> <span class="hljs-attr">20</span>,
                },

                <span class="hljs-attr">768:</span> {
                    <span class="hljs-attr">slidesPerView:</span> <span class="hljs-attr">3</span>,
                    <span class="hljs-attr">spaceBetween:</span> <span class="hljs-attr">40</span>,
                },

                <span class="hljs-attr">1024:</span> {
                    <span class="hljs-attr">slidesPerView:</span> <span class="hljs-attr">4</span>,
                    <span class="hljs-attr">spaceBetween:</span> <span class="hljs-attr">50</span>,
                }
            })
        }&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide1<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide2<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide3<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide4<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide5<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide6<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide7<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide8<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide9<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-container</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
)
}
</code></pre>
<p>Here, we are adding three different breakpoints <em><code>640</code></em>, <code>768</code>, and <code>1024</code> respectively for three different screen sizes (media queries), where <code>640</code> means (<code>max-width:640px</code>) for small screens. </p>
<p>Your code should look like this when you run it on the browser:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Responsive_Breakpoints.gif" alt="Responsive Breakpoints with Swiper Element" width="600" height="400" loading="lazy"></p>
<p>Keep in mind that breakpoints respond as soon as the components <a target="_blank" href="https://www.freecodecamp.org/news/how-to-understand-a-components-lifecycle-methods-in-reactjs-e1a609840630/">mount</a> (that is, React renders the components for the first time). So if you happen to resize your Desktop browser while learning this, you will need to reload the entire page by clicking on the reload icon to see the breakpoints changes. </p>
<h2 id="heading-pagination-and-navigation">Pagination and Navigation</h2>
<p>Swiper comes with <code>navigation</code> and <code>pagination</code> parameters for adding controls to sliders. With <code>navigation</code>, you can move from the current slide to the previous or next slide, while with <code>pagination</code> you can jump to a specific slide within the slider container. </p>
<p>To enable this on the swiper custom element, apply each parameter as an attribute on the <code>&lt;swiper-container&gt;</code> with a value of <code>true</code>. </p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Usage</span>(<span class="hljs-params"></span>) </span>{

<span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">swiper-container</span> <span class="hljs-attr">space-between</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">slides-per-view</span>=<span class="hljs-string">"3"</span> <span class="hljs-attr">pagination</span>=<span class="hljs-string">"true"</span> <span class="hljs-attr">navigation</span>=<span class="hljs-string">"true"</span> &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide1<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide2<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide3<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide4<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>Slide5<span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-container</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
)
}
</code></pre>
<p>Your code should look just like this on the browser:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/pagination_and_navigation.gif" alt="pagination and navigation in Swiper Element" width="600" height="400" loading="lazy"></p>
<p>To move the slides, click on the navigation arrow or pagination bullet points. </p>
<h2 id="heading-lazy-loading-images">Lazy Loading Images</h2>
<p>We can implement <a target="_blank" href="https://www.freecodecamp.org/news/how-to-lazy-load-images-in-react/">lazy loading</a> on image sliders in Swiper Custom Elements. Apply the <code>lazy=”true”</code> and <code>loading=”lazy”</code> as attributes on the <code>&lt;swiper-slide&gt;</code> and the <code>&lt;img /&gt;</code> tag, respectively. </p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Usage</span>(<span class="hljs-params"></span>) </span>{

<span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">swiper-container</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{</span>
        {
        "<span class="hljs-attr">--swiper-navigation-color</span>"<span class="hljs-attr">:</span> "#<span class="hljs-attr">fff</span>", 
        "<span class="hljs-attr">--swiper-pagination-color</span>"<span class="hljs-attr">:</span> "#<span class="hljs-attr">fff</span>"
        }
    } 
    <span class="hljs-attr">pagination-clickable</span>=<span class="hljs-string">"true"</span> 
    <span class="hljs-attr">navigation</span>=<span class="hljs-string">"true"</span> 
    <span class="hljs-attr">className</span>=<span class="hljs-string">"mySwiper"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span> <span class="hljs-attr">lazy</span>=<span class="hljs-string">"true"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/slightly-opened-silver-macbook-mP7aPSUm7aE"</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span> <span class="hljs-attr">lazy</span>=<span class="hljs-string">"true"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/macbook-y0_vFxOHayg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span> <span class="hljs-attr">lazy</span>=<span class="hljs-string">"true"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/black-macbook-near-black-iphone-7-plus-and-black-apple-watch-HY3l4IeOc3E"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span> <span class="hljs-attr">lazy</span>=<span class="hljs-string">"true"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/apple-products-on-table-tdMu8W9NTnY"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span> <span class="hljs-attr">lazy</span>=<span class="hljs-string">"true"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/turned-on-ipad-Im8ylpB8SpI"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-container</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
)
}
</code></pre>
<p>Implementing lazy loading on images will require the lazy <em>preloader</em> element to be added to each slide on the <code>&lt;swiper-slide&gt;</code> component when <code>lazy="true"</code> is set on the element.</p>
<p>I added some CSS styles to clean things up a bit, so you can just copy the below code:</p>
<pre><code class="lang-css">*,*<span class="hljs-selector-pseudo">::before</span>, *<span class="hljs-selector-pseudo">::after</span> {
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">box-sizing</span>: border-box;
    <span class="hljs-attribute">font-family</span>: calibri;
}

<span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">justify-content</span>: center;
}

<span class="hljs-selector-tag">swiper-container</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">800px</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">400px</span>;

}

<span class="hljs-selector-tag">swiper-slide</span> {
   <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
   <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
}

<span class="hljs-selector-tag">swiper-slide</span> <span class="hljs-selector-tag">img</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">object-fit</span>: cover;
}
</code></pre>
<p>Your code should look like this when you run it on the browser:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/lazy_loading_images.gif" alt="lazy loading images in Swiper Element" width="600" height="400" loading="lazy"></p>
<h2 id="heading-effects-in-swiper-element">Effects in Swiper Element</h2>
<p>You can add effects in Swiper Element by setting the <code>effect</code> attribute to the desired value you need for your project. For example, we implemented a <code>cube</code> effect to create a 3D-like slide display. </p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Usage</span>(<span class="hljs-params"></span>) </span>{

<span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">swiper-container</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{</span>
        {
        "<span class="hljs-attr">--swiper-navigation-color</span>"<span class="hljs-attr">:</span> "#<span class="hljs-attr">fff</span>", 
        "<span class="hljs-attr">--swiper-pagination-color</span>"<span class="hljs-attr">:</span> "#<span class="hljs-attr">fff</span>"
        }
    } 

    <span class="hljs-attr">pagination-clickable</span>=<span class="hljs-string">"true"</span> 
    <span class="hljs-attr">navigation</span>=<span class="hljs-string">"true"</span>
    <span class="hljs-attr">effect</span>=<span class="hljs-string">"cube"</span>
    <span class="hljs-attr">grab-cursor</span>=<span class="hljs-string">"true"</span>
    <span class="hljs-attr">cube-effect-shadow</span>=<span class="hljs-string">"true"</span>
    <span class="hljs-attr">cube-effect-slide-shadows</span>=<span class="hljs-string">"true"</span>
    <span class="hljs-attr">cube-effect-shadow-offset</span>=<span class="hljs-string">"20"</span>
    <span class="hljs-attr">cube-effect-shadow-scale</span>=<span class="hljs-string">"0.94"</span>

    <span class="hljs-attr">className</span>=<span class="hljs-string">"mySwiper"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span> &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/slightly-opened-silver-macbook-mP7aPSUm7aE"</span>  <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/macbook-y0_vFxOHayg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/black-macbook-near-black-iphone-7-plus-and-black-apple-watch-HY3l4IeOc3E"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/apple-products-on-table-tdMu8W9NTnY"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/turned-on-ipad-Im8ylpB8SpI"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-container</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
)
}
</code></pre>
<p>Your code should look like this on the browser:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/effects.gif" alt="cube effect in Swiper Element" width="600" height="400" loading="lazy"></p>
<p>Here, we apply the cube effect's attributes as follows:</p>
<ul>
<li><strong>effect=”cube”:</strong> sets the slider to a cube</li>
<li><strong>grab-cursor=”true”:</strong> changes the cursor to a grabbable icon.</li>
<li><strong>cube-effect-shadow=”true”</strong>: sets the shadow to the main slide component</li>
<li><strong>cube-effect-slide-shadows=”true”:</strong> sets the shadow to the slide element</li>
<li><strong>cube-effect-shadow-offset=”true”</strong>: sets the offset direction of the shadow</li>
<li><strong>cube-effect-shadow-scale</strong>: sets the size of the shadow</li>
</ul>
<p>Aside from the cube effect, you can specify other values as you can find listed in the <a target="_blank" href="https://swiperjs.com/swiper-api#cube-effect">Swiper API here</a>.</p>
<h2 id="heading-vertical-sliders">Vertical Sliders</h2>
<p>To apply vertical slides, simply apply the <code>direction="vertical”</code> attribute on the <code>&lt;swiper-component&gt;</code> as you can see in the code below:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Usage</span>(<span class="hljs-params"></span>) </span>{

<span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">swiper-container</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{</span>
        {
        "<span class="hljs-attr">--swiper-navigation-color</span>"<span class="hljs-attr">:</span> "#<span class="hljs-attr">fff</span>", 
        "<span class="hljs-attr">--swiper-pagination-color</span>"<span class="hljs-attr">:</span> "#<span class="hljs-attr">fff</span>"
        }
    } 

    <span class="hljs-attr">pagination-clickable</span>=<span class="hljs-string">"true"</span> 
    <span class="hljs-attr">navigation</span>=<span class="hljs-string">"true"</span>

    <span class="hljs-attr">direction</span>=<span class="hljs-string">"vertical"</span>

    <span class="hljs-attr">className</span>=<span class="hljs-string">"mySwiper"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span> &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/slightly-opened-silver-macbook-mP7aPSUm7aE"</span>  <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/macbook-y0_vFxOHayg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/black-macbook-near-black-iphone-7-plus-and-black-apple-watch-HY3l4IeOc3E"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

        <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-container</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
)
}
</code></pre>
<p>Your code should look like this when you run it on the browser:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/vertical_slides.gif" alt="vertical slides in Swiper Element" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-style-swiper-element">How to Style Swiper Element</h2>
<p>Styling Swiper Element is very straightforward. Swiper comes with lots of premade classes that are applied to Swiper parameters (Attributes in Swiper Custom Elements). We can overwrite the default style rules on these classes with the HTML <code>style</code> attribute or external CSS rules. </p>
<p>Swiper Custom Elements can be styled in two ways: you can reset the default styles on the <em>Swiper Custom Elements</em> and the <em>Custom CSS Classes</em>, or create a <em>new class name</em> on the Swiper Element and style it. </p>
<h3 id="heading-reset-swiper-custom-styles">Reset Swiper Custom Styles</h3>
<p>To reset the Swiper Custom Element styles, target the specific Swiper Custom Elements or classes that the default styles are applied to and change them to your desired styles.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Usage</span>(<span class="hljs-params"></span>) </span>{

<span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">swiper-container</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{</span>
        {
        "<span class="hljs-attr">--swiper-navigation-color</span>"<span class="hljs-attr">:</span> "#<span class="hljs-attr">fff</span>", 
        "<span class="hljs-attr">--swiper-pagination-color</span>"<span class="hljs-attr">:</span> "#<span class="hljs-attr">fff</span>"
        }
    } 

    <span class="hljs-attr">pagination-clickable</span>=<span class="hljs-string">"true"</span> 
    <span class="hljs-attr">navigation</span>=<span class="hljs-string">"true"</span>

    <span class="hljs-attr">className</span>=<span class="hljs-string">"mySwiper"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span> &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/slightly-opened-silver-macbook-mP7aPSUm7aE"</span>  <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/macbook-y0_vFxOHayg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/black-macbook-near-black-iphone-7-plus-and-black-apple-watch-HY3l4IeOc3E"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

        <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-container</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
)
}
</code></pre>
<p>From the code sample above, the <code>--swiper-navigation-color</code> and <code>--swiper-pagination-color</code> are set to the <code>#fff</code> color to change the default colors on the <em>navigation</em> and <em>pagination</em> buttons from the <code>#007aff</code> light blue color. Depending on what you are working on, you can customize this further using other custom classes from the <a target="_blank" href="https://swiperjs.com/swiper-api">Swiper APIs</a>. </p>
<p>Additionally, the <code>&lt;swiper-container&gt;</code> and <code>&lt;swiper-slide&gt;</code> are styled as follows:</p>
<pre><code class="lang-jsx">*,*::before, *::after {
    <span class="hljs-attr">margin</span>: <span class="hljs-number">0</span>;
    padding: <span class="hljs-number">0</span>;
    box-sizing: border-box;
    font-family: calibri;
}

body {
    <span class="hljs-attr">display</span>: flex;
    justify-content: center;
}

swiper-container {
    <span class="hljs-attr">width</span>: <span class="hljs-number">800</span>px;
    height: <span class="hljs-number">400</span>px;

}

swiper-slide {
   <span class="hljs-attr">width</span>: <span class="hljs-number">100</span>%;
   height: <span class="hljs-number">100</span>%;
}

swiper-slide img {
    <span class="hljs-attr">width</span>: <span class="hljs-number">100</span>%;
    height: <span class="hljs-number">100</span>%;
    object-fit: cover;
}
</code></pre>
<p>From the code sample above, the <code>swiper-container</code> is set to <code>width: 800px</code> and <code>height: 400px</code> to give the <code>swiper-container</code> a defined <code>width</code> and <code>height</code>. The <code>swiper-slide</code> is set to <code>100%</code> on both <code>width</code> and <code>height</code> to intrinsically set any child element of the <code>swiper-slide</code> to the default size of the <code>swiper-container</code>. </p>
<p>Also, the <code>swiper-container</code> does not have a specific <code>width</code> and <code>height</code> set. This makes it take the default size of the content within the <code>swiper-slide</code>. </p>
<p>Also, note that the <code>swiper-container</code> and <code>swiper-slide</code> are styled as an actual HTML element without a period (<code>.</code>) for class or hash sign (<code>#</code>) for id.</p>
<p>Your code should look like this when you run it on your browser:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/custom_styles.gif" alt="Styling Swiper Custom Element and Classes" width="600" height="400" loading="lazy"></p>
<h3 id="heading-create-a-new-class-name">Create a New Class Name</h3>
<p>Sometimes, a single page can contain multiple <code>&lt;swiper-container&gt;</code> that solve different problems, and each may require its own styles. Creating a new class name might be very useful to provide different styling options. </p>
<pre><code class="lang-jsx">&lt;swiper-container className=<span class="hljs-string">"image-swiper"</span> &gt;
            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span> &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/slightly-opened-silver-macbook-mP7aPSUm7aE"</span>  <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span></span>

            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/macbook-y0_vFxOHayg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span></span>
 &lt;/swiper-container&gt;
</code></pre>
<p>The <code>image-swiper</code> class indicates that the Swiper Element is an image slider.</p>
<h2 id="heading-how-to-build-a-custom-slider-element">How to Build a Custom Slider Element</h2>
<p>Swiper has default controls such as <em>navigation</em> and <em>pagination</em>, which makes it easy to control the slides within the <code>swiper-container</code>.  The navigation and pagination come with some default icons for user interaction. </p>
<p>For example, you have the <em>left</em> and <em>right</em> angle icons for navigation and small <em>bullet</em> icons for pagination. But based on your design or UI requirements for a specific website or application, this might need to change. </p>
<p>Below is a simple way of implementing custom SVGs as navigation icons and customizing the pagination for better user interaction. </p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Usage</span>(<span class="hljs-params"></span>) </span>{

<span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"slider-main-container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">swiper-container</span>

            <span class="hljs-attr">navigation-next-el</span>=<span class="hljs-string">".custom-next-button"</span>
            <span class="hljs-attr">navigation-prev-el</span>=<span class="hljs-string">".custom-prev-button"</span>
            <span class="hljs-attr">pagination-clickable</span>=<span class="hljs-string">"true"</span>
            <span class="hljs-attr">pagination-dynamic-bullets</span>=<span class="hljs-string">"true"</span>
            <span class="hljs-attr">autoplay-delay</span>=<span class="hljs-string">"2000"</span>
            <span class="hljs-attr">autoplay-disable-on-interaction</span>=<span class="hljs-string">"false"</span>
            <span class="hljs-attr">center-slides</span>=<span class="hljs-string">"true"</span>

            <span class="hljs-attr">style</span>=<span class="hljs-string">{</span>
                {
                "<span class="hljs-attr">--swiper-pagination-color</span>"<span class="hljs-attr">:</span> "#<span class="hljs-attr">fff</span>",
                "<span class="hljs-attr">--swiper-pagination-bullet-size</span>"<span class="hljs-attr">:</span> "<span class="hljs-attr">15px</span>",
                }
            }
        &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/white-lamborghini-aventador-parked-in-building-7_OQMgoGzDw"</span>  <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/shallow-focus-photo-of-white-sedan-oN661Kw9ZOY"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/black-car-interior-4xM5cytsdMo"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/turned-on-monitor-inside-vehicle-tU-L__PI7gw"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">swiper-slide</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://source.unsplash.com/black-and-blue-vacuum-cleaner-rHfTdK9YU2Q"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-slide</span>&gt;</span>

            {/* Navigations */}
        <span class="hljs-tag">&lt;/<span class="hljs-name">swiper-container</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-btn custom-prev-button"</span>&gt;</span>
          {/* <span class="hljs-comment">&lt;!-- https://feathericons.dev/?search=arrow-left&amp;iconset=feather --&gt;</span> */}
          <span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 24 24"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"24"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"24"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main-grid-item-icon"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span> <span class="hljs-attr">stroke</span>=<span class="hljs-string">"#fff"</span> <span class="hljs-attr">strokeLinecap</span>=<span class="hljs-string">"round"</span> <span class="hljs-attr">strokeLinejoin</span>=<span class="hljs-string">"round"</span> <span class="hljs-attr">strokeWidth</span>=<span class="hljs-string">"2"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">line</span> <span class="hljs-attr">x1</span>=<span class="hljs-string">"19"</span> <span class="hljs-attr">x2</span>=<span class="hljs-string">"5"</span> <span class="hljs-attr">y1</span>=<span class="hljs-string">"12"</span> <span class="hljs-attr">y2</span>=<span class="hljs-string">"12"</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">polyline</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"12 19 5 12 12 5"</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-btn custom-next-button"</span>&gt;</span>
             {/* <span class="hljs-comment">&lt;!-- https://feathericons.dev/?search=arrow-right&amp;iconset=feather --&gt;</span> */}
             <span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 24 24"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"24"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"24"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main-grid-item-icon"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span> <span class="hljs-attr">stroke</span>=<span class="hljs-string">"#fff"</span> <span class="hljs-attr">strokeLinecap</span>=<span class="hljs-string">"round"</span> <span class="hljs-attr">strokeLinejoin</span>=<span class="hljs-string">"round"</span> <span class="hljs-attr">strokeWidth</span>=<span class="hljs-string">"2"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">line</span> <span class="hljs-attr">x1</span>=<span class="hljs-string">"5"</span> <span class="hljs-attr">x2</span>=<span class="hljs-string">"19"</span> <span class="hljs-attr">y1</span>=<span class="hljs-string">"12"</span> <span class="hljs-attr">y2</span>=<span class="hljs-string">"12"</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">polyline</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"12 5 19 12 12 19"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
)
}
</code></pre>
<p>Here's what's going in in the above code:</p>
<ul>
<li><strong>navigation-next-el=".custom-next-button"</strong>: used to specify the custom element for next navigation icon.</li>
<li><strong>navigation-prev-el=".custom-prev-button"</strong>: used to specify the custom element for prev navigation icon.</li>
<li><strong>pagination-clickable="true"</strong>: enables and sets the pagination to a clickable button.</li>
<li><strong>pagination-dynamic-bullets="true"</strong>: used to the change design presentation of the pagination button.</li>
<li><strong>autoplay-delay="2000"</strong>: enables slides to automatically play themselves and repeat.</li>
<li><strong>center-slides="true"</strong>: sets the active slide to center.</li>
</ul>
<p>The SVG icons are declared outside the <code>swiper-container</code> element to prevent it from clipping to the first slide. The <code>&lt;main&gt;</code> tag is set to a class of <code>slider-wrapper</code> to wrap both the custom slider elements and the custom SVGs icons. </p>
<p>I added some CSS for styling. You can copy it here.</p>
<pre><code class="lang-css">*,*<span class="hljs-selector-pseudo">::before</span>, *<span class="hljs-selector-pseudo">::after</span> {
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">box-sizing</span>: border-box;
    <span class="hljs-attribute">font-family</span>: calibri;
}

<span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">justify-content</span>: center;
}

<span class="hljs-selector-tag">swiper-container</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">800px</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">400px</span>;

}

<span class="hljs-selector-class">.slider-main-container</span> {
    <span class="hljs-attribute">position</span>: relative;
}

<span class="hljs-selector-tag">swiper-slide</span> {
   <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
   <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
}

<span class="hljs-selector-tag">swiper-slide</span> <span class="hljs-selector-tag">img</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">object-fit</span>: cover;
}

<span class="hljs-selector-class">.nav-btn</span> {
    <span class="hljs-attribute">display</span>: block;
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">z-index</span>: <span class="hljs-number">20</span>;
    <span class="hljs-attribute">user-select</span>: none;
    <span class="hljs-attribute">-webkit-user-select</span>: none;
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.3</span>);
    <span class="hljs-attribute">cursor</span>: pointer;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">2px</span>;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
    <span class="hljs-attribute">transition</span>: background <span class="hljs-number">0.5s</span> ease;
}

<span class="hljs-selector-class">.nav-btn</span><span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">255</span>, <span class="hljs-number">165</span>, <span class="hljs-number">0</span>);
}

<span class="hljs-selector-class">.nav-btn</span><span class="hljs-selector-class">.custom-prev-button</span> {
    <span class="hljs-attribute">top</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">2em</span>;
}

<span class="hljs-selector-class">.nav-btn</span><span class="hljs-selector-class">.custom-next-button</span> {
    <span class="hljs-attribute">right</span>: <span class="hljs-number">2em</span>;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">50%</span>;
}
</code></pre>
<p>Your code should look like this when you run it on the browser:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Custom_Slider_Elements.gif" alt="Customize Swiper Element in React" width="600" height="400" loading="lazy"></p>
<h2 id="heading-summary">Summary</h2>
<p>Swiper Element is a new way of creating sliders in Swiper.js from the new version 11.0.6. </p>
<p>In this tutorial, I explained how to create and implement the new Swiper Custom Element in a React Application.</p>
<p>You saw some use cases for Swiper.js such as navigation, pagination, slides, effects, and properties. You also learned how to customize Swiper from the default design to give it a more professional style.</p>
<p>Thank you for reading!</p>
<h3 id="heading-references">References</h3>
<ol>
<li><a target="_blank" href="https://swiperjs.com/">Official Swiper Docs</a></li>
<li><a target="_blank" href="https://swiperjs.com/element">Swiper Element Docs</a></li>
<li><a target="_blank" href="https://swiperjs.com/swiper-api">Swiper API reference</a></li>
<li><a target="_blank" href="https://swiperjs.com/demos">Swiper Project Demo</a></li>
<li><a target="_blank" href="https://github.com/nolimits4web/swiper/">Swiper Git Issues</a>s</li>
</ol>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create Animations in React 18 ]]>
                </title>
                <description>
                    <![CDATA[ We are surrounded by gorgeous web applications. Sometimes I catch myself admiring visual effects on some website and wondering how they were made.  Well today I'll show you how you can create awesome CSS animations in React 18. As always, we'll work ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-animations-in-react/</link>
                <guid isPermaLink="false">66bc4cf83fc58765eaa843c6</guid>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Matéu.sh ]]>
                </dc:creator>
                <pubDate>Thu, 08 Feb 2024 23:51:27 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/Animations-splash--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>We are surrounded by gorgeous web applications. Sometimes I catch myself admiring visual effects on some website and wondering how they were made. </p>
<p>Well today I'll show you how you can create awesome CSS animations in React 18.</p>
<p>As always, we'll work on the real world example but we'll just focus on the animations only to avoid confusion. If you want to see the final results applied to a proper application, then don't worry. I've attached the source code of a pet project so feel free to <a target="_blank" href="https://mateuszsokola.github.io/2048-in-react/">play with it</a>. </p>
<p>Before we start, I need to give you some context – I designed those animations for my 2048 Game in React. This game is a part of my <a target="_blank" href="https://www.udemy.com/course/2048-in-react-and-nextjs/?referralCode=AC3FD6336BAB9C402106">online course on Udemy</a> but I will tell you more about it at the end of this article.  </p>
<p>You can find the <a target="_blank" href="https://github.com/mateuszsokola/2048-in-react/">source code on GitHub</a>. Here's the final result of what we'll be creating:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/all-animations.gif" alt="Image" width="600" height="400" loading="lazy">
<em>All animations of 2048-in-react</em></p>
<h2 id="heading-prerequisites"><strong>🛠️ P</strong>rerequisites<em>**</em></h2>
<p>Before we start, make sure you know some basics of React and CSS. It would be great if you are familiar CSS transitions but it isn't necessary. Actually I'm hoping this article will encourage you to go down that rabbit hole on your own. Believe me – nothing is more rewarding than users admiring your work. </p>
<p>Also, you don't need any tools, but if you want to run the example project on your computer, then you will need to install <a target="_blank" href="https://nodejs.org/en">Node.js</a> first.</p>
<h2 id="heading-quick-introduction">🕹️ <strong>Quick Introduction</strong></h2>
<p>If you aren't familiar with the 2048 game, here's the gist: the player must combine tiles containing the same numbers until they reach the number 2048. The tiles can contain only numbers that represent a power of two starting from 2 – this means 2, 4, 8, 16, 32, and so on. The board has dimension of 4 x 4 tiles, so that it can fit up to 16 tiles.</p>
<p>Let me briefly show you what animations I prepared for the game's users:</p>
<p>The first animation is supposed to visualize the tile movement.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/slide.gif" alt="Image" width="600" height="400" loading="lazy">
<em>The "tile sliding" animation</em></p>
<p>The game would look janky if tiles disappeared and popped up in different places. CSS transitions help make the movement smooth for users.</p>
<p>The second animation highlights tile creation and their merges.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/hightlight-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>The "tile highlighting" animation</em></p>
<p>This animation helps users spot tiles that are changed after the movement.</p>
<p>I think that's all I need to tell you about the project. Let's get our hands dirty!</p>
<h2 id="heading-how-to-create-the-highlighting-animation">🌟 How to Create the Highlighting Animation</h2>
<p>We'll start with the animation responsible for highlighting changes. I must admit I had a hard time to find a "beautiful" way to visualize it. The main objective was to bring the user's focus to tiles that changed their values or were created. I decided to rescale those tiles because it didn't want the animation to be too "intrusive".</p>
<p>So how is this going to work? First, we'll increase the size of the tile to 110%. Once the tile reaches 110% of its original size, we will downscale it back to 100%. The entire animation will last 0.2s (0.1s upscale, 0.1s downscale). I think that's enough to show the user's updated elements.</p>
<p>We can accomplish this animation using the following CSS transitions:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.tile</span> {
  // ...
  <span class="hljs-attribute">transition-property</span>: transform;
  <span class="hljs-attribute">transition-duration</span>: <span class="hljs-number">100ms</span>;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1</span>);
}
</code></pre>
<p>Brief explanation of those CSS properties:</p>
<ul>
<li><code>transition-property</code> – defines the property on which the transition will be applied. In our case, we want to animate the transformation – the change of the element's size. </li>
<li><code>transition-duration</code> – defines transition duration. In our case – 0.1s.</li>
<li><code>transform</code> – this property allows us to rotate, scale, skew, or translate an element. Side note: the <code>scale(1)</code> means 100%, and we will use it as a default value.</li>
</ul>
<p>The CSS transition is ready. Now we need to implement rescaling in React. </p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Tile</span>(<span class="hljs-params">{ value }</span>) </span>{
  <span class="hljs-keyword">const</span> [scale, setScale] = useState(<span class="hljs-number">1</span>);

  <span class="hljs-keyword">const</span> previousValue = usePreviousProps(value);
  <span class="hljs-keyword">const</span> hasChanged = previousValue !== value;

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (hasChanged) {
      setScale(<span class="hljs-number">1.1</span>);
      <span class="hljs-built_in">setTimeout</span>(
          <span class="hljs-function">() =&gt;</span> setScale(<span class="hljs-number">1</span>), 
          <span class="hljs-number">100</span> <span class="hljs-comment">/* 100ms == 0.1s */</span>
      );
    }
  }, [hasChanged, setScale]);

  <span class="hljs-keyword">const</span> style = {
    <span class="hljs-attr">transform</span>: <span class="hljs-string">`scale(<span class="hljs-subst">${scale}</span>)`</span>
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"tile"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{style}</span>&gt;</span>
      {value}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};
</code></pre>
<p>Let me briefly explain this code:</p>
<ol>
<li>It sets the initial scale using the <code>useState</code> hook. By default, it's <code>1</code> to reflect 100% of the tile size.</li>
<li>We take advantage of the <code>usePreviousProps</code> hook to retrieve the previous value of the tile. If the tile is freshly created, the previous value will be <code>undefined</code>.</li>
<li>The <code>useEffect</code> hook plays a key role in our animation – it's checking if the tile's value has changed. If yes, it will scale it up to 110% and after 0.1s it will set it back to 100%.</li>
<li>The <code>style</code> constant is used to inject inline CSS attributes into the <code>div</code> element. </li>
</ol>
<p>And the result is the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/hightlight.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Tile creation (aka "hightlighting")</em></p>
<h2 id="heading-how-to-create-the-sliding-animation">🛝 How to Create the Sliding Animation</h2>
<p>The second animation is responsible for tile movements. I hope you agree with me that users might feel confused if they can't trace tiles moving across the board. After every move they would need to analyze the entire board again. It'd be a poor user-experience.</p>
<p>Let's think about how we can fix it. We could definitely take advantage of CSS properties responsible for positioning, such as <code>left</code> and <code>top</code>. If we follow this approach, we need to add a few additional CSS transitions. Let's do it.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.tile</span> {
  <span class="hljs-attribute">position</span>: absolute;
  // ...
  <span class="hljs-attribute">transition-property</span>: left, top, transform;  // <span class="hljs-attribute">added</span>: left, top
  transition-duration: <span class="hljs-number">250ms</span>, <span class="hljs-number">250ms</span>, <span class="hljs-number">100ms</span>; // <span class="hljs-attribute">added</span>: <span class="hljs-number">250ms</span>, <span class="hljs-number">250ms</span>
  transform: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1</span>);
}
</code></pre>
<p>Once we've declared the transitions, we can implement the logic responsible for tile movement.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Tile</span>(<span class="hljs-params">{ value, position }</span>) </span>{
  <span class="hljs-comment">// ...</span>
  <span class="hljs-keyword">const</span> boardWidthInPixels = <span class="hljs-number">464</span>; 
  <span class="hljs-keyword">const</span> tileCount = <span class="hljs-number">4</span>;

  <span class="hljs-keyword">const</span> positionToPixels = <span class="hljs-function">(<span class="hljs-params">position</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> (position / tileCount) * boardWidthInPixels;
  };    

  <span class="hljs-keyword">const</span> style = {
    <span class="hljs-attr">top</span>: positionToPixels(position[<span class="hljs-number">0</span>]),
    <span class="hljs-attr">left</span>: positionToPixels(position[<span class="hljs-number">1</span>]),      
    <span class="hljs-attr">transform</span>: <span class="hljs-string">`scale(<span class="hljs-subst">${scale}</span>)`</span>
  };

  <span class="hljs-comment">// ...</span>
};
</code></pre>
<p>As you can see, the equation in the <code>positionToPixels</code> function needs to know the position of the tile, the total number of tiles per row and column, and the total board length in pixels (width or height – same, it is a square). The calculated value is passed down to the <code>style</code> constant which we passed down to the div element in the previous step.</p>
<p>The result is the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/slide-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Animation for tile movement</em></p>
<h2 id="heading-summary"><strong>🏁 Summary</strong></h2>
<p>Adding CSS transitions into your React project may seem intimidating at first but it really isn't. As you can see, just a few lines of code significantly improved the user-experience of my game. </p>
<p>Keep in mind that while animations can indeed improve user experience, they can also ruin it. Always aim to find the right balance when you are applying them. It takes some practice, and that's why I hope this article encouraged you to experiment on your own.</p>
<p>The best way to learn is by practicing and learning from others. That's why you should check the <a target="_blank" href="https://github.com/mateuszsokola/2048-in-react/">source code on my 2048 Game on Github</a>. Don't forget to give it a star 🌟 . It's the easiest way to bookmark it in your profile so you never lose it. </p>
<p>If this article helped you, please share it on your social media or give me a <a target="_blank" href="https://twitter.com/msokola">shout-out on Twitter</a>. Thank you!</p>
<h2 id="heading-would-you-like-to-build-your-own-2048-game">🏫 <strong>Would You Like to Build Your Own 2048 Game?</strong></h2>
<p>As I told you at the beginning, I created an online course on Udemy where I teach how to create a fully-functional 2048 Game in React 18. I'm giving 50% discount for freeCodeCamp readers. Just use the code <strong>50DISCOUNT</strong> to enroll.</p>
<h3 id="heading-join-my-react-18-course-on-udemyhttpswwwudemycomcourse2048-in-react-and-nextjsreferralcodeac3fd6336bab9c402106"><strong>🧑‍🎓 Join my <a target="_blank" href="https://www.udemy.com/course/2048-in-react-and-nextjs/?referralCode=AC3FD6336BAB9C402106">React 18 course on Udemy</a></strong></h3>
<p>What you'll learn:</p>
<ul>
<li>How to build 2048 game with React 18 and Next.js.</li>
<li>Essential React hooks such as useState, useRef, useCallback, useEffect, and many more.</li>
<li>Managing state using Reducer and React Context.</li>
<li>How to create responsive mobile apps that support touch events (like mobile swiping). </li>
<li>Integrate TypeScript into your React projects.</li>
<li>Testing React apps.</li>
</ul>
<p>I created this course because I believe programming should be fun and unleash creativity. Rather than build yet another TODO list or a shopping cart, let's create something that you can show to your friends or maybe even a hiring manager!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create Custom CSS Animations with Examples ]]>
                </title>
                <description>
                    <![CDATA[ Animations are a crucial component of modern web design. They enable you to create dynamic and engaging web elements that attract more customers and drive more sales. In this article, we will discuss how to create cool custom animations using CSS. Pr... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-custom-css-animations/</link>
                <guid isPermaLink="false">66bb8a8d7a6500a14ba5b774</guid>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Eric Hu ]]>
                </dc:creator>
                <pubDate>Tue, 09 Jan 2024 21:59:50 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Animations are a crucial component of modern web design. They enable you to create dynamic and engaging web elements that attract more customers and drive more sales.</p>
<p>In this article, we will discuss how to create cool custom animations using CSS.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before going forward with this article, make sure you have basic knowledge of HTML and CSS. </p>
<p>I'll assume you are familiar with <a target="_blank" href="https://www.freecodecamp.org/news/use-css-selectors-to-style-webpage/">CSS selectors</a>, defining element <a target="_blank" href="https://www.w3schools.com/css/css_dimension.asp">size</a> and <a target="_blank" href="https://www.w3schools.com/css/css_colors.asp">color</a>, <a target="_blank" href="https://www.ericsdevblog.com/courses/html-css/4/">positioning elements</a>, <a target="_blank" href="https://www.freecodecamp.org/news/css-opacity/">adjusting opacity</a>, and <a target="_blank" href="https://www.freecodecamp.org/news/complete-guide-to-css-transform-functions-and-properties/">transforming elements</a>.</p>
<h2 id="heading-how-to-create-your-first-css-animation">How to Create Your First CSS Animation</h2>
<p>Let's start by preparing an HTML element.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-class">.square</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100px</span>;
  <span class="hljs-attribute">background-color</span>: purple;

  <span class="hljs-comment">/* Center the element */</span>
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>, -<span class="hljs-number">50%</span>);
}
</code></pre>
<p>Lines 7 to 10 demonstrate a commonly used method to <a target="_blank" href="https://www.ericsdevblog.com/posts/how-to-center-a-div-in-css/">center an element using CSS</a>. Here's the result of the above code:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/square-center.png" alt="square center" width="600" height="400" loading="lazy">
<em>Centered square</em></p>
<p>Before we start crafting the animation, you must first think about what kind of effect you wish to achieve. </p>
<p>For example, for this tutorial, I want to create a bouncing effect for the square. This means I need to create an animation based on the <code>top</code> property so that the square can move up and down.</p>
<pre><code class="lang-css"><span class="hljs-keyword">@keyframes</span> bounce {
  0% {
    <span class="hljs-attribute">top</span>: <span class="hljs-number">90%</span>;
  }
  100% {
    <span class="hljs-attribute">top</span>: <span class="hljs-number">10%</span>;
  }
}
</code></pre>
<p>To define an animation, you need to use the <code>@keyframes</code> rule, which allows you to define keyframes in the animation process. </p>
<p>The keyframes are set with percentage values, starting from <code>0%</code> and finishing with <code>100%</code>. For instance, in our example, the animation will start from <code>top: 90%;</code>, and end with <code>top: 10%;</code>, and after that, it will reset back to <code>50%</code>.</p>
<p>And, of course, you need to tie the <code>bounce</code> animation with the square (<code>animation-name</code>) and also tell the browser how long you want this animation to last (<code>animation-duration</code>). Here's how you do that:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.square</span> {
  . . .
  <span class="hljs-attribute">animation-name</span>: bounce;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">2s</span>;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/bounce-1.gif" alt="square moves up" width="600" height="400" loading="lazy">
<em>A square moving up</em></p>
<h2 id="heading-how-to-add-multiple-keyframes">How to Add Multiple Keyframes</h2>
<p>But as you can see, the square starts from the bottom, moves to the top, and then resets back to the center. That is not exactly a bouncing effect. So, how can we make the square move back down?</p>
<p>To do that, you can set up a third keyframe like this:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@keyframes</span> bounce {
  0% {
    <span class="hljs-attribute">top</span>: <span class="hljs-number">90%</span>;
  }
  50% {
    <span class="hljs-attribute">top</span>: <span class="hljs-number">10%</span>;
  }
  100% {
    <span class="hljs-attribute">top</span>: <span class="hljs-number">90%</span>;
  }
}
</code></pre>
<p>This way, the square will start from the bottom (<code>top: 90%;</code>), move to the top (<code>top: 10%;</code>), and then move back down (<code>top: 90%;</code>).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/bounce-2.gif" alt="square moves up and then down" width="600" height="400" loading="lazy">
<em>The square moving up and then back down</em></p>
<h2 id="heading-how-to-create-a-repeat-animation">How to Create a Repeat Animation</h2>
<p>There is one problem that still needs to be solved. The animation only plays once. In practice, you might want your animation to repeat several times to create the effect that the square is actually bouncing. </p>
<p>Instead of creating more keyframes, which is not easy, you can define an <code>animation-iteration-count</code> property and specify the number of times you want the animation to repeat.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.square</span> {
  . . .
  <span class="hljs-attribute">animation-name</span>: bounce;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">2s</span>;
  <span class="hljs-attribute">animation-iteration-count</span>: <span class="hljs-number">5</span>;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/bounce-3.gif" alt="repeat animation 5 times" width="600" height="400" loading="lazy">
<em>The square moving up and down for five times</em></p>
<p>And if you want the animation to last indefinitely, simply specify <code>infinite</code>.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.square</span> {
  . . .
  <span class="hljs-attribute">animation-name</span>: bounce;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">2s</span>;
  <span class="hljs-attribute">animation-iteration-count</span>: infinite;
}
</code></pre>
<h2 id="heading-how-to-use-a-timing-function-for-smoother-animation">How to Use a Timing Function for Smoother Animation</h2>
<p>Finally, the bouncing effect started working, but there is still room for improvement. The movement of the square seems a bit unnatural. The bouncing effect would look better if you could smooth out the movement.</p>
<p>This can be achieved with a timing function. By default, the browser will assume a <code>linear</code> timing function, which means the animation will have constant speed from start to end. But you can change that using the <code>animation-timing-function</code> property, like this:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.square</span> {
  . . .
  <span class="hljs-attribute">animation-name</span>: bounce;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">2s</span>;
  <span class="hljs-attribute">animation-iteration-count</span>: infinite;
  <span class="hljs-attribute">animation-timing-function</span>: ease-in-out;
}
</code></pre>
<p>By specifying <code>ease-in-out</code>, you are telling the browser to start the animation slowly and also end it gradually. As a result, the entire animation will look a lot smoother.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/bounce-4.gif" alt="ease in out" width="600" height="400" loading="lazy">
<em><code>ease-in-out</code> making the square move smoothly</em></p>
<h3 id="heading-the-cubic-bezier-curve">The Cubic Bezier curve</h3>
<p>The value <code>ease-in-out</code> actually represents a mathematical equation called <a target="_blank" href="https://www.w3schools.com/cssref/func_cubic-bezier.php">Cubic Bezier</a>. I will spare you the complex mathematical definitions, and you only need to know that the function defines a curve with four control points. </p>
<p><a target="_blank" href="https://cubic-bezier.com/">cubic-bezier.com</a> is an online tool that allows you to customize the curve by simply dragging the control points.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/cubic-bezier.png" alt="cubic bezier" width="600" height="400" loading="lazy">
<em>A Cubic Bezier curve</em></p>
<p>The points control the shape of the curve, and the slope of the curve then controls the speed of the animation. For example, the above graph indicates the animation will start slowly, accelerate, and then end smoothly.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.square</span> {
  . . .
  <span class="hljs-attribute">animation-name</span>: bounce;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">2s</span>;
  <span class="hljs-attribute">animation-iteration-count</span>: infinite;
  <span class="hljs-attribute">animation-timing-function</span>: <span class="hljs-built_in">cubic-bezier</span>(<span class="hljs-number">0.17</span>, <span class="hljs-number">0.67</span>, <span class="hljs-number">0.8</span>, <span class="hljs-number">0.36</span>);
}
</code></pre>
<p>In most cases, you don't have to define a customized Cubic Bezier curve. There are several predefined curves that should be enough for most use cases.</p>
<p><code>ease</code> represents the curve <code>cubic-bezier(0.25, 0.1, 0.25, 1)</code>. The animation will start by slowly accelerating and then decelerate to stop.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/ease.png" alt="ease" width="600" height="400" loading="lazy">
<em>Cubic Bezier curve for ease</em></p>
<p><code>ease-in</code> represents the curve <code>cubic-bezier(0.42, 0, 1, 1)</code>. The animation will start smoothly and then stop rather abruptly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/ease-in.png" alt="ease in" width="600" height="400" loading="lazy">
<em>Cubic Bezier curve for ease-in</em></p>
<p><code>ease-out</code> represents the curve <code>cubic-bezier(0, 0, 0.58, 1)</code>. The animation will start abruptly and then slow down to stop smoothly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/ease-out.png" alt="ease out" width="600" height="400" loading="lazy">
<em>Cubic Bezier curve for ease-out</em></p>
<p><code>ease-in-out</code> represents the curve <code>cubic-bezier(0.42, 0, 0.58, 1)</code>. The animation will be smooth on both ends.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/ease-in-out.png" alt="ease in out" width="600" height="400" loading="lazy">
<em>Cubic Bezier curve for ease-in-out</em></p>
<h3 id="heading-the-steps-function">The <code>steps()</code> function</h3>
<p>Besides the smooth curve, you can also specify a stepping function. The function <code>steps()</code> takes two arguments. The first one specifies the number of steps, and the second one sets the point at which the change occurs within the step, either start or end.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.square</span> {
  . . .
  <span class="hljs-attribute">animation-name</span>: bounce;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">2s</span>;
  <span class="hljs-attribute">animation-iteration-count</span>: infinite;
  <span class="hljs-attribute">animation-timing-function</span>: <span class="hljs-built_in">steps</span>(<span class="hljs-number">5</span>, start);
}
</code></pre>
<p>In this case, the animation will be divided into five steps, and for each step, the change will happen at the beginning of the step.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/bounce-5.gif" alt="5 steps" width="600" height="400" loading="lazy">
<em>A demo for the steps function</em></p>
<p>There are also two shortcuts available for the <code>steps()</code> function. <code>step-start</code> corresponds to <code>steps(1, start)</code>, and <code>step-end</code> corresponds to <code>steps(1, end)</code>.</p>
<h2 id="heading-how-to-combine-multiple-animations">How to Combine Multiple Animations</h2>
<p>So far, we've covered all the fundamentals you should understand to create CSS animations. And now, it is time to get more creative.</p>
<p>Our previous examples all focused on changing the <code>top</code> property in order to create the bounce effect. You can, in fact, combine multiple properties in one animation. For example, you can create a pulse effect by changing the element's shape and opacity together.</p>
<pre><code class="lang-css"><span class="hljs-keyword">@keyframes</span> pulse {
  0% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>, -<span class="hljs-number">50%</span>) <span class="hljs-built_in">scale</span>(<span class="hljs-number">1</span>);
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
  }
  50% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>, -<span class="hljs-number">50%</span>) <span class="hljs-built_in">scale</span>(<span class="hljs-number">1.2</span>);
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0.7</span>;
  }
  100% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>, -<span class="hljs-number">50%</span>) <span class="hljs-built_in">scale</span>(<span class="hljs-number">1</span>);
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
  }
}
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-class">.ball</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100px</span>;
  <span class="hljs-attribute">background-color</span>: purple;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;

  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>, -<span class="hljs-number">50%</span>);

  <span class="hljs-attribute">animation</span>: pulse <span class="hljs-number">2s</span> ease-in-out infinite;
}
</code></pre>
<p>Also note that the animation properties can be combined into a shortcut, <code>animation</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/pulse.gif" alt="pulse" width="600" height="400" loading="lazy">
<em>The pulse effect animation</em></p>
<h2 id="heading-other-animation-related-properties">Other Animation-Related Properties</h2>
<p>Besides the animation properties we have discussed so far, there are some miscellaneous properties we should talk about. They can also be useful sometimes. </p>
<p>First of all, there is the <code>animation-direction</code> property, which defines how the animation will be played. The property accepts four different values:</p>
<ul>
<li><code>normal</code>: The animation is played forward.</li>
<li><code>reverse</code>: The animation is played backward.</li>
<li><code>alternate</code>: The animation is played forward first, then backward. It only works when <code>animation-iteration-count</code> is more than 1.</li>
<li><code>alternate-reverse</code>: The animation is played backward first, then forward.</li>
</ul>
<p>By default, the animation will start playing immediately after the page is loaded. But you can change that with the <code>animation-delay</code> property, which specifies how long you wish to wait before the animation starts.</p>
<p>Lastly, the <code>animation-fill-mode</code> property determines how the element will be displayed before and after the animation is played. By default, the element will not retain any styles from the animation. After the animation stops, the element will reset to normal.</p>
<p>When <code>animation-fill-mode</code> is set to <code>forwards</code>, the element will retain the styles from the last keyframe of the animation after the animation is played.</p>
<p>When set to <code>backwards</code>, the element will take on the styles from the first keyframe of the animation as soon as the animation is played.</p>
<p>When set to <code>both</code>, the element will retain the styles from the first keyframe before the animation starts (behaves like <code>backwards</code>), and it will also retain the styles from the last keyframe after the animation is finished (like <code>forwards</code>).</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This tutorial covered everything you need to know to start creating CSS animations using the <code>@keyframes</code> rule.</p>
<pre><code class="lang-css"><span class="hljs-keyword">@keyframes</span> pulse {
  0% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>, -<span class="hljs-number">50%</span>) <span class="hljs-built_in">scale</span>(<span class="hljs-number">1</span>);
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
  }
  50% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>, -<span class="hljs-number">50%</span>) <span class="hljs-built_in">scale</span>(<span class="hljs-number">1.2</span>);
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0.7</span>;
  }
  100% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>, -<span class="hljs-number">50%</span>) <span class="hljs-built_in">scale</span>(<span class="hljs-number">1</span>);
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
  }
}
</code></pre>
<p>We also went over several animation-related CSS properties:</p>
<ul>
<li><code>animation-duration</code>: Defines how long the animation will last.</li>
<li><code>animation-iteration-count</code>: Defines how many times the animation will repeat.</li>
<li><code>animation-timing-function</code>: Specifies the timing function, which controls the speed at which the animation is played.</li>
<li><code>animation-direction</code>: The direction in which the animation is played.</li>
<li><code>animation-delay</code>: The delay before the animation begins.</li>
<li><code>animation-fill-mode</code>: Whether or not to retain styles from the animation after it is finished.</li>
</ul>
<p>For further readings on HTML and CSS, check out this course series -&gt; <a target="_blank" href="https://www.ericsdevblog.com/courses/html-css/">HTML &amp; CSS: A Practical Guide</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create Scroll Animations with React, Tailwind CSS, and Framer Motion ]]>
                </title>
                <description>
                    <![CDATA[ By Manu Arora Scroll-based animations are triggered when a user scrolls on a webpage. Recently, I built a Scroll Animation with Framer Motion that moves grids in uneven directions. This project prompted me to write a tutorial about how I did that her... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-scroll-animations-with-framer-motion-and-react/</link>
                <guid isPermaLink="false">66d46012c7632f8bfbf1e443</guid>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tailwind ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 27 Nov 2023 18:47:58 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/11/FreeCodeCamp.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Manu Arora</p>
<p>Scroll-based animations are triggered when a user scrolls on a webpage. Recently, I built a <a target="_blank" href="https://www.aceternity.com/components/container-scroll-animation">Scroll Animation with Framer Motion</a> that moves grids in uneven directions. This project prompted me to write a tutorial about how I did that here on freeCodeCamp.  </p>
<p>The Framer Motion library makes it super easy to integrate animations into your React applications. With a few lines of code, you can achieve what might seem like a difficult task.</p>
<p>Today, we are going to build a scroll-triggered animation that rotates, translates, and scales a card (or a container) when the user scrolls.</p>
<h2 id="heading-what-were-building">What We're Building:</h2>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://stackblitz.com/edit/stackblitz-starters-2mybwg?embed=1&amp;file=src%2FScroll.tsx&amp;view=preview">https://stackblitz.com/edit/stackblitz-starters-2mybwg?embed=1&amp;file=src%2FScroll.tsx&amp;view=preview</a></div>
<p>Here, as the user scrolls, three things are going to happen:</p>
<ol>
<li>The text <code>Unleash the power of Scroll Animations</code> moves up a little bit.</li>
<li>The Frame (the black container which is holding the cards) rotates and aligns perfectly with the page.</li>
<li>The cards inside the frame translate up a bit – providing a parallax effect.</li>
</ol>
<p>All of these actions are achieved with the help of the <code>scrollYProgress</code> value from the <code>useScroll()</code> function from Framer Motion. The <code>scrollYProgress</code> value (more on this later) gives you the progress between <code>0</code> to <code>1</code>, determining where the user currently is on the page.</p>
<p>Let's jump into the code and see how to implement this animation from scratch.</p>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>For this demo, we are going to use:</p>
<ul>
<li>Next.js for writing our component</li>
<li>Tailwind CSS for styling and CSS</li>
<li>Framer Motion for animations</li>
</ul>
<h2 id="heading-how-to-setup-the-project"><strong>How to Setup the Project</strong></h2>
<p>Setting up the project is pretty simple. Here are the steps you should follow:</p>
<p>First, you'll need to install Next.js if you don't already have it.</p>
<p>Open your terminal and type the following command:</p>
<pre><code>npx create-next-app@latest scroll-animation --typescript --eslint
</code></pre><p>This will initialize a <code>Next.js</code> application where you can go to the <code>app</code> directly for routes and the <code>components</code> folder to create your components.</p>
<p>We are going to keep it really simple for this demo and add the component in the <code>components</code> folder.</p>
<p>Next you'll need to install Tailwind CSS, which you can do like this:</p>
<pre><code>npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
</code></pre><p>Now add Tailwind to your project by copying the following file contents into the <code>tailwind.config.ts</code> file which gets created after you run the above step:</p>
<pre><code>tailwind.config.js

<span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('tailwindcss').Config}</span> </span>*/</span>
<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">content</span>: [
    <span class="hljs-string">"./app/**/*.{js,ts,jsx,tsx,mdx}"</span>,
    <span class="hljs-string">"./pages/**/*.{js,ts,jsx,tsx,mdx}"</span>,
    <span class="hljs-string">"./components/**/*.{js,ts,jsx,tsx,mdx}"</span>,

    <span class="hljs-comment">// Or if using `src` directory:</span>
    <span class="hljs-string">"./src/**/*.{js,ts,jsx,tsx,mdx}"</span>,
  ],
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {},
  },
  <span class="hljs-attr">plugins</span>: [],
}
</code></pre><p>Now add the following global styles in the <code>globals.css</code> file:</p>
<pre><code>@tailwind base;
@tailwind components;
@tailwind utilities;
</code></pre><p>With these steps completed, you should be able to write the component and add it to your project seamlessly.  </p>
<p>Now that we are done with the setup, let's deep dive into the component code that we are going to build.</p>
<h2 id="heading-how-to-build-the-scroll-component">How to Build the Scroll Component</h2>
<p>There's essentially only one main component that we are going to work with. We are calling it <code>Scroll</code>, because why not? Here's the code:</p>
<pre><code class="lang-tsx">export const Scroll = () =&gt; {
  return (
    &lt;div className="flex flex-col bg-white h-screen w-screen"&gt;
      &lt;ScrollCore /&gt;
    &lt;/div&gt;
  );
};
export const ScrollCore = () =&gt; {
  return (
    &lt;div className="h-[120vh] p-10 flex items-center justify-center relative "&gt;
      &lt;div
        className="py-40 w-full relative"
      &gt;
        &lt;Header /&gt;
        &lt;Card /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

export const Header = () =&gt; {
  return (
    &lt;div
      className="div max-w-5xl mx-auto text-center"
    &gt;
      &lt;h1 className="text-4xl font-semibold"&gt;
        Unleash the power of &lt;br /&gt;{' '}
        &lt;span className="text-5xl lg:text-6xl  font-bold mt-1 leading-none"&gt;
          Scroll Animations
        &lt;/span&gt;
      &lt;/h1&gt;
    &lt;/div&gt;
  );
};

export const Card = () =&gt; {
    // Going to implement later in the blog
};
</code></pre>
<p>The <code>Scroll</code> components is the container which contains a <code>ScrollCore</code> component.</p>
<p>The <code>ScrollCore</code> component holds the <code>Header</code> and the <code>Card</code> components:</p>
<ul>
<li>The <code>Header</code> is the text component that translates to the top (as we saw in the preview</li>
<li>The <code>Card</code> component is the <code>Frame</code> that we talked about earlier.</li>
</ul>
<p>Both of these components are styles with Tailwind CSS. We give a class of h-screen and w-screen to the container, and we want the container to take the entire height and width of the screen.</p>
<h2 id="heading-how-to-build-the-card-component">How to Build the Card Component</h2>
<p>The <code>Card</code> component is pretty basic (without the animation) since we are going to render multiple cards inside a container with <code>grids</code> from Tailwind CSS. Here's the code:</p>
<pre><code class="lang-tsx">import {users} from './users';

export const Card = () =&gt; {
  return (
    &lt;div
      style={{
        boxShadow:
          '0 0 #0000004d, 0 9px 20px #0000004a, 0 37px 37px #00000042, 0 84px 50px #00000026, 0 149px 60px #0000000a, 0 233px 65px #00000003',
      }}
      className="max-w-5xl -mt-12 mx-auto h-[30rem] md:h-[40rem] w-full border-4 border-[#6C6C6C] p-6 bg-[#222222] rounded-[30px] shadow-2xl"
    &gt;
      &lt;div className="bg-gray-100 h-full w-full rounded-2xl grid grid-cols-2 md:grid-cols-4 gap-4 overflow-hidden p-4"&gt;
        {users.map((user, idx) =&gt; (
          &lt;div
            key={`user-${idx}`}
            className="bg-white rounded-md cursor-pointer relative"
          &gt;
            &lt;div className="absolute top-2 right-2 rounded-full text-xs font-bold bg-white px-2 py-1"&gt;
              {user.badge}
            &lt;/div&gt;
            &lt;img
              src={user.image}
              className="rounded-tr-md rounded-tl-md text-sm "
            /&gt;
            &lt;div className="p-4"&gt;
              &lt;h1 className="font-semibold text-sm "&gt;{user.name}&lt;/h1&gt;
              &lt;h2 className=" text-gray-500 text-xs "&gt;{user.designation}&lt;/h2&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        ))}
      &lt;/div&gt;
    &lt;/div&gt;
  );
};
</code></pre>
<p>Here, we are giving a <code>box shadow</code> which I have taken from <a target="_blank" href="https://manuarora.in/boxshadows">Box shadows for Tailwind CSS</a>. Also we are giving it a background of <code>#22222</code>. In tailwind, we can use arbitrary values using the <code>[]</code> notation. For example, we have given the class <code>bg-[#22222]</code> for the background.</p>
<p>We are also using a <code>users</code> array to render out a list of users. The user array looks something like this:</p>
<pre><code class="lang-tsx">export const users = [
  {
    name: 'Manu Arora',
    designation: 'Founder, Algochurn',
    image: 'https://picsum.photos/id/10/300/300',
    badge: 'Mentor',
  },
  {
    name: 'Sarah Singh',
    designation: "Founder, Sarah's Kitchen",
    image: 'https://picsum.photos/id/11/300/300',
    badge: 'Mentor',
  },
  // Rest of the users...
];
</code></pre>
<p>Here, we are rendering out the user's name, designation, image, and badge.</p>
<p>Now we're done with the basic <code>cards</code> and <code>header</code> design, so we can move on to animating these using Framer Motion.</p>
<h2 id="heading-how-to-add-the-animation-functions">How to Add the Animation Functions</h2>
<p>Framer Motion provides helpful functions that you can use to animate anything on a webpage. Some of the use cases of these animations might be:</p>
<ul>
<li>Animate when the user drags and drops</li>
<li>Animate when the user scrolls</li>
<li>Animate when the user clicks or hovers</li>
<li>Animate on page load</li>
</ul>
<p>In this demo, we want to animate on <code>scroll</code>. For that, we can use the <code>useScroll()</code> function provided by Framer Motion.</p>
<p>To animate using scroll, we are going to:</p>
<ol>
<li>Get <code>scrollYProgress</code> from <code>useScroll()</code> method</li>
<li>Use the <code>useTransform</code> hook to transform <code>scrollYProgress</code> values</li>
<li>Use the transformed values to animate our cards.</li>
</ol>
<p>Let's take a look at the code snippet for the same:</p>
<pre><code class="lang-tsx">import { useScroll, useTransform, motion } from 'framer-motion';

import { users } from './users';

export const Scroll = () =&gt; {
  return (
    &lt;div className="flex flex-col bg-white h-screen w-screen"&gt;
      &lt;ScrollCore /&gt;
    &lt;/div&gt;
  );
};
export const ScrollCore = () =&gt; {
  const { scrollYProgress } = useScroll();

  const rotate = useTransform(scrollYProgress, [0, 1], [20, 0]);
  const scale = useTransform(scrollYProgress, [0, 1], [1.05, 1]);
  const translate = useTransform(scrollYProgress, [0, 1], [0, -100]);

  return (
    &lt;div className="h-[120vh] transform scale-[0.8] p-10 flex items-center justify-center relative "&gt;
      &lt;div
        className="py-40 w-full relative"
        style={{
          perspective: '1000px',
        }}
      &gt;
        &lt;Header /&gt;
        &lt;Card /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};
// rest of the code
</code></pre>
<p>Let's break down what's happening in the code:</p>
<p>We are using the <code>scrollYProgress</code> value from the <code>useScroll()</code> function. This <code>scrollYProgress</code> is a <code>motion value</code> which we can use with <code>motion.div</code> from Framer Motion to animate various CSS properties. The CSS properties we are going to animate are <code>rotate</code>, <code>scale</code> and <code>translate</code>.</p>
<p>We combine these <code>scrollYProgress</code> values with another hook from framer-motion which is <code>useTransform</code>.  </p>
<p>The <code>useTransform</code> hook is responsible from converting one value to another. For example, if we want to rotate the card from 45 degrees to 90 degrees when the user scrolls from the top of the page to bottom of the page, we could use something like this:</p>
<pre><code class="lang-tsx"> const rotate = useTransform(scrollYProgress, [0, 1], [45, 90]);
</code></pre>
<p>This <code>rotate</code> value can now be passed to the <code>style</code> tag of a <code>motion.div</code> element. Remember that a regular a div cannot be used here since rotate is a MOTION VALUE and should be used with a motion.div element.</p>
<p>Similarly, we are going to add all the values for <code>rotate</code>, <code>scale</code> and <code>translate</code> like this:</p>
<pre><code class="lang-tsx">const rotate = useTransform(scrollYProgress, [0, 1], [20, 0]);
const scale = useTransform(scrollYProgress, [0, 1], [1.05, 1]);
const translate = useTransform(scrollYProgress, [0, 1], [0, -100]);
</code></pre>
<p>Here:</p>
<ol>
<li>When a user scrolls from top to bottom (0 is starting, 1 is ending, meaning the user has scrolled from top to bottom), we want to rotate the card from 20 degrees to 0 degrees. But here's a catch: we also specify the <code>perspective</code> property and set it to <code>800px</code> so that it gives a 3D effect.</li>
<li>We want the scale to go from <code>1.05</code> to <code>1</code> when the user scrolls.</li>
<li>And finally we want to translate the cards from 0 to -100 px in the Y direction (later on how we are going to animate the Y direction).</li>
</ol>
<p>Now that we have all the animations setup, we just need to pass these values to the components' <code>style</code> tags and get the animations working.</p>
<h2 id="heading-how-to-add-the-animations">How to Add the Animations</h2>
<p>We saw earlier how we use the <code>useScroll()</code> hook to get scroll progress and get the <code>rotate</code>, <code>scale</code> and <code>translate</code> values (these values are called motion values, because they can only be used with a <code>motion.div</code> block). Now it's time to actually use these values within our component.</p>
<p>We can do this by passing down the <code>rotate</code>, <code>scale</code> and <code>translate</code> values to the <code>Header</code> and <code>Card</code> component and using them in their respective style tags.  </p>
<p>Let's have a look at the code snippet to understand it better:</p>
<pre><code class="lang-tsx">import { useScroll, useTransform, motion } from 'framer-motion';

import { users } from './users';

export const Scroll = () =&gt; {
  return (
    &lt;div className="flex flex-col bg-white h-screen w-screen"&gt;
      &lt;ScrollCore /&gt;
    &lt;/div&gt;
  );
};
export const ScrollCore = () =&gt; {
  const { scrollYProgress } = useScroll();

  const rotate = useTransform(scrollYProgress, [0, 1], [20, 0]);
  const scale = useTransform(scrollYProgress, [0, 1], [1.05, 1]);
  const translate = useTransform(scrollYProgress, [0, 1], [0, -100]);

  return (
    &lt;div className="h-[120vh] transform scale-[0.8] p-10 flex items-center justify-center relative "&gt;
      &lt;div
        className="py-40 w-full relative"
        style={{
          perspective: '1000px',
        }}
      &gt;
        &lt;Header translate={translate} /&gt;
        &lt;Card rotate={rotate} translate={translate} scale={scale} /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};
// rest of the code
</code></pre>
<p>Here, we are passing down the translate, rotate, and scale values inside the components:</p>
<pre><code class="lang-tsx">&lt;Header translate={translate} /&gt;
&lt;Card rotate={rotate} translate={translate} scale={scale} /&gt;
</code></pre>
<ul>
<li>For <code>Header</code>, we only want to translate the text from bottom to top a bit (sort of giving a parallax effect)</li>
<li>For <code>Card</code>, we want to do a bit more with rotation and translation.</li>
</ul>
<p>Here's the code for the <code>Header</code> component:</p>
<pre><code class="lang-tsx">export const Header = ({ translate }: any) =&gt; {
  return (
    &lt;motion.div
      style={{
        translateY: translate,
      }}
      className="div max-w-5xl mx-auto text-center"
    &gt;
      &lt;h1 className="text-4xl font-semibold"&gt;
        Unleash the power of &lt;br /&gt;{' '}
        &lt;span className="text-5xl lg:text-6xl  font-bold mt-1 leading-none"&gt;
          Scroll Animations
        &lt;/span&gt;
      &lt;/h1&gt;
    &lt;/motion.div&gt;
  );
};
</code></pre>
<p>Here, we converted the <code>div</code> to <code>motion.div</code> so that it can accept motion values.</p>
<p>We also animated the <code>translateY</code> property given by Framer Motion and added the <code>translate</code> value. Remember, translate goes from <code>0</code> to <code>-100</code>.</p>
<p>And that is it to animate the text. Essentially for the <code>Header</code> component, we have written just three lines of code to animate it. Pretty cool, huh?</p>
<p>Here's the code for the <code>Card</code> component:</p>
<pre><code class="lang-tsx">export const Card = ({
  rotate,
  scale,
  translate,
}: {
  rotate: any;
  scale: any;
  translate: any;
}) =&gt; {
  return (
    &lt;motion.div
      style={{
        rotateX: rotate, // rotate in X-axis
        scale,
        boxShadow:
          '0 0 #0000004d, 0 9px 20px #0000004a, 0 37px 37px #00000042, 0 84px 50px #00000026, 0 149px 60px #0000000a, 0 233px 65px #00000003',
      }}
      className="max-w-5xl -mt-12 mx-auto h-[30rem] md:h-[40rem] w-full border-4 border-[#6C6C6C] p-6 bg-[#222222] rounded-[30px] shadow-2xl"
    &gt;
      &lt;div className="bg-gray-100 h-full w-full rounded-2xl grid grid-cols-2 md:grid-cols-4 gap-4 overflow-hidden p-4"&gt;
        {users.map((user, idx) =&gt; (
          &lt;motion.div
            key={`user-${idx}`}
            className="bg-white rounded-md cursor-pointer relative"
            style={{ translateY: translate }}
            whileHover={{
              boxShadow:
                '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)',
            }}
          &gt;
            &lt;div className="absolute top-2 right-2 rounded-full text-xs font-bold bg-white px-2 py-1"&gt;
              {user.badge}
            &lt;/div&gt;
            &lt;img
              src={user.image}
              className="rounded-tr-md rounded-tl-md text-sm "
            /&gt;
            &lt;div className="p-4"&gt;
              &lt;h1 className="font-semibold text-sm "&gt;{user.name}&lt;/h1&gt;
              &lt;h2 className=" text-gray-500 text-xs "&gt;{user.designation}&lt;/h2&gt;
            &lt;/div&gt;
          &lt;/motion.div&gt;
        ))}
      &lt;/div&gt;
    &lt;/motion.div&gt;
  );
};
</code></pre>
<p>This is the same code as before with just one difference: the <code>div</code> is now converted to a <code>motion.div</code> to accept values wherever required. Here, we want the <code>cards</code> inside of the container to translate, and the entire card itself to rotate.</p>
<p>From the code above, let's look at this part closely:</p>
<pre><code class="lang-tsx">&lt;motion.div
      style={{
        rotateX: rotate, // rotate in X-axis
        scale,
        boxShadow:
          '0 0 #0000004d, 0 9px 20px #0000004a, 0 37px 37px #00000042, 0 84px 50px #00000026, 0 149px 60px #0000000a, 0 233px 65px #00000003',
      }}
      className="max-w-5xl -mt-12 mx-auto h-[30rem] md:h-[40rem] w-full border-4 border-[#6C6C6C] p-6 bg-[#222222] rounded-[30px] shadow-2xl"
    &gt;
    // rest of the code...
&lt;/motion.div&gt;
</code></pre>
<p>Here, we want to: </p>
<ol>
<li><code>rotateX</code> so that it goes from giving an illusion of lying flat on the screen to standing straight. (Remember, as the user scrolls, the value goes from <code>20deg</code> to <code>0deg</code>.)</li>
<li>The <code>scale</code> of the container (or the frame) is also animated to go from <code>1.05</code> to <code>1</code>.</li>
</ol>
<p>Let's look at the cards inside this frame now:</p>
<pre><code class="lang-tsx">{users.map((user, idx) =&gt; (
          &lt;motion.div
            key={`user-${idx}`}
            className="bg-white rounded-md cursor-pointer relative"
            style={{ translateY: translate }}
            whileHover={{
              boxShadow:
                '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)',
            }}
          &gt;
            &lt;div className="absolute top-2 right-2 rounded-full text-xs font-bold bg-white px-2 py-1"&gt;
              {user.badge}
            &lt;/div&gt;
            &lt;img
              src={user.image}
              className="rounded-tr-md rounded-tl-md text-sm "
            /&gt;
            &lt;div className="p-4"&gt;
              &lt;h1 className="font-semibold text-sm "&gt;{user.name}&lt;/h1&gt;
              &lt;h2 className=" text-gray-500 text-xs "&gt;{user.designation}&lt;/h2&gt;
            &lt;/div&gt;
          &lt;/motion.div&gt;
        ))}
</code></pre>
<p>Here, the <code>translateY</code> property is animated and the div is converted to a <code>motion.div</code>.</p>
<p>And that's it. That's all it takes to animate on scroll using Framer Motion.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you learned how to animate using Framer Motion. Essentially, we looked at two core functions:</p>
<ul>
<li><code>useScroll()</code></li>
<li><code>useTransform()</code></li>
</ul>
<p>There are other functions you can use which can help you achieve your animation goals. But I believe Framer Motion is a really simple animation API to work with, given its intuitive functions and ease of use.  </p>
<p>Here's the complete <a target="_blank" href="https://stackblitz.com/edit/stackblitz-starters-2mybwg?file=src%2FScroll.tsx">source code</a> for the demo.</p>
<p>I've created various other demos like this <a target="_blank" href="https://www.aceternity.com/components/parallax-scroll">Parallax Effect Using Tailwind CSS and Framer Motion</a> which essentially uses the same pattern that we discussed in this guide.  </p>
<p>If you liked this demo and want me to create more of these cool <a target="_blank" href="https://aceternity.com/components">Tailwind CSS and Framer motion components</a>, let me know on <a target="_blank" href="https://twitter.com/mannupaaji">Twitter</a> and I'd be more than happy to work on it. :)</p>
<p>Happy coding ✨</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Web Animation Techniques – CSS vs JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ Animations play a vital role in enhancing user experience on web pages. They add interactivity, visual appeal, and engagement to websites and web applications.  Two popular methods for creating web animations are Cascading Style Sheets (CSS) and Java... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/web-animation-css-vs-javascript/</link>
                <guid isPermaLink="false">66c4c41d356b00550fa89b5c</guid>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joan Ayebola ]]>
                </dc:creator>
                <pubDate>Thu, 19 Oct 2023 14:54:50 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/10/Addition-and-Subtraction-Word-Problems-Math-Presentation-Orange-in-Pink-and-Purple-Groovy-Style.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Animations play a vital role in enhancing user experience on web pages. They add interactivity, visual appeal, and engagement to websites and web applications. </p>
<p>Two popular methods for creating web animations are Cascading Style Sheets (CSS) and JavaScript. Each of these techniques has its strengths and use cases, and understanding when to use one over the other is crucial for web developers. </p>
<p>In this article, we will explore the key differences between CSS and JavaScript animations, provide code examples, and guide you on when to choose one over the other.</p>
<h2 id="heading-css-animations">CSS Animations</h2>
<p>CSS (Cascading Style Sheets) is commonly used for styling web pages. But it also provides a powerful and straightforward way to create animations. </p>
<p>CSS animations are primarily used for simple, declarative animations like transitions, keyframes, and transformations.</p>
<h3 id="heading-css-transition-example">CSS Transition Example</h3>
<p>First, let's look at an example of a simple CSS transition:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.button</span> {
  <span class="hljs-attribute">transition</span>: background-color <span class="hljs-number">0.3s</span> ease;
}

<span class="hljs-selector-class">.button</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#3498db</span>;
}
</code></pre>


  


  Hover me




<p>In the above example, the background color of the button will smoothly transition to a new color when a user hovers over it. This is achieved using the <code>transition</code> property. </p>
<p>Let's learn a bit more about how the <code>transition</code> property works:</p>
<ul>
<li><code>background-color</code>: This is the CSS property being animated. In this case, it's the background color of the button.</li>
<li><code>0.3s</code>: This is the duration of the animation. It specifies how long the transition takes to complete (0.3 seconds in this example).</li>
<li><code>ease-in-out</code>: This is the timing function that controls the animation's speed curve. It starts slow, speeds up in the middle, and slows down at the end.</li>
<li><code>0s</code>: This is the delay before the animation starts (in this case, there is no delay).</li>
</ul>
<h3 id="heading-keyframes-example">Keyframes Example</h3>
<p>Keyframes are another type of CSS animation you can use to style your elements. Here's an example of one in action:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@keyframes</span> pulse {
            0% {
                <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1</span>);
            }
            50% {
                <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1.1</span>);
            }
            100% {
                <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1</span>);
            }
        }

        <span class="hljs-selector-class">.element</span> {
            <span class="hljs-attribute">width</span>: <span class="hljs-number">100px</span>;
            <span class="hljs-attribute">height</span>: <span class="hljs-number">100px</span>;
            <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#3498db</span>;
            <span class="hljs-attribute">animation</span>: pulse <span class="hljs-number">2s</span> ease-in-out infinite;
        }
</code></pre>
<p>Result:</p>
<p>&lt;!DOCTYPE html&gt;</p>


    
    
    Pulse Animation
    


    <div class="element"></div>




<p>In this example:</p>
<ul>
<li>We define a <code>@keyframes</code> rule named "pulse" that specifies three keyframes at 0%, 50%, and 100% of the animation duration. It uses the <code>transform</code> property to scale the element.</li>
<li>The <code>.element</code> CSS class sets the initial background color, and it applies the "pulse" animation with a 2-second duration, "ease-in-out" timing function, and the "infinite" value, which means the animation will loop indefinitely.</li>
<li>Inside the <code>&lt;body&gt;</code>, there's a <code>&lt;div&gt;</code> element with the class "element" that will undergo the "pulse" animation when the page loads.</li>
</ul>
<p>When you open this HTML file in a web browser, the element will pulse or "breathe" by smoothly scaling up and down in size, creating a simple but eye-catching animation.</p>
<h3 id="heading-other-css-animation-techniques">Other CSS Animation Techniques:</h3>
<p>There are other CSS animation techniques, including:</p>
<ul>
<li><strong>Transformations:</strong> CSS can be used to perform 2D and 3D transformations like scaling, rotating, and translating elements.</li>
<li><strong>Keyframes:</strong> As shown in the above example, keyframes allow you to create more complex animations by specifying multiple steps or keyframes in an animation sequence.</li>
<li><strong>Other types of CSS Transitions:</strong> Besides property-based transitions, you can also use transitions for multiple properties, allowing you to create more intricate animations.</li>
</ul>
<h3 id="heading-advantages-of-css-animations">Advantages of CSS Animations</h3>
<ul>
<li><strong>Easy to Use</strong>: CSS animations are relatively simple to implement, especially for basic animations like transitions and fades.</li>
<li><strong>Performance</strong>: They are hardware-accelerated and generally perform well, providing a smooth user experience.</li>
<li><strong>Responsive Design</strong>: CSS animations are inherently responsive and adapt to different screen sizes and devices.</li>
<li><strong>Low JavaScript Overhead</strong>: Using CSS for animations can reduce the load on JavaScript, making your web application more efficient.</li>
<li><strong>Browser Compatibility</strong>: CSS animations are widely supported in modern browsers. But it's important to note that there can be compatibility issues with older versions of Internet Explorer (IE) and some mobile browsers. In such cases, it may be necessary to provide graceful degradation or alternative designs for users on older browsers.</li>
</ul>
<h2 id="heading-javascript-animations">JavaScript Animations</h2>
<p>JavaScript is a versatile programming language used for a wide range of tasks, including creating complex animations. JavaScript animations are typically more flexible and capable of handling intricate, data-driven animations.</p>
<h3 id="heading-js-animations-using-the-requestanimationframe-method">JS Animations using the <code>requestAnimationFrame</code> method</h3>
<pre><code class="lang-javascript">     <span class="hljs-keyword">const</span> box = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'animated-box'</span>);
        <span class="hljs-keyword">let</span> isAnimating = <span class="hljs-literal">false</span>;

        box.addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function">() =&gt;</span> {
            <span class="hljs-keyword">if</span> (!isAnimating) {
                isAnimating = <span class="hljs-literal">true</span>;
                box.style.transform = <span class="hljs-string">'translateX(200px)'</span>;

                <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
                    isAnimating = <span class="hljs-literal">false</span>;
                    box.style.transform = <span class="hljs-string">'translateX(0)'</span>;
                }, <span class="hljs-number">1000</span>);
            }
        });
</code></pre>
<p>Result:</p>
<p>&lt;!DOCTYPE html&gt;</p>


    


    <div id="animated-box">Click Me</div>

    




<p>In the JavaScript animation example, the <code>requestAnimationFrame</code> method is used to create a simple animation where a box moves horizontally when clicked. This method is often used for smoother, more complex animations.</p>
<p>In this example,</p>
<ul>
<li>We use <code>document.getElementById('animated-box')</code> to select the HTML element with the ID "animated-box" and assign it to the <code>box</code> variable.</li>
<li>We also declare a boolean variable <code>isAnimating</code> to keep track of whether an animation is currently in progress.</li>
<li>We add an event listener to the <code>box</code> element that listens for a click event.</li>
<li>When the box is clicked, the event listener triggers an anonymous function that checks if an animation is already in progress (<code>isAnimating</code>). If not, it sets <code>isAnimating</code> to <code>true</code>.</li>
<li>It then changes the <code>transform</code> property of the box to <code>translateX(200px)</code>. This shifts the box 200 pixels to the right, creating a horizontal animation effect.</li>
<li>After a 1-second delay (specified by <code>setTimeout</code>), it sets <code>isAnimating</code> back to <code>false</code> and resets the <code>transform</code> property to its original state (<code>translateX(0)</code>), moving the box back to its initial position.</li>
</ul>
<p>This code creates a simple animation where clicking the box moves it horizontally to the right and then back to its original position, all within the duration of 1 second. The CSS <code>transition</code> property ensures that the movement is smooth and visually appealing.</p>
<h3 id="heading-other-common-javascript-animation-methods">Other common JavaScript animation methods</h3>
<ul>
<li><strong>jQuery:</strong> jQuery is a popular JavaScript library that simplifies animation tasks, making it easier to create animations with less code.</li>
<li><strong>GreenSock Animation Platform (GSAP):</strong> GSAP is a robust animation library for JavaScript that provides advanced animation capabilities and precise control over animations.</li>
<li><strong>Canvas Animation:</strong> HTML5 canvas can be used to create custom animations, especially for games and visualizations.</li>
<li><strong>Web Animation API:</strong> This native browser API provides a JavaScript interface for controlling animations on web pages, allowing for greater control over animations compared to CSS.</li>
<li><strong>SVG Animations:</strong> You can create complex animations within Scalable Vector Graphics (SVG) using JavaScript to manipulate SVG elements.</li>
</ul>
<h3 id="heading-advantages-of-javascript-animations">Advantages of JavaScript Animations</h3>
<ul>
<li><strong>Complex Animations</strong>: JavaScript offers greater flexibility, making it suitable for complex animations with dynamic behavior.</li>
<li><strong>Interactivity</strong>: You can easily add user interactions, such as drag-and-drop functionality, through JavaScript animations.</li>
<li><strong>Data-Driven Animations</strong>: JavaScript allows you to create animations based on data, making it ideal for visualizing dynamic content.</li>
<li><strong>Real-Time Updates</strong>: JavaScript animations can be used for real-time updates and synchronized animations with other parts of the web application.</li>
<li><strong>Performance Implications</strong>: JavaScript animations can sometimes be resource-intensive, especially on mobile devices or less powerful hardware. Developers should be cautious when implementing complex JavaScript animations on these platforms to ensure a smooth user experience.</li>
</ul>
<h2 id="heading-when-to-use-css-vs-javascript-for-animations">When to Use CSS vs JavaScript for Animations</h2>
<h3 id="heading-when-to-use-css-for-animations">When to Use CSS for Animations:</h3>
<p>CSS if often the best choice for basic animations like hover effects, transitions, and small, non-interactive animations.</p>
<p>CSS animations are generally smoother and more efficient, making them ideal for performance-critical scenarios.</p>
<p>And when you're designing responsive websites, CSS animations adapt to different screen sizes seamlessly.</p>
<h3 id="heading-when-to-use-javascript-for-animations">When to Use JavaScript for Animations:</h3>
<p>On the other hand, when you need to create intricate animations with dynamic elements, JavaScript provides the necessary flexibility and control.</p>
<p>Also, if your animations need to respond to user interactions, JavaScript animations should be your go-to option.</p>
<p>JavaScript is also essential for creating interactive charts and graphs for data-driven animations.</p>
<p>And finally, when you require real-time updates or synchronized animations, JavaScript is the best choice for dynamic content.</p>
<h2 id="heading-how-to-combine-css-and-javascript-animations">How to Combine CSS and JavaScript Animations</h2>
<p>In some scenarios, a hybrid approach using both CSS and JavaScript animations can offer the best of both worlds. </p>
<p>For instance, you might use CSS for initial animations and transitions that occur when a page loads and then employ JavaScript for user interactions, real-time updates, or data-driven animations. This combination can provide the efficiency and performance benefits of CSS with the interactivity and dynamic capabilities of JavaScript. </p>
<p>Check out the following Codepen for an example: </p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/joanayebola/embed/wvRLKbQ" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Web animations are a crucial element of modern web development, enhancing user experience and engagement. </p>
<p>The choice between CSS and JavaScript for animations depends on the complexity of your project, the level of interactivity required, and your performance needs. </p>
<p>For simple and performance-critical animations, CSS is often the best choice, while JavaScript is the go-to option for complex, interactive, and data-driven animations.</p>
<p>Remember that in many cases, a combination of both CSS and JavaScript can be the most effective approach. By understanding the strengths of each technique and when to apply them, you can create web animations that captivate your audience and elevate your web development projects.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Stunning Animations with the Vue.js Transition API ]]>
                </title>
                <description>
                    <![CDATA[ I’m easily gripped by animations and purposeful motion on the Web – so much so that I wrote a whole article on it.  I’m also a big fan of the Vue.js framework, and I’ve been building apps with it for three years. So it was a delightful surprise when ]]>
                </description>
                <link>https://www.freecodecamp.org/news/animations-with-vuejs-transition-api/</link>
                <guid isPermaLink="false">66bc54a3e35f27b35395073b</guid>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Vue.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Felix Favour Chinemerem ]]>
                </dc:creator>
                <pubDate>Tue, 10 Oct 2023 15:28:04 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/10/supercharged-animations.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>I’m easily gripped by animations and purposeful motion on the Web – so much so that I wrote a <a target="_blank" href="https://favourfelix.com/stories/css-and-motion-build-animations-on-the-web/">whole article</a> on it. </p>
<p>I’m also a big fan of the Vue.js framework, and I’ve been building apps with it for three years.</p>
<p>So it was a delightful surprise when I realized that I could use <strong>only</strong> the Transition API in Vue.js while leveraging my decent CSS skills to animate a component’s enter and exit animations in such a fluid manner.</p>
<p>How fluid, you might ask? Let me show you:</p>
<div class="embed-wrapper">
        <iframe width="640" height="360" src="https://player.vimeo.com/video/872452747" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="Vimeo embed" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen="" loading="lazy"></iframe></div>
<p>In this article, we'll build a straightforward movie app with built-in filtering features. By the end, you should have a solid understanding of the <code>&lt;Transition&gt;</code> and <code>&lt;TransitionGroup&gt;</code> built-in components in Vue.js and how they seamlessly handle enter and exit animations within Vue.js.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Hold on! We need a few tools in our toolkit before we dive into this adventure. This article is designed to be a breeze for beginners, but to ensure a smooth ride, here's what you'll need:</p>
<ul>
<li>A basic understanding of HTML, CSS, and Javascript.</li>
<li>A <a target="_blank" href="https://www.freecodecamp.org/news/css-transition-vs-css-animation-handbook/">basic understanding of Transitions and Animations in CSS</a>.</li>
<li>A <a target="_blank" href="https://www.freecodecamp.org/news/vue-3-full-course/">basic knowledge of the Vue.js framework</a>.</li>
<li>You can also access the bare movie app without the transitions <a target="_blank" href="https://github.com/felixfavour/supercharged-animations-vue">here</a>, but only if you think it’s the boring part ;)</li>
<li>Last but not least, some good background music—I’ll let you choose this one yourself, <a target="_blank" href="https://coderadio.freecodecamp.org/">but there's always freeCodeCamp radio</a>.</li>
</ul>
<p>Ok, now we're ready to get started.</p>
<h2 id="heading-what-is-the-transition-api">What is the Transition API?</h2>
<p>The Transition API primarily consists of the built-in <code>&lt;Transition&gt;</code> and  <code>&lt;TransitionGroup&gt;</code> components in Vue.</p>
<p>The <code>&lt;Transition&gt;</code> component is used for animating single elements or components. In contrast, the <code>&lt;TransitionGroup&gt;</code> is used for animating multiple elements in a list in conjunction with the v-for directive in Vue.</p>
<h3 id="heading-how-to-add-animations-with-the-component">How to Add Animations with the <code>&lt;Transition&gt;</code> Component</h3>
<p>The <code>&lt;Transition&gt;</code> component is a built-in component that is typically wrapped around any root element or component for animation benefits. The animations are triggered when the inner element or component is shown or hidden using common Vue directives like v-show or v-if.</p>
<p>This component is "built-in" because it does not need to be imported into the template to be functional. It's recognized by the Vue template compiler.</p>
<p>We can try this out by adding a v-show to our <code>.header-filters</code> container first and wrapping the container in the <code>&lt;Transition&gt;</code> component like below:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">Transition</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-show</span>=<span class="hljs-string">"filtersVisible"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header-filters"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"search"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"searchQuery"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search Movies"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"button-group"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"query = ''"</span> <span class="hljs-attr">:class</span>=<span class="hljs-string">"{ active: query === '' }"</span>&gt;</span>Clear Filters<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"query = '2021'"</span> <span class="hljs-attr">:class</span>=<span class="hljs-string">"{ active: query === '2021' }"</span>&gt;</span>2021<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"query = 'Action'"</span> <span class="hljs-attr">:class</span>=<span class="hljs-string">"{ active: query === 'Action' }"</span>&gt;</span>Action<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">Transition</span>&gt;</span>
</code></pre>
<p>We can then wrap up the animation by including styling specifications for the enter and exit animations. If you are familiar with CSS Animations and Transitions, the mode of operation is pretty similar. If you are not, here is a <a target="_blank" href="https://favourfelix.com/stories/css-and-motion-build-animations-on-the-web/">quick crash course</a>.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.v-move</span>,
<span class="hljs-selector-class">.v-enter-active</span>,
<span class="hljs-selector-class">.v-leave-active</span> {
  <span class="hljs-attribute">transition</span>: <span class="hljs-number">0.3s</span> ease;
}

<span class="hljs-selector-class">.v-enter-from</span>,
<span class="hljs-selector-class">.v-leave-to</span> {
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateY</span>(<span class="hljs-number">10px</span>);
}
</code></pre>
<p>And now, you should have your fluid animations for single root elements with the <code>&lt;Transition&gt;</code> component. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/ezgif.com-video-to-gif--1-.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Illustration of the effect of the Transition component when an element is hidden and shown.</em></p>
<p>What if you want something similar to the video that I shared earlier? Something more mesmerizing? Well, let’s see the <code>&lt;TransitionGroup&gt;</code> component.</p>
<h3 id="heading-how-to-add-list-animations-with-the-component">How to Add List Animations with the <code>&lt;TransitionGroup&gt;</code> Component</h3>
<p>The <code>&lt;TransitionGroup&gt;</code> component is wrapped around a list to animate the insertion, removal, and change of order of the items that are rendered in this list. This list is typically created with the v-for directive.</p>
<p>Unlike the <code>&lt;Transition&gt;</code> component, the elements or components wrapped in the <code>&lt;TransitionGroup&gt;</code> component must have unique key attributes.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">TransitionGroup</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">MovieCard</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"movie in filteredMovies"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"movie.title"</span> <span class="hljs-attr">:movie</span>=<span class="hljs-string">"movie"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">TransitionGroup</span>&gt;</span>
</code></pre>
<p>Aside from the instructions above, the <code>&lt;TransitionGroup&gt;</code> component has a similar mode of integration and operation as the <code>&lt;Transition&gt;</code> component.</p>
<h2 id="heading-how-to-identify-and-name-transitions">How to Identify and Name Transitions</h2>
<p>A common problem when using <code>&lt;Transition&gt;</code> and <code>&lt;TransitionGroup&gt;</code> components is having multiple instances of these components in your app and using different enter and exit transitions for specific instances. This is why we name <code>&lt;Transition&gt;</code> and <code>&lt;TransitionGroup&gt;</code> components.</p>
<p>The <code>&lt;Transition&gt;</code> and <code>&lt;TransitionGroup&gt;</code> components accept a <code>name</code> prop that helps to identify and group transitions.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">TransitionGroup</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"list"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">MovieCard</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"movie in filteredMovies"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"movie.title"</span> <span class="hljs-attr">:movie</span>=<span class="hljs-string">"movie"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">TransitionGroup</span>&gt;</span>
</code></pre>
<p>The <code>name</code> prop also determines the class name for styling enter and exit transitions like below:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.list-move</span>,
<span class="hljs-selector-class">.list-enter-active</span>,
<span class="hljs-selector-class">.list-leave-active</span> {
  <span class="hljs-attribute">transition</span>: <span class="hljs-number">0.3s</span> ease;
}

<span class="hljs-selector-class">.list-enter-from</span>,
<span class="hljs-selector-class">.list-leave-to</span> {
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateY</span>(<span class="hljs-number">10px</span>);
}
</code></pre>
<p>Notice that the <code>name</code> prop passed in the <code>&lt;TransitionGroup&gt;</code> code above is “list”, and it is used as a prefix in the styles for enter and exit transitions in the CSS code above.</p>
<h2 id="heading-how-to-customize-enter-and-exit-animations-with-css">How to Customize Enter and Exit Animations With CSS</h2>
<p>In this article, we used the CSS <code>transition</code> property to help with subtle enter and exit animations. But the <code>&lt;Transition&gt;</code> and <code>&lt;TransitionGroup&gt;</code> components also support the <code>animation</code> property in CSS for much more complex animations with multiple keyframes.</p>
<p>Here is an example of how we can use the <code>animation</code> property in our <code>&lt;Transition&gt;</code> component:</p>
<h3 id="heading-template">Template</h3>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">Transition</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"bounce"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-show</span>=<span class="hljs-string">"filtersVisible"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header-filters"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"search"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"searchQuery"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search Movies"</span>&gt;</span>
    . . .
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">Transition</span>&gt;</span>
</code></pre>
<h3 id="heading-styles">Styles</h3>
<pre><code class="lang-css"><span class="hljs-selector-class">.bounce-enter-active</span> {
  <span class="hljs-attribute">animation</span>: bounce-in <span class="hljs-number">0.5s</span>;
}
<span class="hljs-selector-class">.bounce-leave-active</span> {
  <span class="hljs-attribute">animation</span>: bounce-in <span class="hljs-number">0.5s</span> reverse;
}
<span class="hljs-keyword">@keyframes</span> bounce-in {
  0% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">0</span>);
  }
  50% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1.25</span>);
  }
  100% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1</span>);
  }
}
</code></pre>
<p>If the concept of keyframes or the animation property in CSS does not make much sense to you, feel free to <a target="_blank" href="https://favourfelix.com/stories/css-and-motion-build-animations-on-the-web/">get a quick introduction to animations in CSS</a>.</p>
<h2 id="heading-purposeful-motion-on-the-web">Purposeful Motion on the Web</h2>
<p>In any discussion about web animations and transitions, it's crucial to address the "why" behind them. Why should we include motion on the web, and is it genuinely indispensable?</p>
<p>Motion on the web serves a purpose that extends far beyond mere aesthetics. It's a powerful tool for conveying messages to your users. Whether it's to elevate your storytelling, provide user feedback, or captivate their attention, animations can play a pivotal role in enhancing your users' experience.</p>
<p>Gone are the days when animations were added merely for decorative purposes. In the modern web landscape, every keyframe should be thoughtfully designed with a clear purpose, and the user should always be at the heart of your design decisions.</p>
<p>That being said, make sure not to overuse animations – as too many moving parts can be distracting and actually detract from the user experience. It's all about balance.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Phew, that was an exciting ride! I hope you enjoyed it. This article shared a lot, and I'm excited to see how you use that information. I would love to know if you built something cool while reading.</p>
<p>Also feel free to look into the official Vue <a target="_blank" href="https://vuejs.org/guide/built-ins/transition.html">documentation</a> to see what else is possible with the Transition API.</p>
<p>Finally, have fun creating delightful experiences with animation, but always remember CSS animations are only useful to your users when they are purposeful. If you found this article helpful, feel free to connect on <a target="_blank" href="http://favourfelix.com/">favourfelix.com</a> to see what else I'm up to.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Implement a Blender Model in a React.js Application using Three.js ]]>
                </title>
                <description>
                    <![CDATA[ In this step-by-step guide, you'll learn how to build a basic Blender file with incorporated fundamental animations. After that, you'll learn how to integrate Three.js with your React apps using React Three Fiber.  Getting familiar with these concept... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/blender-three-js-react-js/</link>
                <guid isPermaLink="false">66bb8f3cdeef71ff683a6d2a</guid>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ three.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Matthes B. ]]>
                </dc:creator>
                <pubDate>Thu, 17 Aug 2023 14:58:49 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/pexels-chevanon-photography-1335971.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this step-by-step guide, you'll learn how to build a basic Blender file with incorporated fundamental animations. After that, you'll learn how to integrate Three.js with your React apps using React Three Fiber. </p>
<p>Getting familiar with these concepts can help you make sure your upcoming React.js applications stand out.</p>
<h2 id="heading-heres-what-well-cover"><strong>🔐</strong> Here's What We'll Cover:</h2>
<ul>
<li>Crafting a Blender model, encompassing animations, materials and the export process.</li>
<li>Building a React.js application integrated with Three.js via React Three Fiber.</li>
<li>Incorporating your personally created Blender model into the React.js application.</li>
</ul>
<h2 id="heading-prerequisites"><strong>📝</strong> Prerequisites:</h2>
<ul>
<li>A fundamental grasp of the 3D software Blender is recommended.</li>
<li>Basic familiarity with React.js is required.</li>
<li>Prior experience with Three.js is not necessary.</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-are-threejs-and-blender">💭 What are Three.js and Blender?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-reactjs-with-threejs">🔧 How to Set Up React.js with Three.js</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-blender-model"><strong>🔨</strong> How to Create a Blender Model</a></li>
<li><a class="post-section-overview" href="#heading-texture-baking-for-procedural-materials"><strong>✏️</strong> Texture Baking for Procedural Materials</a></li>
<li><a class="post-section-overview" href="#-how-to-implement-the-blender-model-into-the-react-js-application"><strong>✒️</strong> How to Implement the Blender Model into the React.js Application</a></li>
<li><a class="post-section-overview" href="#heading-additional-information"><strong>📄</strong> Additional information</a></li>
<li><a class="post-section-overview" href="#heading-wrap-up"><strong>📋</strong> Wrap-up</a></li>
</ol>
<h2 id="heading-what-are-threejs-and-blender">💭 What are Three.js and Blender?</h2>
<p>Three.js is a JavaScript library that functionas as an API, allowing you to exhibit 3D models within web browsers. </p>
<p>Leveraging Three.js helps you seamlessly integrate interactivity and distinctive functionalities into your website. </p>
<p>Blender is a robust software tailored for crafting and refining 3D models. Its versatility offers boundless opportunities, catering to a wide spectrum of creative visions.</p>
<p>Beyond its display capabilities, Blender provides you with an array of tools encompassing cameras, lighting, and even post-production enhancements.</p>
<p>When used together, these tools facilitate boundless creativity, allowing you to seamlessly translate your artistic creations into your upcoming website project.</p>
<h2 id="heading-how-to-set-up-reactjs-with-threejs">🔧 How to Set Up React.js with Three.js</h2>
<p>To start the process, install the React.js application:</p>
<p><code>npx create-react-app my-app</code></p>
<p>Next, we'll install Three.js and <a target="_blank" href="https://docs.pmnd.rs/react-three-fiber/getting-started/installation">React Three Fiber</a>. React Three Fiber serves as a React renderer for Three.js, harnessing the power of React components to streamline Three.js integration within a React.js environment:</p>
<p><code>npm install three @react-three/fiber</code></p>
<p>For an enriched Three.js experience, we'll also integrate <a target="_blank" href="https://www.npmjs.com/package/@react-three/drei">React Three Drei</a>, a package that introduces an assortment of helpers for diverse Three.js scenarios, including several camera controls, for example:</p>
<p><code>npm install @react-three/drei</code></p>
<h3 id="heading-gltf-tools-extension">glTF Tools extension</h3>
<p>I also recommend installing the <strong>glTF Tools</strong> extension. Although not strictly necessary, this extension can help you perform various tasks. </p>
<p>If you're using Visual Studio Code as your Integrated Development Environment (IDE), you can conveniently add the extension through the extensions tab. Again, this extension is optional, but it can significantly simplify certain processes later on. I will use it throughout this tutorial:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/React1.0.PNG" alt="Image" width="600" height="400" loading="lazy">
<em><strong>gltf Tools</strong> extension in Visual Studio Code</em></p>
<h3 id="heading-completed-setup-for-threejs-in-reactjs">Completed setup for Three.js in React.js</h3>
<p>The dependencies in the <code>package.json</code> file of our React.js application now appear as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-string">"dependencies"</span>: {
    <span class="hljs-string">"@react-three/drei"</span>: <span class="hljs-string">"^9.80.2"</span>,
    <span class="hljs-string">"@react-three/fiber"</span>: <span class="hljs-string">"^8.13.6"</span>,
    <span class="hljs-string">"@testing-library/jest-dom"</span>: <span class="hljs-string">"^5.17.0"</span>,
    <span class="hljs-string">"@testing-library/react"</span>: <span class="hljs-string">"^13.4.0"</span>,
    <span class="hljs-string">"@testing-library/user-event"</span>: <span class="hljs-string">"^13.5.0"</span>,
    <span class="hljs-string">"react"</span>: <span class="hljs-string">"^18.2.0"</span>,
    <span class="hljs-string">"react-dom"</span>: <span class="hljs-string">"^18.2.0"</span>,
    <span class="hljs-string">"react-scripts"</span>: <span class="hljs-string">"5.0.1"</span>,
    <span class="hljs-string">"three"</span>: <span class="hljs-string">"^0.155.0"</span>,
    <span class="hljs-string">"web-vitals"</span>: <span class="hljs-string">"^2.1.4"</span>
  },
</code></pre>
<p>These dependencies are sufficient for accomplishing a variety of tasks with Three.js in a React.js environment. Of course, you can incorporate any additional libraries you may desire for purposes beyond Three.js integration.</p>
<p>In addition to this, I have also made the code from this tutorial available on <a target="_blank" href="https://github.com/Matthes-Baer/blender-threejs-reactjs-article-app">GitHub</a>. This will allow you to quickly access the information without having to scroll through the entire article.</p>
<h2 id="heading-how-to-create-a-blender-model">🔨 How to Create a Blender Model</h2>
<p>To begin, our initial task involves creating a Blender model that will then be integrated into our React.js application. For this stage, let's consider a scene in the <strong>Layout</strong> tab where we've got three objects: two spheres and one plane. You can add such objects with the <code>Shift + A</code> shortcut in Blender.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blenderFirstImage.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Blender scene with two spheres and one plane in the <strong>Layout</strong> tab</em></p>
<p>This composition includes just a plane and two spheres, with no additional details. Of course, you can work on more elaborate scene and model designs according to your preferences. </p>
<p>But for the purpose of illustrating the fundamental process of incorporating your custom Blender models into React.js, this basic example will serve us just fine.</p>
<h3 id="heading-how-to-add-animations-to-the-model">How to add animations to the model</h3>
<p>Now, our focus shifts to introducing basic animations to all three objects within this Blender scene. These animations can facilitate movement, rotation, or even adjustments in scale for the objects, enabling dynamic transformations.</p>
<p>In order to add animations in Blender for your objects, you can switch to the <strong>Animation</strong> tab, next to the <strong>Shading</strong> and <strong>Rendering</strong> tab.</p>
<p>In the Animation tab, you can add points to a certain frame. For instance, if you want to shift a sphere a bit to the left, begin by adding a starting keyframe (right-click on the object, choose "Insert Keyframe," then pick "Location"). </p>
<p>Afterward, move ahead a few frames on the object's animation timeline, adjust the object's position, and repeat the same process. This way, you'll have two keyframes: the initial one and the new position.</p>
<p>Remember, this motion is in one direction. If you want to repeat the animation, it will move to the new location and then return to its initial position with a jump. </p>
<p>To make the movement smoother, you can copy the initial keyframe and insert it at the end. This will make the object move back with a smooth motion after reaching the new location. This is also how I set up the keyframes in our Blender model.</p>
<p>Of course, you can add more keyframes to make more complex animations. This is just a basic introduction to starting with Blender animations. Like many aspects of Blender, there's a lot more to explore and learn.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blenderSecondImage.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Adding animations to all three objects in the <strong>Animation</strong> tab</em></p>
<p>In this context, it's not necessary to have a thorough understanding of the specifics of these animations we added here. So, you don't really need to know to which exact position the first sphere is being moved through the animation. </p>
<p>The key point is to acknowledge their presence, as they will be integrated into our React.js application at a later stage so we can activate them in the browser.</p>
<h3 id="heading-how-to-add-colors">How to add colors</h3>
<p>Moving forward, we'll add some simple colors for the small sphere and the underlying plane, which you can do within the <strong>Shading</strong> tab, for example.</p>
<p>For basic colors, you can also go to the <strong>Material Properties</strong> section of the object (right-click on the object, then choose the second-to-last category at the bottom). But I want to focus on a specific situation you might encounter with your models later on. Therefore, I'll exclusively use the <strong>Shading</strong> tab for setting object colors in this tutorial.</p>
<p>In the <strong>Shading</strong> tab, you can add nodes at the bottom of the screen. These nodes can modify the color and texture of an object, among other things. You'll also find <code>Vector</code> and <code>Shader</code> nodes that, when combined, can create unique visuals for your objects. </p>
<p>All these adjustments apply to a specific material. So, if you want the same visual for different objects, you can simply apply the same material to them.</p>
<p>The <code>Principled BSDF</code> and <code>Material Output</code> nodes are initially generated when we open the <strong>Shading</strong> tab to look up on of our object's material for the first time. Both nodes are pretty much the basic case. </p>
<p>The <code>Principled BSDF</code> has a lot of settings you can play around with. In our case we just want to change the <code>Base Color</code> property to a blue color.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender3.0.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Material of one sphere where we just adjust the <code>Base Color</code> within the <code>Principled BSDF</code> node</em></p>
<p>For the larger sphere, a similar material application is used. But, in contrast to the <code>Principled BSDF</code> node, we'll use the <code>Glossy BSDF</code> node which is such a node from the <code>Shader</code> category. This will help us recognize a possible issue that you might come across when designing a Blender model for your React.js application – which you will see later on.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender3.2-1.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Using the <code>Glossy BSDF</code> node to add a material to the large sphere</em></p>
<p>Once we've done this, we're ready to export our Blender model. Note that this version is considerably simplified. You can work on more detailed model designs tailored to your preferences. Still, the overall workflow remains similar.</p>
<h3 id="heading-how-to-export-the-model">How to export the model</h3>
<p>To export the model, we need to generate a <code>.glb/.gltf</code> file. This is crucial as Three.js expects particular file formats for compatibility, and in this instance, a <code>.glb</code> or <code>.gltf</code> file aligns with the library's requirements.</p>
<p>So, once you've finished creating your model with objects, animations, colors, and more, you can do the following:</p>
<ol>
<li>Click on the <strong>File</strong> tab located at the top left corner.</li>
<li>Choose <strong>Export</strong> from the options that appear. Now, a variety of export formats will be shown.</li>
<li>If you plan to use your model with Three.js in your application, you need to pick the <code>glTF 2.0 (.glb/.gltf)</code> option, like I mentioned earlier.</li>
</ol>
<p>After selecting this option, a new window will pop up. This window lets you pick the folder where you want to save your file. </p>
<p>On the right side of this window, there are additional choices. You can decide which specific objects you want to export, for instance. In most situations, the default settings should work well. Just remember that you can adjust these settings to your liking if necessary.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender3.1-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Remember to export with the <code>glTF 2.0 (.glb/.gltf)</code> format.</em></p>
<h3 id="heading-how-to-visualize-the-exported-model">How to visualize the exported model</h3>
<p>Next, let's transition to Visual Studio Code and navigate to the folder where we've stored our exported file. </p>
<p>Within this directory, you'll find a <code>.glb</code> file. Referring back to the <strong>glTF Tools</strong> extension setup from earlier, you can simply right-click on the <code>.glb</code> file in order to find two additional options positioned at the bottom, called <code>glTF: Import from GLB</code> and <code>glTF: Validate a GLB or GLTF file</code>.</p>
<p>In this scenario, we'll opt for the <code>glTF: Import from GLB</code> option. This action will generate a <code>.gltf</code> file in the same folder, in our case <code>blenderFile.gltf</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender4.0.png" alt="Image" width="600" height="400" loading="lazy">
<em>Generating a <code>.gltf</code> file from the original <code>.glb</code> file we exported in Blender with the <strong>glTF Tools</strong> extension</em></p>
<p>We've chosen this approach to bring enhanced accessibility to the <code>.gltf</code> file, enabling direct viewing within Visual Studio Code through the <strong>glTF Tools</strong> extension. This can be quite helpful to check on your file prior to its actual implementation.</p>
<p>If we access the newly created <code>.gltf</code> file, we can observe a bunch of information based on the Blender model. It's important to note that the specifics could differ in your case, as they're tailored to reflect the attributes of the objects and scenes within your Blender project.</p>
<p>If we look at the upper-right corner, there is a symbol that looks like a cube with a cone next to it. By clicking on this symbol, you can seamlessly preview your Blender scene directly within your IDE. This functionality is exclusively accessible for the <code>.gltf</code> file and not applicable to the <code>.glb</code> file in this case.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender4.5.png" alt="Image" width="600" height="400" loading="lazy">
<em>The newly created <code>.gltf</code> file with the option to view the model directly in Visual Studio Code (in the upper-right corner, circled in red)</em></p>
<p>It's worth noting that you don't have to do this through the <strong>glTF Tools</strong> extension. Alternatively, various websites allow you to upload your file for visualization. But I've personally found this in-IDE approach to be especially convenient. It centralizes the process, enabling you to assess your file's integrity before actually implementing it. </p>
<p>If you find any errors, this practice lets you preemptively find out whether the issue is based on a problematic file export or just an implementation oversight within your React.js application. Consequently, I wholeheartedly recommend evaluating your model file following its export from Blender.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender5.0.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Viewing the Blender model with <strong>glTF Tools</strong> in Visual Studio Code</em></p>
<p>By using the <strong>glTF Tools</strong> extension to view our Blender model in Visual Studio Code, we can see that all three objects are correctly recognized. Both the small sphere and the plane are shown in their intended colors.</p>
<p>But the large sphere doesn't have the expected color assigned and just appears with a default white color instead. </p>
<p>This discrepancy raises the question: what led to this anomaly? It's circumstances like this that demonstrate how useful it is to preview your model before integrating it into your React.js application.</p>
<p>By scrutinizing your model at this stage, you can affirm that the issue originates from the Blender model itself rather than the implementation process, given that we haven't done any implementation yet. </p>
<p>This pre-implementation assessment proves to be handy and enables you to diagnose and address potential complications before proceeding with the implementation process in React.js.</p>
<h2 id="heading-texture-baking-for-procedural-materials">✏️ Texture Baking for Procedural Materials</h2>
<p>In a nutshell, Blender provides the flexibility to employ procedural nodes for your materials. While these nodes function seamlessly within Blender, they are not directly compatible with other game engines or software frameworks such as Three.js. </p>
<p>To learn more, consider watching the following video. In just 10 minutes, it demonstrates the process of texture baking, which effectively resolves the issue at hand. </p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/AioskAgcU2U" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Personally, when confronted with this challenge and initially uncertain about its nature, I found this video to be a valuable resource for gaining deeper insights into the subject matter.</p>
<p>In our specific scenario, while we might not encounter as complex a situation as seen in the video, we are still faced with the use of nodes that lack direct compatibility with various software tools.</p>
<p>Next, we'll briefly walk through the steps mentioned in the video. However, if you're interested in delving deeper into this process, I highly recommend watching the video.</p>
<h3 id="heading-how-to-create-an-image-texture-node">How to create an image texture node</h3>
<p>To start, in the <strong>Shading</strong> tab for the material containing the <code>Glossy BSDF</code> node, we'll introduce an <code>Image Texture</code> node and connect it to a new image (by click on <code>New</code>). </p>
<p>We'll leave the settings at their default values, which means a width and height of <code>1024px</code>. Using larger values would considerably extend the processing time we're going to face. Still, it's important to note that a larger texture can offer more detail and an overall improved appearance. </p>
<p>In our current situation, we're aiming for a quick process. But for more significant projects, visual quality might be crucial. In such cases, opting for a higher resolution could be desirable.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender6.0-1.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Creating an <code>Image Texture</code> node and assigning a new image to it with default settings</em></p>
<h3 id="heading-how-to-apply-the-smart-uv-project-process">How to apply the Smart UV Project process</h3>
<p>Next, we need to employ the <code>Smart UV Project</code> option located in the <strong>UV Editing</strong> tab. Essentially, this action unwraps the faces of the particular object onto a texture. </p>
<p>This process enables us to specify which parts of the texture should be colored and modified as soon as we are back in the <strong>Shading</strong> tab. To make this process effective, we must select all the faces of the large sphere.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender7.0.png" alt="Image" width="600" height="400" loading="lazy">
<em>Selecting all faces of the object in the <strong>UV Editing</strong> tab and applying <code>Smart UV Project</code> on it</em></p>
<p>Once we've finished this step and utilized the default settings for the <code>Smart UV Project</code> procedure, the image on the left —previously featuring a grid— will now display the shapes of the sphere we applied this process to. In our situation, it seems like the texture captured various angles of our sphere.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender8.0.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>The texture after <code>Smart UV Project</code></em></p>
<p>Depending on the specific object, you may need to fine-tune the settings presented after clicking the <code>Smart UV Project</code> button. If you encounter challenges with a particular object, the video I shared earlier can give you additional guidance on this aspect.</p>
<p>Generally, to mitigate issues, you should optimize your object layout during its creation phase. Avoiding the introduction of excessive edges in specific locations can prevent problems like clipping, for instance.</p>
<h3 id="heading-the-bake-process">The Bake process</h3>
<p>Now, let's return to the <strong>Shading</strong> tab, where we'll access the <code>Render Properties</code> on the right side (represented by the small screen or TV symbol). If not already selected, pick <code>Cycles</code> as your <code>Render Engine</code>. Then navigate to the <code>Bake</code> category, which is located below the <code>Performance</code> category.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender9.0-1.PNG" alt="Image" width="600" height="400" loading="lazy">
<em><code>Bake</code> option in the <strong>Shading</strong> tab within the <code>Render Properties</code></em></p>
<p>With the existing default settings, you can proceed by clicking the <code>Bake</code> button while ensuring that both the <code>Image Texture</code> node and the large sphere are selected. </p>
<p>Keep in mind that I integrated a <code>Sun</code> light into my scene, as this bake process takes the scene's lighting into account. Without sufficient lighting, the result might appear excessively dark.</p>
<p>After a period of processing (which might be more time-consuming if you've employed larger dimensions for the <code>Image Texture</code> node's image), the baking process will finish. This results in the texture being applied to the image from the <code>Image Texture</code>. Instead of obtaining the texture from the <code>Shader</code> node named <code>Glossy BSDF</code>, we now have access to it through a regular "normal" image texture.</p>
<p>Then we can establish a connection from the <code>Image Texture</code> node to the <code>Material Output</code> node, thereby successfully implementing our material. At this stage, there isn't a significant difference compared to the previous method where we had the <code>Principled BSDF</code> node connected to the <code>Surface</code> input of the <code>Material Output</code> node.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender10.0.PNG" alt="Image" width="600" height="400" loading="lazy">
<em><code>Image Texture</code> node with the "baked" texture is connected with the <code>Material Output</code> node instead of the <code>Glossy BSDF</code> node</em></p>
<h3 id="heading-how-to-see-the-final-result">How to see the final result</h3>
<p>Now, we can export the file again, repeat the same process from before in our IDE with <strong>glTF Tools</strong> and view the <code>.gltf</code> file with the extension. Upon examining the outcome, you might notice that it's not an exact match to the version we had using the <code>Glossy BSDF</code> node in Blender. This difference can be primarily attributed to the lighting conditions in the Blender scene.</p>
<p>Bear in mind that the approach I've outlined isn't the typical usage for the baking process, since in this case you could also just have picked a similar base color with the <code>Principled BSDF</code> node and would achieve pretty much the same solution, for example.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/blender11.0.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Finalized view with <strong>glTF Tools</strong>, including the "baked" texture for the large sphere</em></p>
<p>I introduced the baking process based on personal experience. There were instances where I encountered a scenario where materials appeared differently in Blender compared to when implemented them in a React.js application with Three.js. This situation prompted me to explore the concept of baking, which turned out to be a helpful solution.</p>
<p>To summarize, if you find yourself facing a scenario where your materials don't appear as expected in your React.js application with Three.js, considering the baking process and researching this topic can provide valuable insights. This can be particularly beneficial for people who are new to Blender.</p>
<h2 id="heading-how-to-implement-the-blender-model-in-the-reactjs-application">✒️ How to Implement the Blender model in the React.js Application</h2>
<p>To implement the Blender file, we can use a really useful shortcut (source: <a target="_blank" href="https://github.com/pmndrs/gltfjsx">https://github.com/pmndrs/gltfjsx</a>):</p>
<p><code>npx gltfjsx public/blenderFileName.glb</code></p>
<p>It's important to note that you need to store your Blender file within the <code>public</code> folder of your React.js application for this step. It's also worth highlighting that you need React Three Drei to use this helper. So in our case, we can directly use this shortcut without the need for any additional preparations.</p>
<p>Upon executing this shortcut, we are presented with the following file:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/*
Auto-generated by: https://github.com/pmndrs/gltfjsx
Command: npx gltfjsx@6.1.4 public/blenderStuff/blenderFile.glb
*/</span>

<span class="hljs-keyword">import</span> { useLayoutEffect, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useGLTF, useAnimations } <span class="hljs-keyword">from</span> <span class="hljs-string">"@react-three/drei"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Model</span>(<span class="hljs-params">props</span>) </span>{
  <span class="hljs-keyword">const</span> group = useRef();
  <span class="hljs-keyword">const</span> { nodes, materials, animations } = useGLTF(
    <span class="hljs-string">"./blenderStuff/blenderFile.glb"</span>
  );
  <span class="hljs-keyword">const</span> { actions } = useAnimations(animations, group);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">group</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{group}</span> {<span class="hljs-attr">...props</span>} <span class="hljs-attr">dispose</span>=<span class="hljs-string">{null}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">group</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Scene"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mesh</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"Cube"</span>
          <span class="hljs-attr">geometry</span>=<span class="hljs-string">{nodes.Cube.geometry}</span>
          <span class="hljs-attr">material</span>=<span class="hljs-string">{materials.Material}</span>
          <span class="hljs-attr">position</span>=<span class="hljs-string">{[-0.07,</span> <span class="hljs-attr">0.16</span>, <span class="hljs-attr">-0.27</span>]}
          <span class="hljs-attr">scale</span>=<span class="hljs-string">{[1,</span> <span class="hljs-attr">0.03</span>, <span class="hljs-attr">1</span>]}
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mesh</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"Sphere"</span>
          <span class="hljs-attr">geometry</span>=<span class="hljs-string">{nodes.Sphere.geometry}</span>
          <span class="hljs-attr">material</span>=<span class="hljs-string">{materials[</span>"<span class="hljs-attr">Material.002</span>"]}
          <span class="hljs-attr">position</span>=<span class="hljs-string">{[-0.62,</span> <span class="hljs-attr">0.43</span>, <span class="hljs-attr">-0.79</span>]}
          <span class="hljs-attr">rotation</span>=<span class="hljs-string">{[-0.01,</span> <span class="hljs-attr">0.11</span>, <span class="hljs-attr">-0.02</span>]}
          <span class="hljs-attr">scale</span>=<span class="hljs-string">{0.09}</span>
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">mesh</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"Sphere001"</span>
          <span class="hljs-attr">geometry</span>=<span class="hljs-string">{nodes.Sphere001.geometry}</span>
          <span class="hljs-attr">material</span>=<span class="hljs-string">{materials[</span>"<span class="hljs-attr">Material.001</span>"]}
          <span class="hljs-attr">position</span>=<span class="hljs-string">{[0.4,</span> <span class="hljs-attr">0.55</span>, <span class="hljs-attr">0.15</span>]}
          <span class="hljs-attr">scale</span>=<span class="hljs-string">{0.41}</span>
        /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">group</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">group</span>&gt;</span></span>
  );
}

useGLTF.preload(<span class="hljs-string">"./blenderStuff/blenderFile.glb"</span>);
</code></pre>
<p>At first glance, you can see that this process has added many elements, so we basically don't need to add much on our own.</p>
<p>An important aspect to configure is the path within the <code>useGLTF</code> hook. In my instance, the accurate path to incorporate is <code>./blenderStuff/blenderFile.glb</code> (this applies to <code>useGLTF.preload()</code> as well). This is because I created a sub-folder named <code>blenderStuff</code> within my <code>public</code> directory.</p>
<h3 id="heading-how-to-add-a-canvas-wrapper-and-other-components">How to add a Canvas wrapper and other components</h3>
<p>With this configuration in place, we're now ready to use the <code>Model</code> component. But to effectively integrate this <code>Model</code> component into our desired location, we need to make some adjustments in the parent component. </p>
<p>In my case, I've opted to implement it within the main <code>App.js</code> file. And I've assigned a height of <code>100vh</code> to the <code>App</code>'s CSS class to ensure the desired display.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;
<span class="hljs-keyword">import</span> { Model } <span class="hljs-keyword">from</span> <span class="hljs-string">"./BlenderFile"</span>;
<span class="hljs-keyword">import</span> { Canvas } <span class="hljs-keyword">from</span> <span class="hljs-string">"@react-three/fiber"</span>;
<span class="hljs-keyword">import</span> { OrbitControls } <span class="hljs-keyword">from</span> <span class="hljs-string">"@react-three/drei"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Canvas</span> <span class="hljs-attr">camera</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">fov:</span> <span class="hljs-attr">64</span>, <span class="hljs-attr">position:</span> [<span class="hljs-attr">-2</span>, <span class="hljs-attr">2</span>, <span class="hljs-attr">0</span>] }}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ambientLight</span> <span class="hljs-attr">intensity</span>=<span class="hljs-string">{5}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">OrbitControls</span> <span class="hljs-attr">enableZoom</span>=<span class="hljs-string">{true}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Model</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Canvas</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Generally speaking, you'll need a component to encapsulate all the Three.js related elements. Within the <code>Canvas</code> component, there's an opportunity to configure various settings. In my specific instance, I'm adjusting the initial camera position.</p>
<p>The light for the component plays a crucial role. In our case we made use of <code>ambientLight</code> which will add a light to the whole scene. Without adequate lighting, your scene might appear exceedingly dark or even entirely black despite the presence of object colors. You can also use additional light sources like the <code>spotLight</code> component.</p>
<p>The <code>OrbitControls</code> component, accessible from the Drei helper library, enhances your interactivity by enabling scrolling and rotation within the model right within the browser. This single line of code substantially improves user interactivity options.</p>
<p>Remember that your <code>Canvas</code> component can accommodate multiple models. You can also selectively apply components like <code>OrbitControls</code> to specific Blender models, thereby tailoring their behavior. </p>
<p>To do this, you'll need to build a parent component for each scene you want to make to be integrated within the <code>Canvas</code>. Within each new parent component, incorporate your Blender model component, along with any supplementary helper components you want to add. </p>
<p>This approach proves particularly advantageous when distinct models require different lighting or unique camera positions, for example.</p>
<h3 id="heading-how-to-implement-the-animations">How to implement the animations</h3>
<p>At this point, we've established a functional Three.js <code>Canvas</code> environment, featuring our Blender model. But it's important to remember that we've also introduced basic animations, which are not yet operational.</p>
<p>To tackle this, we can leverage the pre-implemented <code>useAnimations</code> hook.</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">const</span> { actions, names } = useAnimations(animations, group);

  useLayoutEffect(<span class="hljs-function">() =&gt;</span> {
    names.forEach(<span class="hljs-function">(<span class="hljs-params">animation</span>) =&gt;</span> {
      actions?.[animation]?.play();
    });
  }, [actions, names]);
</code></pre>
<p>By incorporating this implementation, all animations associated with this Blender model will start playing upon the rendering of the page. This behavior also includes an indefinite loop for each animation.</p>
<h2 id="heading-additional-information">📄 Additional Information</h2>
<p>While this tutorial primarily focused on integrating a Blender model into a React.js application using Three.js, there's a realm of untapped potential within Three.js that we didn't cover.</p>
<p>Although we didn't use it in this basic example, you can introduce Post Processing to your Three.js models within React.js. The <a target="_blank" href="https://www.npmjs.com/package/@react-three/postprocessing">React Three Postprocessing</a> library serves as a valuable tool in this regard. It lets you elevate your Three.js scenes with sophisticated effects like Bloom or Noise effects, which can add a more advanced dimension to your visualizations.</p>
<p>Also, when working on future Three.js projects, consider exploring the <a target="_blank" href="https://docs.pmnd.rs/react-three-fiber/tutorials/using-with-react-spring">React Spring</a> library which integrates well with React Three Fiber. React Spring provides the opportunity to incorporate custom animations within your Three.js scenes, on top of any animations directly integrated within Blender. </p>
<p>For instance, you could make a specific object within your scene get larger or smaller upon clicking it. As with other aspects of Three.js, this aspect might enhance interactivity and might be worth your time to get into.</p>
<p>By the way, if you find that your frames are running at a lower rate, consider toggling Hardware Acceleration within your browser settings to potentially improve performance.</p>
<h2 id="heading-wrap-up">📋 Wrap-up</h2>
<p>At this point, we've successfully crafted a Blender model with animations and materials. Afterwards we integrated it into our React.js application using React Three Fiber.</p>
<p>Although the example we looked at here was quite basic, the integration approach remains the same for more complex Blender models. The fundamental functions of Three.js can be combined with supplementary helpers to enhance your scenes. </p>
<p>In addition to Post Processing, additional animations or also specific Blender materials, aspects like cameras and lights often are the most important when aiming to enhance the visual impact of your Blender models within Three.js scenes.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create a Meteor Effect with React and TailwindCSS ]]>
                </title>
                <description>
                    <![CDATA[ By Manu Arora A while ago, I saw a post on Twitter that had some fancy beams of light emanating out from behind the main image. It looked like a meteor was blazing softly behind the card, and I thought it was a really cool UI component to have in ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-a-meteor-effect-with-react-and-tailwindcss/</link>
                <guid isPermaLink="false">66d4601b3a8352b6c5a2aaa8</guid>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tailwind ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 11 Aug 2023 16:14:27 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-11-at-9.20.20-PM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Manu Arora</p>
<p>A while ago, I saw a post on Twitter that had some fancy beams of light emanating out from behind the main image. It looked like a meteor was blazing softly behind the card, and I thought it was a really cool UI component to have in a project.</p>
<p>Looking at that, I thought of creating a React component of my own that would do the same job – that is, adding this meteor glowing effect to the background of a card.  </p>
<p>This would make the card stand out instantly and would be really useful if you wanted to highlight a specific card from your set of UI cards.</p>
<p>So that's what we're going to build in this tutorial.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>For creating this effect, we are going to use:</p>
<ul>
<li><strong>Next.js</strong> for our framework (because we are going to create a component)</li>
<li><strong>TailwindCSS</strong> for styling</li>
</ul>
<h2 id="heading-how-to-setup-the-project">How to Setup the Project</h2>
<p>To setup a project in Next.js and TailwindCSS, simply follow these steps:</p>
<p>First, head over to the terminal and enter the following command:</p>
<pre><code class="lang-bash">npx create-next-app@latest meteor-effect --typescript --eslint
</code></pre>
<p>Once you have <code>Next.js</code> installed, cd into the project like this:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> meteor-effect
</code></pre>
<p>Then install TailwindCSS like this:</p>
<pre><code class="lang-bash">npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
</code></pre>
<p>Setup the <code>tailwind.config.js</code> file so that Tailwind knows where to find your styles:</p>
<pre><code class="lang-js">tailwind.config.js

<span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('tailwindcss').Config}</span> </span>*/</span>
<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">content</span>: [
    <span class="hljs-string">"./app/**/*.{js,ts,jsx,tsx,mdx}"</span>,
    <span class="hljs-string">"./pages/**/*.{js,ts,jsx,tsx,mdx}"</span>,
    <span class="hljs-string">"./components/**/*.{js,ts,jsx,tsx,mdx}"</span>,

    <span class="hljs-comment">// Or if using `src` directory:</span>
    <span class="hljs-string">"./src/**/*.{js,ts,jsx,tsx,mdx}"</span>,
  ],
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {},
  },
  <span class="hljs-attr">plugins</span>: [],
}
</code></pre>
<p>Once you've setup the config file, add the base styles for Tailwind to the global stylesheet like this:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@tailwind</span> base;
<span class="hljs-keyword">@tailwind</span> components;
<span class="hljs-keyword">@tailwind</span> utilities;
</code></pre>
<p>With these steps, you should be good to go.</p>
<h2 id="heading-what-are-we-building">What Are We Building?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-11-at-9.20.20-PM-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>the cool lines at the background are meteors</em></p>
<p>A <strong>Meteor</strong> (as I call it, you can call it anything really) is basically a UI element with a head and a tail. It's a sort of beam which has a gradient.  </p>
<p>In the image, the background lines are what I call meteors. We are going to animate these lines to go from the left side of the card container to the right side, giving an illusion of a meteor shower.</p>
<p>We are going to build:</p>
<ul>
<li>A beautiful Card Component</li>
<li>A Meteor component to add to the card</li>
</ul>
<p>But before we build the core Meteor component, let's create the container that holds the meteors.</p>
<h2 id="heading-how-to-create-the-card-container">How to Create the Card Container</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-11-at-9.21.23-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>The card container we'll build here</em></p>
<p>Before we create the <code>Meteor</code> component, let's first create the Container that will hold down our meteors.</p>
<p>The Card Container has four parts to it:</p>
<ul>
<li>An SVG icon</li>
<li>A headline</li>
<li>Content Section</li>
<li>Call to Action</li>
</ul>
<p>We are going to style this card with TailwindCSS and give it a background gradient too so that it looks good.</p>
<pre><code class="lang-tsx">import React from "react";

export const MeteorPreview = () =&gt; {
  return (
    &lt;div className=" h-[40rem]"&gt;
      &lt;div className=" h-3/4 md:h-1/2 w-3/4  relative max-w-sm"&gt;
        &lt;div className="absolute inset-0 h-full w-full bg-gradient-to-r from-blue-500 to-teal-500 transform scale-[0.80] bg-red-500 rounded-full blur-3xl" /&gt;
        &lt;div className="relative shadow-xl bg-gray-900 border border-gray-800  px-4 py-8 h-full overflow-hidden rounded-2xl flex flex-col justify-end items-start"&gt;
          &lt;div className="h-5 w-5 rounded-full border flex items-center justify-center mb-4 border-gray-500"&gt;
            &lt;svg
              xmlns="http://www.w3.org/2000/svg"
              fill="none"
              viewBox="0 0 24 24"
              stroke-width="1.5"
              stroke="currentColor"
              className="h-2 w-2 text-gray-300"
            &gt;
              &lt;path
                stroke-linecap="round"
                stroke-linejoin="round"
                d="M4.5 4.5l15 15m0 0V8.25m0 11.25H8.25"
              /&gt;
            &lt;/svg&gt;
          &lt;/div&gt;

          &lt;h1 className="font-bold text-xl text-white mb-0 mt-4 relative z-50"&gt;
            Meteors because they're cool
          &lt;/h1&gt;

          &lt;p className="font-normal text-base text-slate-500 mb-4 relative z-50"&gt;
            I don't know what to write so I'll just paste something cool here.
            One more sentence because lorem ipsum is just unacceptable.
          &lt;/p&gt;

          &lt;button className="border px-4 py-1 rounded-lg !text-sm  border-gray-500 text-gray-300"&gt;
            Explore &amp;rarr;
          &lt;/button&gt;

        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};
</code></pre>
<p>Firstly, we created a container that holds the content of the card. This container contains the following:</p>
<ul>
<li>An SVG Icon at the top of the container</li>
<li>A headline, which is a one liner that shows the purpose of the card</li>
<li>Some content, which is contained in a paragraph tag explaining the contents of the card</li>
<li>CTA, which is a button element that takes the user to some other part of the website.</li>
</ul>
<p>Now that we have the Card component in place (the container), lets create the <code>Meteor</code> component.</p>
<h2 id="heading-how-to-build-the-meteor-component">How to Build the Meteor Component</h2>
<p>Like I explained before, a meteor is nothing but a UI element with a head and a tail that has a gradient. We are going to build exactly that here.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-11-at-9.04.17-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Standalone meteors</em></p>
<p>Every meteor will have:</p>
<ul>
<li>A tail of width of <code>50px</code></li>
<li>A tail height of <code>1px</code></li>
<li>A background gradient (for the tail) which goes from <code>#64748b</code> to <code>transparent</code></li>
<li>A head of height and width <code>2px</code></li>
</ul>
<pre><code class="lang-tsx">import clsx from "clsx";
import React from "react";

export const Meteors = ({ number }: { number?: number }) =&gt; {
  const meteors = new Array(number || 20).fill(true);
  return (
    &lt;&gt;
      {meteors.map((el, idx) =&gt; (
        &lt;span
          key={"meteor" + idx}
          className={clsx(
            "animate-meteor-effect absolute top-1/2 left-1/2 h-0.5 w-0.5 rounded-[9999px] bg-slate-500 shadow-[0_0_0_1px_#ffffff10] rotate-[215deg]",
            "before:content-[''] before:absolute before:top-1/2 before:transform before:-translate-y-[50%] before:w-[50px] before:h-[1px] before:bg-gradient-to-r before:from-[#64748b] before:to-transparent"
          )}
          style={{
            top: 0,
            left: Math.floor(Math.random() * (400 - -400) + -400) + "px",
            animationDelay: Math.random() * (0.8 - 0.2) + 0.2 + "s",
            animationDuration: Math.floor(Math.random() * (10 - 2) + 2) + "s",
          }}
        &gt;&lt;/span&gt;
      ))}
    &lt;/&gt;
  );
};
</code></pre>
<p>Let's understand the Meteor component.</p>
<ul>
<li>The <code>Meteor</code> component takes in a prop of <code>numbers</code>. This is created in such a way that if you pass the numbers, the meteors increase. The default is set to 20.</li>
<li>We create a <code>span</code> element which will essentially be our meteor that goes from left to right.</li>
<li>the <code>before:</code> class creates a pseudo before element which is essentially the <code>line</code> part of the meteor. We are giving it a linear gradient and a width of <code>50px</code>.</li>
<li>The <code>style</code> tag decides where the meteor is currently in the DOM. We are going to use <code>Math.random()</code> to randomly place meteors on the background.</li>
<li>To actually animate the meteors, we are using the class of <code>animate-meteor-effect</code>. This class is actually added in the <code>tailwind.config.js</code> file to add moving animation.</li>
</ul>
<pre><code class="lang-js"> theme: {
    <span class="hljs-attr">extend</span>: {
      <span class="hljs-attr">animation</span>: {
        <span class="hljs-string">"meteor-effect"</span>: <span class="hljs-string">"meteor 5s linear infinite"</span>,
      },
      <span class="hljs-attr">keyframes</span>: {

        <span class="hljs-attr">meteor</span>: {
          <span class="hljs-string">"0%"</span>: { <span class="hljs-attr">transform</span>: <span class="hljs-string">"rotate(215deg) translateX(0)"</span>, <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span> },
          <span class="hljs-string">"70%"</span>: { <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span> },
          <span class="hljs-string">"100%"</span>: {
            <span class="hljs-attr">transform</span>: <span class="hljs-string">"rotate(215deg) translateX(-500px)"</span>,
            <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span>,
          },
        },
      },
    },
  },
</code></pre>
<p>Here, we are basically moving the beam to negative <code>500px</code> in a span of 5 seconds. This is what causes the meteor to move from left to right. It also nicely animates the opacity from visible to hidden (when we are 70% of the way through).</p>
<h2 id="heading-how-to-use-the-meteor-component">How to Use the Meteor Component</h2>
<p>Now since we have the <code>Meteor</code> component in place, we can easily embed it into our card component that we created previously:</p>
<pre><code class="lang-tsx">import React from "react";
import { Meteors } from "./Meteors";

export const MeteorPreview = () =&gt; {
  return (
    &lt;div className=" h-[40rem]"&gt;
      &lt;div className=" h-3/4 md:h-1/2 w-3/4  relative max-w-sm"&gt;
        &lt;div className="absolute inset-0 h-full w-full bg-gradient-to-r from-blue-500 to-teal-500 transform scale-[0.80] bg-red-500 rounded-full blur-3xl" /&gt;
        &lt;div className="relative shadow-xl bg-gray-900 border border-gray-800  px-4 py-8 h-full overflow-hidden rounded-2xl flex flex-col justify-end items-start"&gt;
          &lt;div className="h-5 w-5 rounded-full border flex items-center justify-center mb-4 border-gray-500"&gt;
            &lt;svg
              xmlns="http://www.w3.org/2000/svg"
              fill="none"
              viewBox="0 0 24 24"
              stroke-width="1.5"
              stroke="currentColor"
              className="h-2 w-2 text-gray-300"
            &gt;
              &lt;path
                stroke-linecap="round"
                stroke-linejoin="round"
                d="M4.5 4.5l15 15m0 0V8.25m0 11.25H8.25"
              /&gt;
            &lt;/svg&gt;
          &lt;/div&gt;

          &lt;h1 className="font-bold text-xl text-white mb-0 mt-4 relative z-50"&gt;
            Meteors because they're cool
          &lt;/h1&gt;

          &lt;p className="font-normal text-base text-slate-500 mb-4 relative z-50"&gt;
            I don't know what to write so I'll just paste something cool here.
            One more sentence because lorem ipsum is just unacceptable. 
          &lt;/p&gt;

          &lt;button className="border px-4 py-1 rounded-lg !text-sm  border-gray-500 text-gray-300"&gt;
            Explore &amp;rarr;
          &lt;/button&gt;

          {/* Meaty part - Meteor effect */}
          &lt;Meteors number={10} /&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};
</code></pre>
<p>Here, we are embedding the <code>&lt;Meteor /&gt;</code> component with a <code>number={10}</code> prop to only have 10 meteors in our component.</p>
<p>The final component looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-11-at-9.20.20-PM-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>The final Card Component with Meteors</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>It is really easy to create beautiful components that stand out with TailwindCSS  </p>
<p>I loved creating this component from scratch and hope it helps you make your components stand out.  </p>
<p>If you'd like to see more of these cool <a target="_blank" href="https://aceternity.com/components">TailwindCSS and Framer motion components</a>, let me know on <a target="_blank" href="https://twitter.com/mannupaaji">Twitter</a> and I'd be more than happy to work on it. :)  </p>
<p>Happy coding! ✨</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create Custom Animations in Flutter – A Step-by-Step Guide ]]>
                </title>
                <description>
                    <![CDATA[ Animations play a crucial role in enhancing user experience and making mobile apps more engaging.  Flutter, Google's UI toolkit for building natively compiled applications for mobile, web, and desktop, offers a powerful animation system that allows d... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/creating-custom-animations-in-flutter/</link>
                <guid isPermaLink="false">66ba10a1d14c87384322b69f</guid>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Wed, 26 Jul 2023 17:44:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/07/Flutter-Animation.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Animations play a crucial role in enhancing user experience and making mobile apps more engaging. </p>
<p>Flutter, Google's UI toolkit for building natively compiled applications for mobile, web, and desktop, offers a powerful animation system that allows developers to create stunning custom animations. </p>
<p>In this step-by-step guide, we will explore how to build beautiful custom animations in Flutter to take your app's UI to the next level.</p>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>Before we start, make sure you have Flutter installed on your system. It's also useful to have a basic understanding of the framework's fundamental concepts, such as widgets, state management, and gesture handling.</p>
<p>Finally, but most importantly, muster up a small spark of interest in learning animation! :) Because once you see the widgets come to life with animation magic, that spark's gonna grow into a blazing inferno of excitement.</p>
<p>In this guide, we are going to see how to implement animation in two kinds of tasks:</p>
<ol>
<li>Animated List</li>
<li>Animated Loader</li>
</ol>
<p>We are going to create a simple Todo app with Animated List and Animated Loader. So, saddle up, and let's ride into the world of animating lists and loaders in Flutter. 🤠🐴.</p>
<h2 id="heading-how-to-build-an-animated-list-in-flutter">How to Build an Animated List in Flutter</h2>
<p>First, we will create a simple Flutter list with animation. Animated List is a Flutter widget that allows developers to create dynamic and animated lists with smooth and visually appealing transitions. It is part of the Flutter animation framework and is an extension of the ListView widget. </p>
<p>The Animated List automatically animates changes to the list's content, such as inserting or removing items, providing an engaging and interactive user experience.</p>
<h3 id="heading-key-features">Key Features</h3>
<h4 id="heading-insertion-and-removal-animations">Insertion and Removal Animations</h4>
<p>When you add or remove items from the list, the Animated List animates these changes with predefined or custom animations, making the list's modifications visually seamless.</p>
<h4 id="heading-built-in-animation-controllers">Built-in Animation Controllers</h4>
<p>Animated List comes with built-in animation controllers that handle the timing and ease curves of the animations, simplifying the process of creating smooth and fluid transitions.</p>
<h4 id="heading-customizable-animations">Customizable Animations</h4>
<p>While Animated List provides default animations, developers can also customize the animations to fit the app's unique visual style and requirements.</p>
<p>Now, while theory is essential, practical examples bring concepts to life. So, let's dive into a practical example of using an Animated List in Flutter.</p>
<h3 id="heading-project-setup-and-dependencies">Project Setup and Dependencies</h3>
<p>To create our Flutter app, we'll use Visual Studio Code as our development environment. </p>
<p>If you're not familiar with setting up a new Flutter project, don't worry – you can refer to my previous <a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-a-simple-login-app-with-flutter/">blogs</a> for step-by-step instructions. If you're already comfortable creating Flutter projects, skip this part and proceed with the app development.</p>
<p>No need to install any external plugin to create an Animated List.</p>
<h2 id="heading-how-to-create-a-task-model">How to Create a Task Model</h2>
<p>In this blog, we will focus more on animation so we can keep the functionalities simple. Define a Task class that represents a single task with a title and status.</p>
<p>I created a file called <code>todo_list.dart</code> in the <code>lib</code> folder that will contain the Animated List. First I created a simple class that represents a Task with title and status describing whether it's completed or not.</p>
<p><code>todo_list.dart</code></p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Task</span> </span>{
  <span class="hljs-built_in">String</span> title;
  bool isCompleted;
  Task(<span class="hljs-built_in">this</span>.title, <span class="hljs-built_in">this</span>.isCompleted);
}
</code></pre><h2 id="heading-how-to-create-a-simple-list-with-animation">How to Create a Simple List with Animation</h2>
<p>Technically our goal is to create a scrolling container that animates items when inserted or removed. This widget's <a target="_blank" href="https://api.flutter.dev/flutter/widgets/AnimatedListState-class.html">AnimatedListState</a> can be used to dynamically insert or remove items. </p>
<p>To refer to the AnimatedListState either provide a <a target="_blank" href="https://api.flutter.dev/flutter/widgets/GlobalKey-class.html">GlobalKey</a> or use the static <a target="_blank" href="https://api.flutter.dev/flutter/widgets/AnimatedList/of.html">of</a> method from an item's input callback.</p>
<p>To do that, let's create a StatefulWidget to create an Animated List.</p>
<p><code>todo_list.dart</code></p>
<pre><code class="lang-dart"><span class="hljs-comment">// todo_list.dart</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">void</span> main() {
  runApp(TodoListApp());
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Task</span> </span>{
  <span class="hljs-built_in">String</span> title;
  <span class="hljs-built_in">bool</span> isCompleted;
  Task(<span class="hljs-keyword">this</span>.title, <span class="hljs-keyword">this</span>.isCompleted);
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TodoListApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  _TodoListAppState createState() =&gt; _TodoListAppState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_TodoListAppState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">TodoListApp</span>&gt; </span>{
  <span class="hljs-built_in">List</span>&lt;Task&gt; tasks = [];
  <span class="hljs-built_in">bool</span> isLoading = <span class="hljs-keyword">false</span>;

  <span class="hljs-keyword">final</span> GlobalKey&lt;AnimatedListState&gt; _animatedListKey = GlobalKey();

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'ToDo List'</span>)),
        body: AnimatedList(
          key: _animatedListKey,
          initialItemCount: tasks.length,
          itemBuilder: (context, index, animation) {
            <span class="hljs-keyword">return</span> _buildTaskItem(tasks[index], animation, index);
          },
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _addTask,
          child: <span class="hljs-keyword">const</span> Icon(Icons.add),
        ),
        backgroundColor: Colors.white60,
      ),
    );
  }

  Widget _buildTaskItem(Task task, Animation&lt;<span class="hljs-built_in">double</span>&gt; animation, <span class="hljs-built_in">int</span> index) {
    <span class="hljs-keyword">return</span> SizeTransition(
        sizeFactor: animation,
        child: Card(
          color: Colors.white,
          child: ListTile(
            title: Text(task.title),
            onLongPress: () =&gt; _removeTask(index),
          ),
        ));
  }

  <span class="hljs-keyword">void</span> _addTask() <span class="hljs-keyword">async</span> {
    Task newTask = Task(<span class="hljs-string">'New Task <span class="hljs-subst">${tasks.length + <span class="hljs-number">1</span>}</span>'</span>, <span class="hljs-keyword">false</span>);
    tasks.add(newTask);
    _animatedListKey.currentState!.insertItem(tasks.length - <span class="hljs-number">1</span>);
  }

  <span class="hljs-keyword">void</span> _removeTask(<span class="hljs-built_in">int</span> index) <span class="hljs-keyword">async</span> {
    _animatedListKey.currentState!.removeItem(index,
        (context, animation) =&gt; _buildTaskItem(tasks[index], animation, index));
    tasks.removeAt(index);
  }
}
</code></pre>
<p>Here, we used <code>AnimatedList</code> (a default Flutter package ). The <code>AnimatedList</code> class in Flutter is a powerful widget that allows us to create dynamic and animated lists with smooth transitions. It is an extension of the ListView widget, providing built-in animation support for adding, removing, and updating items in the list. </p>
<p>The primary goal of  <code>AnimatedList</code> is to enhance the user experience by animating changes to the list's content, making the app feel more interactive and visually engaging.</p>
<p><code>AnimatedList</code> has multiple properties or parameters that control various aspects of the widget's behavior, appearance, and animations. Understanding and using these props correctly is crucial to achieving the desired behavior and visual effects in an <code>AnimatedList</code>. </p>
<p>To know about the properties and behavior of <code>AnimatedList</code> please refer to the official <a target="_blank" href="https://api.flutter.dev/flutter/widgets/AnimatedList-class.html">documentation</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/flutter_animated_list_demo.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Simple Animated List in Flutter</em></p>
<p>In this tutorial, we will be focusing on Animated List and Animated Loader. If you are not familiar with Flutter basics (like widgets, states, and so on) I would recommend that you read my previous <a target="_blank" href="https://www.freecodecamp.org/news/learn-state-management-in-flutter/">tutorial</a>.</p>
<h2 id="heading-how-to-build-the-animated-loader">How to Build the Animated Loader</h2>
<p>A loader is commonly used to provide visual feedback to users while waiting for data to load, processing content, or completing network requests. Loaders help improve the user experience by giving a sense of activity and preventing the app from appearing unresponsive during waiting periods.</p>
<p>There are various ways to implement loaders in Flutter, including using built-in widgets, third-party packages, or creating custom loaders. Additionally, "animated loaders" add an extra touch of dynamism to the loading process by incorporating smooth animations.</p>
<p>Let's add an animated loader in our TodoApp while creating and deleting a task.</p>
<h3 id="heading-how-to-add-the-flutter-loader-package">How to Add the Flutter Loader Package</h3>
<p>You'll need to install the package with the following command:</p>
<pre><code>flutter pub add loading_animation_widget
</code></pre><p>Then you should see the following screen:</p>
<p><img src="https://www.gogosoon.com/wp-content/uploads/2023/07/image-28-1024x208.png" alt="Image" width="600" height="400" loading="lazy">
<em>Installing loading animation package in Flutter</em></p>
<p>Now your package should be ready for use.</p>
<h3 id="heading-how-to-implement-animatedloader">How to Implement <code>AnimatedLoader</code></h3>
<p>The <code>loading_animation_widget</code> package offers various loader animations that we can use to display loading indicators in our app. By importing the package, we gain access to these loader animations and can utilize them to enhance the user experience during loading operations or any other asynchronous tasks.</p>
<p>All loading animation APIs follow the same straightforward implementation. There is a static method for each animation inside the LoadingAnimationWidget class, which returns the Object of that animation. Both <code>size</code> and <code>color</code> are required some animations need more than one color.</p>
<p><code>loading_animation_widget</code> offers multiple animated loaders with customized animation. Let's explore a few of those and integrate into our Todo App.</p>
<p>Now I created a file called <code>animated_loader.dart</code>, which has AnimatedLoader Widget.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// animated_loader.dart</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:loading_animation_widget/loading_animation_widget.dart'</span>;

<span class="hljs-keyword">void</span> main() {
  runApp(AnimatedLoader());
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AnimatedLoader</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      home: MyLoaderScreen(),
    );
  }
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyLoaderScreen</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      body: Center(
        child: LoadingAnimationWidget.staggeredDotsWave(
            size: <span class="hljs-number">75</span>, color: Colors.deepPurple),
      ),
      backgroundColor: Colors.transparent,
    );
  }
}
</code></pre>
<p>Let's show this animated loader in our animated list while adding or removing a task.</p>
<p><code>todo_list.dart</code></p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter_animation/animated_loader.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:loader_overlay/loader_overlay.dart'</span>;

<span class="hljs-keyword">void</span> main() {
  runApp(TodoListApp());
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Task</span> </span>{
  <span class="hljs-built_in">String</span> title;
  <span class="hljs-built_in">bool</span> isCompleted;
  Task(<span class="hljs-keyword">this</span>.title, <span class="hljs-keyword">this</span>.isCompleted);
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TodoListApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  _TodoListAppState createState() =&gt; _TodoListAppState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_TodoListAppState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">TodoListApp</span>&gt; </span>{
  <span class="hljs-built_in">List</span>&lt;Task&gt; tasks = [];
  <span class="hljs-built_in">bool</span> isLoading = <span class="hljs-keyword">false</span>;

  <span class="hljs-keyword">final</span> GlobalKey&lt;AnimatedListState&gt; _animatedListKey = GlobalKey();

  Future&lt;<span class="hljs-keyword">void</span>&gt; loadData() <span class="hljs-keyword">async</span> {
    setState(() {
      isLoading = <span class="hljs-keyword">true</span>;
    });
    <span class="hljs-keyword">await</span> Future.delayed(<span class="hljs-keyword">const</span> <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">2</span>));
    setState(() {
      isLoading = <span class="hljs-keyword">false</span>;
    });
  }

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'ToDo List'</span>)),
        body: Stack(
          children: [
            AnimatedList(
              key: _animatedListKey,
              initialItemCount: tasks.length,
              itemBuilder: (context, index, animation) {
                <span class="hljs-keyword">return</span> _buildTaskItem(tasks[index], animation, index);
              },
            ),
            <span class="hljs-keyword">if</span> (isLoading)
              <span class="hljs-keyword">const</span> Opacity(
                opacity: <span class="hljs-number">0</span>,
                child: ModalBarrier(dismissible: <span class="hljs-keyword">false</span>, color: Colors.black),
              ),
            <span class="hljs-keyword">if</span> (isLoading)
              Center(
                child: Center(child: AnimatedLoader()),
              ),
          ],
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _addTask,
          child: <span class="hljs-keyword">const</span> Icon(Icons.add),
        ),
        backgroundColor: Colors.white60,
      ),
    );
  }

  Widget _buildTaskItem(Task task, Animation&lt;<span class="hljs-built_in">double</span>&gt; animation, <span class="hljs-built_in">int</span> index) {
    <span class="hljs-keyword">return</span> SizeTransition(
        sizeFactor: animation,
        child: Card(
          color: Colors.white,
          child: ListTile(
            title: Text(task.title),
            onLongPress: () =&gt; _removeTask(index),
          ),
        ));
  }

  <span class="hljs-keyword">void</span> _addTask() <span class="hljs-keyword">async</span> {
    Task newTask = Task(<span class="hljs-string">'New Task <span class="hljs-subst">${tasks.length + <span class="hljs-number">1</span>}</span>'</span>, <span class="hljs-keyword">false</span>);
    <span class="hljs-keyword">await</span> loadData();
    tasks.add(newTask);
    _animatedListKey.currentState!.insertItem(tasks.length - <span class="hljs-number">1</span>);
  }

  <span class="hljs-keyword">void</span> _removeTask(<span class="hljs-built_in">int</span> index) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">await</span> loadData();
    _animatedListKey.currentState!.removeItem(index,
        (context, animation) =&gt; _buildTaskItem(tasks[index], animation, index));
    tasks.removeAt(index);
  }
}
</code></pre>
<p>To explore more about the Loader you can refer to the <a target="_blank" href="https://pub.dev/packages/loading_animation_widget">docs</a>. It has multiple loaders with customization options.</p>
<p><img src="https://www.gogosoon.com/wp-content/uploads/2023/07/flutter_animation_with_loader-2.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Animated List with Animated Loader in Flutter</em></p>
<p>Hurray! We can see that the Animation Loader and Animation List are rendering very smoothly, and they look even better.</p>
<p>If you are implementing this from scratch, that's great and it'll really help you learn. But if you prefer, you can also clone the repo from <a target="_blank" href="https://github.com/5minslearn/flutter_animation">GitHub</a>. Either way, I'm excited to see the Animation Loader and Animation List in action from you.</p>
<p>Note: In the context of creating a task in real time, a loader might not be necessary since the creation of a task typically happens quickly and doesn't involve any lengthy processes like fetching data from an API or performing complex computations. But adding a loader during task creation can still be a useful visual cue to indicate that the task is being processed and provide immediate feedback to the user.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We explored the world of creating beautiful custom animations in Flutter, focusing on the implementation of Animated List and Animated Loader. By understanding the Animated List, we learned how to create dynamic and interactive lists with smooth item insertions and removals.</p>
<p>Through these examples, you saw Flutter's ability to make animation implementation enjoyable and straightforward. By incorporating custom animations into your apps, you can create engaging and visually appealing interfaces that captivate users and set your apps apart.</p>
<p>If you wish to learn more about Flutter, subscribe to my <a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_animation">email newsletter</a> (<a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_animation">https://5minslearn.gogosoon.com/</a>) and follow me on social media.</p>
<p>Happy Animating and Fluttering! 🚀 </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Add Swipe Animations to a CardView in an Android App ]]>
                </title>
                <description>
                    <![CDATA[ By Gourav Khunger If you're building an Android app, you should consider adding animations. They can improve your app's user experience and increase retention.  These days, if you see an app that has no animation, it can feel odd and out-dated. And s... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/add-swipe-animations-to-a-card-view-in-android-app/</link>
                <guid isPermaLink="false">66d45edb052ad259f07e4ad2</guid>
                
                    <category>
                        <![CDATA[ android app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ androiddev ]]>
                    </category>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Kotlin ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 15 Nov 2021 16:09:53 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/11/Swiping-Animation-Android-Views.gif" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Gourav Khunger</p>
<p>If you're building an Android app, you should consider adding animations. They can improve your app's user experience and increase retention. </p>
<p>These days, if you see an app that has no animation, it can feel odd and out-dated. And since interactive experiences are kind of the new norm, you'll want to figure out ways to set your app apart.</p>
<h2 id="heading-what-well-build-here">What We'll Build Here</h2>
<p>Now, it might seem difficult to make your app stand out if you just have something basic like a quote sharing app (which is what we are going to work on here). It can be hard to hook the user and keep them interested.</p>
<p>Of course, you could just add two simple buttons to load the next/previous quote and call it a day. But that's pretty basic and any app could do that! Even if you're just building a simple side-project, there's no trade-off for good UX :)</p>
<p>So what we'll do in this tutorial is drop the buttons, and instead have logic where a user can swipe the card to the left. When they've swiped far enough, the app will load a new card with a new quote.</p>
<p>By the end of this post, you will learn how to make a really smooth animated card which a user can swipe that can perform whatever action you choose. Here's a demo of how it works:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/iHxFjvI4x.gif" alt="Animation showing smooth slide to refresh swiping animation on a android cardview." width="600" height="400" loading="lazy"></p>
<p>Amazing, right? Let's get into it!</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>For this tutorial, we will use Kotlin as the programming language for our app – but you can easily translate the code to Java and it would work the same.</p>
<p>For reference, this is the quote card that we wish to enable the swipe feature on.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/9CVHyoJfV.png" alt="Android card view with a quote." width="600" height="400" loading="lazy"></p>
<p>It is an androidX <code>CardView</code> with a bunch of <code>TextView</code>s and an <code>ImageView</code>. There's also a <code>ProgressBar</code> that gets shown while loading a new quote.</p>
<p>We won't be making the XML code for the user interface. You can <a target="_blank" href="https://github.com/gouravkhunger/QuotesApp/blob/main/app/src/main/res/layout/fragment_quote.xml">get the layout</a> I used here from the GitHub repository, or build your own.</p>
<p><a target="_blank" href="https://github.com/gouravkhunger/QuotesApp">Here's the complete code</a> for our Quotes app, if you wish to check it out. It uses the MVVM design pattern, but this article doesn't rely on what pattern you use for the business logic of your app, as we'll just be working on the UI part.</p>
<p>Now, we're ready to make that awesome swipe interface!</p>
<h2 id="heading-how-to-handle-swipes-in-our-app">How to Handle Swipes in Our App</h2>
<p>To handle swipes, we first need to set a touch listener on the card. Each time an action is performed on the card, the touch listener is called. Within the listener, we will add the logic to do the math and perform the animations.</p>
<p>Here is the blueprint of the touch listener we will be using:</p>
<pre><code class="lang-kotlin">quoteCard.setOnTouchListener(
    View.OnTouchListener { view, event -&gt;
        <span class="hljs-keyword">when</span> (event.action) {
            MotionEvent.ACTION_MOVE -&gt; {
                <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Handle ACTION_MOVE</span>
            }
            MotionEvent.ACTION_UP -&gt; {
                <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Handle ACTION_UP</span>
            }
        }

        <span class="hljs-comment">// required to by-pass lint warning</span>
        view.performClick()
        <span class="hljs-keyword">return</span><span class="hljs-symbol">@OnTouchListener</span> <span class="hljs-literal">true</span>
    }
)
</code></pre>
<p>Here, we are specifically listening for 2 actions on the card – the <code>ACTION_MOVE</code> and the <code>ACTION_UP</code>.</p>
<ul>
<li>The <code>ACTION_MOVE</code> event is called when a user starts swiping the card, that is, moving it.</li>
<li>The <code>ACTION_UP</code> is called when a user lifts their finger from the card, basically, when they release it.</li>
</ul>
<p>There are many other action events that we can override, such as <code>ACTION_DOWN</code> that's called when a person gets hold of the view, but we don't need them for this feature.</p>
<p>The basic setup for the card is done, so let's figure out the swiping logic.</p>
<h3 id="heading-the-math-behind-the-swipe-action">The math behind the swipe action</h3>
<p>First, let's re-think <strong>what we want to achieve</strong>. Implementing functionality is easier when you know exactly what you wish to have. Your code will also make more sense when your requirements are clear.</p>
<p>Here, we have a quote card. We want users to be able to swipe it only to the left, and if the minimum threshold to load a new quote is reached, it should move back to its original position and load a new quote.</p>
<p>Now, to achieve this, let's think of it in terms of the card. Let's define the mean position as the center of the card.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/dEnpWr7e4.png" alt="Mean Position of Quote Card" width="600" height="400" loading="lazy">
<em>Mean Position of the Card</em></p>
<p>We want the card to swipe if and only if the user swipes it to the left of the mean position.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/7epeWn53S.gif" alt="Animation illustrating user swipes to the left of the Quote Card" width="600" height="400" loading="lazy">
<em>Swipe only if moved towards the left of mean position</em></p>
<p>So how can we make this happen? </p>
<p>You guessed it – we will calculate the mean position and on the <code>ACTION_MOVE</code> event, we will check if the user swiped to the left and move the card accordingly.</p>
<h3 id="heading-how-to-implement-the-swipe-logic">How to implement the swipe logic</h3>
<p>To implement the logic, we first need to have the starting position of the card, which is fairly easy to calculate. We will just make sure that it is calculated with respect to the full-screen width, not just the card's width.</p>
<p>Place these lines of code before the <code>when(event.action)</code> statement:</p>
<pre><code class="lang-kotlin">quoteCard.setOnTouchListener(
    View.OnTouchListener { view, event -&gt;

        <span class="hljs-comment">// variables to store current configuration of quote card.</span>
        <span class="hljs-keyword">val</span> displayMetrics = resources.displayMetrics
        <span class="hljs-keyword">val</span> cardWidth = quoteCard.width
        <span class="hljs-keyword">val</span> cardStart = (displayMetrics.widthPixels.toFloat() / <span class="hljs-number">2</span>) - (cardWidth / <span class="hljs-number">2</span>)

        <span class="hljs-keyword">when</span> (event.action) {
            ...
        }
        ...
    }
)
</code></pre>
<p>First we get the <code>displayMetrics</code> from resources, which will give us the width of the screen using <code>displayMetrics.widthPixels.toFloat()</code>.</p>
<p>Then we get the <code>cardWidth</code> using the <code>width</code> property of the <code>quoteCard</code>.</p>
<p>Finally, we calculate the starting position of the card using the formula <code>(width of screen/2) - (cardWidth/2)</code>. Essentially, this gives us the x-coordinate of this position of the card:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/NiH3lsseM.gif" alt="Animation highlighting starting position of Quote Card" width="600" height="400" loading="lazy">
<em>Starting position of card.</em></p>
<p>Now, let's implement the code for the <code>ACTION_MOVE</code> event.</p>
<h3 id="heading-how-to-handle-the-actionmove-event">How to handle the <code>ACTION_MOVE</code> event</h3>
<p>Inside the <code>ACTION_MOVE</code> block, we first initialise the <code>newX</code> variable that holds the new x-coordinate that the card has been swiped to.</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> newX = event.rawX
</code></pre>
<p><code>event.rawX</code> gives us the absolute value of the new coordinate with respect to the screen width.</p>
<p><code>newX</code> will contain the x-coordinate where the user's finger is, at any given moment. The value <code>0.0</code> for <code>newX</code> means that the user swiped to the left-most part of the screen. And for my emulator, <code>1080.0</code> represents the right-most edge of the screen.</p>
<p>Since, we want the card to swipe only if <code>newX</code> is less than the mean position of the card, we will place an if-condition here to verify that this is the case.</p>
<p>Think of this with simple values. Let's suppose that the mean position of the card is at x-coordinate <code>540.0</code> (small x-coordinate) and the user swipes to <code>710.0</code> (bigger x-coordinate). But we don't want them to be able to swipe to the right. And if the user swipes to <code>320.0</code> (smaller x-coordinate), then we need to carry out the swipe and move the card to the new position.</p>
<p>Here's the code to implement the above logic:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">if</span> (newX - cardWidth &lt; cardStart) { <span class="hljs-comment">// or newX &lt; cardStart + cardWidth</span>
    quoteCard.animate().x(
        min(cardStart, newX - (cardWidth / <span class="hljs-number">2</span>))
    )
    .setDuration(<span class="hljs-number">0</span>)
    .start()
}
</code></pre>
<p>We subtract <code>cardWidth</code> from <code>newX</code> because <code>newX</code> is an absolute value which is not relative to the card. It has a higher value because <code>cardStart</code> is towards the start of the screen, and <code>newX</code> is initially somewhere in the middle (a user would generally swipe from the middle).</p>
<p>We want to compare the value of <strong>shift</strong> in the x-coordinate and median to the value of <code>cardStart</code>, not the value of <strong><code>newX</code></strong>, so we take this into account by subtracting <code>cardWidth</code>.</p>
<p>Then, we carry out the animation using <code>quoteCard.animate()</code> and we change its x coordinate using the <code>x()</code> function.</p>
<p>Now, why do we do <code>min(cardStart, newX - (cardWidth/2))</code>?</p>
<p>This is very interesting and intuitive to understand. From the beginning, we are emphasizing that the card should move only to the left and not to the right. </p>
<p><code>newX - (cardWidth/2))</code> is nothing but the swiped distance towards the left (so subtraction is involved – for the right side, it should be added).</p>
<p>The <code>min()</code> function here returns the minimum of the two values provided. If the swiped distance is less than the <code>cardStart</code>, it is returned, otherwise <code>cardStart</code> is used. This is the condition we want to meet and <code>min()</code> makes it really easy to handle.</p>
<p><code>setDuration(0)</code> ensures that the animation is carried instantaneously (which keeps swiping from feeling laggy). <code>start()</code> actually starts the animation with the given properties.</p>
<p>This animation will clear any doubt your have on how this works:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/other.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Visualisation of the aforementioned concept</em></p>
<p>(I don't have expertise on making animations, this was the best I could come up with.)</p>
<p>Here is the final code for the <code>ACTION_MOVE</code> event:</p>
<pre><code class="lang-kotlin">MotionEvent.ACTION_MOVE -&gt; {
    <span class="hljs-comment">// get the new coordinate of the event on X-axis</span>
    <span class="hljs-keyword">val</span> newX = event.rawX

    <span class="hljs-comment">// carry out swipe only if newX - cardWidth &lt; cardStart, that is</span>
    <span class="hljs-comment">// the card is swiped to the left side, not to the right</span>
    <span class="hljs-keyword">if</span> (newX - cardWidth &lt; cardStart) {
        quoteCard.animate()
            .x(
                min(cardStart, newX - (cardWidth / <span class="hljs-number">2</span>))
            )
        .setDuration(<span class="hljs-number">0</span>)
        .start()
    }
}
</code></pre>
<p>You can also include a <code>TextView</code> to the UI that reflects when the user should release the card. Place this code inside the above <code>if</code> statement too:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">if</span> (quoteCard.x &lt; MIN_SWIPE_DISTANCE) textView.text = getString(R.string.releaseCard)
<span class="hljs-keyword">else</span> textView.text = getString(R.string.infoText)
</code></pre>
<p>where <code>MIN_SWIPE_DISTANCE</code> is <code>-250</code>:</p>
<pre><code class="lang-kotlin"><span class="hljs-comment">// -250 produces best result, feel free to change to your liking</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">val</span> MIN_SWIPE_DISTANCE = -<span class="hljs-number">250</span> <span class="hljs-comment">// User should move alteast -250 from mean position to load new quote</span>
</code></pre>
<p>Now, the <code>ACTION_MOVE</code> event is handled properly. Let's write the code to handle the <code>ACTION_UP</code> event, that is, when the card is released.</p>
<h3 id="heading-how-to-handle-the-actionup-event">How to handle the <code>ACTION_UP</code> event</h3>
<p>For the <code>ACTION_UP</code> event, we want the card to come back to its original position, wait for about <code>100</code> milliseconds, then load a new quote.</p>
<p>The logic to animate the card is similar, but this time we will make its animation duration about <code>150</code> millisecond to make it look smooth.</p>
<p>First, create a variable <code>currentX</code> that holds the current value of the x coordinate of the quote card. We'll use this variable later.</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">var</span> currentX = quoteCard.x
</code></pre>
<p>Then, start the animation on the card. Pass the <code>cardStart</code> variable to the <code>x()</code> function to make it return to its original position and set the duration to <code>150</code>.</p>
<pre><code class="lang-kotlin">quoteCard.animate()
    .x(cardStart)
    .setDuration(<span class="hljs-number">150</span>)
<span class="hljs-comment">// continued below</span>
</code></pre>
<p>This time, we set a listener on the animation. A listener is something that keeps an eye on the animation. By using it, we can perform actions on various animation events such as start, end, resume, and more.</p>
<pre><code class="lang-kotlin"><span class="hljs-comment">// continuation</span>
.setListener(
    <span class="hljs-keyword">object</span> : AnimatorListenerAdapter() {
        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onAnimationEnd</span><span class="hljs-params">(animation: <span class="hljs-type">Animator</span>)</span></span> {
            viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Default) {
                delay(<span class="hljs-number">100</span>)
                <span class="hljs-comment">// check if the swipe distance was more than</span>
                <span class="hljs-comment">// minimum swipe required to load a new quote</span>
                <span class="hljs-keyword">if</span> (currentX &lt; MIN_SWIPE_DISTANCE) {
                    <span class="hljs-comment">// Add logic to load a new quote if swiped adequately</span>
                    viewModel.getRandomQuote()
                    currentX = <span class="hljs-number">0f</span>
                }
            }
        }
    }
)
.start()
</code></pre>
<p>We set a listener to look for the ending of the animation by overriding the <code>onAnimationEnd()</code> function. </p>
<p>As soon as the animation ends, we launch a coroutine (similar to Threads in Java but much more efficient) with a delay of 100 milliseconds. It then checks if the user had swiped further than the <code>MIN_SWIPE_DISTANCE</code> needed to load a new quote. The variable <code>currentX</code> is used for the comparison here.</p>
<p>If the user actually swipes passing the minimum distance, the coroutine is delayed for <code>100</code> milliseconds. Then the view model loads a new random quote from the API, also resetting the <code>currentX</code> variable to <code>0f</code>.</p>
<p>The final code for the <code>ACTION_UP</code> event looks like this:</p>
<pre><code class="lang-kotlin">MotionEvent.ACTION_UP -&gt; {
    <span class="hljs-keyword">var</span> currentX = quoteCard.x
    quoteCard.animate()
        .x(cardStart)
        .setDuration(<span class="hljs-number">150</span>)
        .setListener(<span class="hljs-keyword">object</span> : AnimatorListenerAdapter() {
            <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onAnimationEnd</span><span class="hljs-params">(animation: <span class="hljs-type">Animator</span>)</span></span> {
                viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Default) {
                    delay(<span class="hljs-number">100</span>)
                    <span class="hljs-comment">// check if the swipe distance was more than</span>
                    <span class="hljs-comment">// minimum swipe required to load a new quote</span>
                    <span class="hljs-keyword">if</span> (currentX &lt; MIN_SWIPE_DISTANCE) {
                        <span class="hljs-comment">// Add logic to load a new quote if swiped adequately</span>
                        viewModel.getRandomQuote()
                        currentX = <span class="hljs-number">0f</span>
                    }
                }
            }
        })
        .start()
    textView.text = getString(R.string.infoText)
}
</code></pre>
<h2 id="heading-final-code">Final Code</h2>
<p>This is the final code for the complete <code>onTouchListener()</code>:</p>
<pre><code class="lang-kotlin">quoteCard.setOnTouchListener(
    View.OnTouchListener { v, event -&gt;

        <span class="hljs-comment">// variables to store current configuration of quote card.</span>
        <span class="hljs-keyword">val</span> displayMetrics = resources.displayMetrics
        <span class="hljs-keyword">val</span> cardWidth = quoteCard.width
        <span class="hljs-keyword">val</span> cardStart = (displayMetrics.widthPixels.toFloat() / <span class="hljs-number">2</span>) - (cardWidth / <span class="hljs-number">2</span>)

        <span class="hljs-keyword">when</span> (event.action) {
            MotionEvent.ACTION_UP -&gt; {
                <span class="hljs-keyword">var</span> currentX = quoteCard.x
                quoteCard.animate()
                    .x(cardStart)
                    .setDuration(<span class="hljs-number">150</span>)
                    .setListener(
                        <span class="hljs-keyword">object</span> : AnimatorListenerAdapter() {
                            <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onAnimationEnd</span><span class="hljs-params">(animation: <span class="hljs-type">Animator</span>)</span></span> {
                                viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Default) {
                                    delay(<span class="hljs-number">100</span>)

                                    <span class="hljs-comment">// check if the swipe distance was more than</span>
                                    <span class="hljs-comment">// minimum swipe required to load a new quote</span>
                                    <span class="hljs-keyword">if</span> (currentX &lt; MIN_SWIPE_DISTANCE) {
                                        <span class="hljs-comment">// Add logic to load a new quote if swiped adequately</span>
                                        viewModel.getRandomQuote()
                                        currentX = <span class="hljs-number">0f</span>
                                    }
                                }
                            }
                        }
                    )
                    .start()
                textView.text = getString(R.string.infoText)
            }
            MotionEvent.ACTION_MOVE -&gt; {
                <span class="hljs-comment">// get the new co-ordinate of X-axis</span>
                <span class="hljs-keyword">val</span> newX = event.rawX

                <span class="hljs-comment">// carry out swipe only if newX &lt; cardStart, that is,</span>
                <span class="hljs-comment">// the card is swiped to the left side, not to the right</span>
                <span class="hljs-keyword">if</span> (newX - cardWidth &lt; cardStart) {
                    quoteCard.animate()
                        .x(
                            min(cardStart, newX - (cardWidth / <span class="hljs-number">2</span>))
                        )
                        .setDuration(<span class="hljs-number">0</span>)
                        .start()
                    <span class="hljs-keyword">if</span> (quoteCard.x &lt; MIN_SWIPE_DISTANCE) 
                        textView.text = getString(R.string.releaseCard)
                    <span class="hljs-keyword">else</span> textView.text = getString(R.string.infoText)
                }
            }
        }

        <span class="hljs-comment">// required to by-pass lint warning</span>
        v.performClick()
        <span class="hljs-keyword">return</span><span class="hljs-symbol">@OnTouchListener</span> <span class="hljs-literal">true</span>
    }
}
</code></pre>
<p>Congrats! In this tutorial, we've implemented animation that lets a user swipe a card containing a quote to get a new quote.</p>
<p>Don't forget to download the app and test it out yourself. Stars and contributions on the <a target="_blank" href="https://github.com/gouravkhunger/QuotesApp">GitHub repository</a> are welcomed!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Now you have learned how to animate a card and handle animation listeners on it. This helps create better UX that makes your app stand out.</p>
<p>Using the knowledge you gained in this post, you can now create most of the following animations for views in Android:</p>
<ul>
<li><strong>Programmatically create sliding animations for Android views.</strong></li>
</ul>
<p>Just as we did in this tutorial.</p>
<ul>
<li><strong>Left to right animation</strong></li>
</ul>
<p>This is fairly simple, just turn the subtraction in the variables to addition and <code>&lt;</code> signs in the <code>if</code> statements to <code>&gt;</code> signs. With these few tweaks here and there, the right to left animations in card view can be turned into left to right ones!</p>
<ul>
<li><strong>You can also show and hide views using animations.</strong></li>
</ul>
<p>For this, you have to keep track of the start position and end position then animate them with <code>alpha()</code> from <code>0</code> to <code>1</code>. For an example, you can refer to my library <a target="_blank" href="https://github.com/gouravkhunger/AccoLib">Accolib</a> to create animated FAQ accordions.</p>
<ul>
<li><strong>Basic animated layout changes can be achieved with view animations.</strong></li>
</ul>
<p>Thanks a lot for reading so far, I hope this post added some value. Subscribe to my newsletter at <a target="_blank" href="https://genicsblog.com">Genics Blog</a> to stay updated with my future articles!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use the Lottie Library like a Pro – Lottie Resources for Designers and Developers ]]>
                </title>
                <description>
                    <![CDATA[ By Idorenyin Udoh Lottie is a library that helps render Adobe After Effects animations natively on mobile and the web. I like using Lottie for animations in my projects because: Creating an animation from scratch can be time-consuming, and GIF files... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-lottie-like-a-pro-resources-for-designers-and-developers/</link>
                <guid isPermaLink="false">66d45f33264384a65d5a953a</guid>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Design ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 17 May 2021 16:25:22 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/05/photo-1619472351888-f844a0b33f5b.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Idorenyin Udoh</p>
<p>Lottie is a library that helps render Adobe After Effects animations natively on mobile and the web. I like using Lottie for animations in my projects because:</p>
<ul>
<li>Creating an animation from scratch can be time-consuming, and</li>
<li>GIF files can be double the size of Lottie JSON files (the files containing the Lottie animation)</li>
</ul>
<p>If you use Lottie frequently in your projects, you have probably felt the stress of:</p>
<ul>
<li>finding an appropriate Lottie animation (if you are not familiar with Adobe After Effects)</li>
<li>knowing what the complete animation looks like</li>
<li>editing it to your preferred style, and</li>
<li>implementing it on the web or mobile.</li>
</ul>
<p>The aim of this article is to boost your productivity as a Lottie designer and developer by providing you with efficient Lottie resources. I will try to include a lottief resources to be as helpful as possible. No pun intended.</p>
<h2 id="heading-resources-to-get-lottie-animations">Resources to Get Lottie Animations</h2>
<p>After you have created your animation in Adobe After Effects, you can export it to the Lottie JSON format using <a target="_blank" href="https://aescripts.com/bodymovin/">the bodymovin extension</a>.</p>
<p>If you are not familiar with Adobe AE, you can get Lottie animations from a number of places. Let's look at some options here.</p>
<h3 id="heading-drawerhttpsdrawerdesign"><a target="_blank" href="https://drawer.design/">Drawer</a></h3>
<p>Drawer offers both free and paid Lottie animations in various formats like JSON, SVG, and PNG as well as Adobe AE, XD and Illustrator files. </p>
<p>After you have selected your preferred animation pack, you can then go ahead with the format you want to use, preferably the Lottie JSON format.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/drawer.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Screenshot of Drawer's Coronavirus Icons' page</em></p>
<h3 id="heading-lottiefileshttpslottiefilescom"><a target="_blank" href="https://lottiefiles.com/">LottieFiles</a></h3>
<p>LottieFiles also offers free and paid Lottie animations. There are packs and individual icons, but unlike Drawer, LottieFiles strictly provides JSON files for Lottie animations.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/lottiefiles.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Screenshot of teen walking animation on LottieFiles</em></p>
<h3 id="heading-icons8httpsicons8comanimated-icons"><a target="_blank" href="https://icons8.com/animated-icons">Icons8</a></h3>
<p>Icons8 provides individual animated icons as well as packs of related animated icons. They provide links to the statically-hosted Lottie JSON files of the animations, which you can either download or use as is in your implementation.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/icons8.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Screenshot of Icons8's pause animated icon's page</em></p>
<h3 id="heading-lordiconhttpslordiconcom"><a target="_blank" href="https://lordicon.com/">Lordicon</a></h3>
<p>Lordicon is a website that offers animations that you can customize before you use them. You can edit features like color and width and then download the animations in your preferred format. </p>
<p>Aside from the JSON format, they also provide animations in HTML, GIF, AEP, PNG, EPS, and SVG.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/lordicon.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Screenshot of Lordicon's icons page</em></p>
<h2 id="heading-how-to-preview-lottie-animations">How to Preview Lottie Animations</h2>
<p>After you have gotten your Lottie animation from one of the sites listed above, you might want to see all the frames you have in the animation. That is, you'll want to watch the animation play from beginning to end. </p>
<p>While this is usually displayed on the sites where you get the animation, I recommend that you check what is in the file you are downloading to confirm that it is what you think you are actually downloading.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/preview-1.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Screenshot of Drawer Preview page</em></p>
<p>To do this, you could go ahead and implement it on web or mobile – but that would just be time-consuming. </p>
<p>Instead, there are resources out there like <a target="_blank" href="https://drawer.design/preview-lottie-animation/">Drawer Preview</a> and <a target="_blank" href="https://lottiefiles.com/preview">LottieFiles Preview</a> that allow you see what is in a Lottie JSON file. All you have to do is drag and drop the file on the provided box. When you have dropped the file, the animation plays automatically and loops, too.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/preview.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Screenshot of LottieFiles Preview page</em></p>
<h2 id="heading-how-to-edit-lottie-animations">How to Edit Lottie Animations</h2>
<p>You might want to tweak one or two things in your animation. Since you did not create it yourself on Adobe AE, you might think that tweaking it isn't possible. But that is not entirely true.</p>
<p>With <a target="_blank" href="https://lottiefiles.com/editor">LottieFiles Editor</a>, you can see the width and height of the animation, frame rate, number of frames, duration, playback speed, and all the layers present in the animation. </p>
<p>Apart from the number of frames, you can edit all these features to your preferences. When you are done, you can share the draft with someone, export a particular layer or the entire Lottie animation, or export it as a Telegram sticker after meeting the required specifications.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/editor.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Screenshot of LottieFiles Editor page</em></p>
<h2 id="heading-how-to-implement-lottie-animations">How to Implement Lottie Animations</h2>
<p>This is the part where you actually use the animation after you've inspected it and made any edits you wanted to make. </p>
<p>You could implement the animation natively on the web, mobile, or CMSs. There are many tutorials out here that show you how to do this, but here I'll provide a few comprehensive resources.</p>
<h3 id="heading-how-to-implement-lottie-on-the-web">How to Implement Lottie on the Web</h3>
<ul>
<li><a target="_blank" href="https://css-tricks.com/animating-with-lottie/">Animating with Lottie | CSS-Tricks</a></li>
<li><a target="_blank" href="https://drawer.design/blog/how-to-use-web-animations-with-lottie/">How to use web animations with Lottie</a></li>
<li><a target="_blank" href="https://lottiefiles.com/blog/working-with-lottie/how-to-add-lottie-animation-in-web-page">How to add a Lottie animation in a web page</a></li>
</ul>
<h3 id="heading-how-to-implement-lottie-on-mobile">How to Implement Lottie on Mobile</h3>
<ul>
<li><a target="_blank" href="https://drawer.design/blog/how-to-use-lottie-animation-in-android-application/">How to use Lottie Animation in Android Application</a></li>
<li><a target="_blank" href="https://lottiefiles.com/blog/working-with-lottie/getting-started-with-lottie-animations-in-android-app">Getting Started with Lottie Animations in an Android App</a></li>
<li><a target="_blank" href="https://www.geeksforgeeks.org/how-to-add-lottie-animation-in-an-android-app/">How to add Lottie Animation in an Android app</a></li>
<li><a target="_blank" href="https://lottiefiles.com/blog/working-with-lottie/using-lottie-animations-apple-watchos">Using Lottie Animations in watchOS</a></li>
<li><a target="_blank" href="https://lottiefiles.com/blog/working-with-lottie/how-to-add-lottie-animation-ios-app-swift">How to add Lottie Animations in iOS apps (Swift)</a></li>
<li><a target="_blank" href="https://www.geeksforgeeks.org/flutter-lottie-animation/">Flutter — Lottie Animation</a></li>
</ul>
<h3 id="heading-how-to-implement-lottie-on-cmss">How to Implement Lottie on CMSs</h3>
<ul>
<li><a target="_blank" href="https://drawer.design/blog/how-to-use-lottie-on-webflow/">How to Use Lottie on Webflow</a></li>
<li><a target="_blank" href="https://university.webflow.com/courses/after-effects-lottie-in-webflow">Add web animations with After Effects &amp; Lottie</a></li>
<li><a target="_blank" href="https://elementor.com/widgets/lottie-widget/">Add Amazing Animations to Your Website With Lottie Widget</a></li>
<li><a target="_blank" href="https://www.wix.com/velo/blog/post/using-lottie-animations-on-wix">Using Lottie Animations on Wix</a></li>
</ul>
<h2 id="heading-lottie-docs-and-libraries">Lottie Docs and Libraries</h2>
<p>In addition to the tools I listed above, when you're implementing Lottie animations there is no better place to start looking than the <a target="_blank" href="https://airbnb.io/lottie/#/">Lottie documentation</a>. If you are more comfortable with the npm package, here is the <a target="_blank" href="https://www.npmjs.com/package/lottie-web">package’s documentation</a> too.</p>
<p>Also, the Lottie libraries for various platforms are available on GitHub:</p>
<ul>
<li><a target="_blank" href="https://github.com/airbnb/lottie-android">lottie-android</a></li>
<li><a target="_blank" href="https://github.com/airbnb/lottie-ios">lottie-ios</a></li>
<li><a target="_blank" href="https://github.com/airbnb/lottie-web">lottie-web</a></li>
</ul>
<p>With all these resources, I really hope you will not be lost because of something Lottie-related.</p>
<p>Thanks for reading and happy animating!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Beautiful Page Transitions in Angular ]]>
                </title>
                <description>
                    <![CDATA[ By Arjav Dave In today’s world, just having a website is not enough. The website needs to have a clean UI and it needs to be intuitive. And most importantly, it needs to have some sort of interactive element. Interactivity keeps users glued to your s... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/beautiful-page-transitions-in-angular/</link>
                <guid isPermaLink="false">66d84de229e30bc0ad47753e</guid>
                
                    <category>
                        <![CDATA[ Angular ]]>
                    </category>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Design ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 11 May 2021 17:50:09 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/05/SF.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Arjav Dave</p>
<p>In today’s world, just having a website is not enough. The website needs to have a clean UI and it needs to be intuitive. And most importantly, it needs to have some sort of interactive element.</p>
<p>Interactivity keeps users glued to your site for longer periods of time. As a result, it increases the chances that users will become customers. Also, longer interaction time leads to a lower bounce rate and a higher ranking on search engines.</p>
<p>One of the most common and basic forms of interaction happens when a user scrolls on your website. But wouldn’t it be quite boring if the user keeps scrolling through your long static page? </p>
<p>In this tutorial, we will have a look at three basic animations that you can implement on scroll. Parallax, fade, and slide animations are the most popular animations devs use to make scrolling more fun. Let’s see how we can build them for our sites.</p>
<p>Before we move further, here are the end results:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/1_Ywqe-PW3A-V8B5mvJmlpVg.gif" alt="Parallax animation" width="600" height="400" loading="lazy">
<em>Parallax ([View Demo](https://animations-demo-ffcb4.web.app/parallax" class="cd il" rel="noopener" style="box-sizing: inherit; color: inherit; text-decoration: underline; -webkit-tap-highlight-color: transparent;))</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/1_cZYvFm4F9EZXCyfpv1Rnwg.gif" alt="Fade animation" width="600" height="400" loading="lazy">
<em>Fade ([View Demo](https://animations-demo-ffcb4.web.app/fade" class="cd il" rel="noopener" style="box-sizing: inherit; color: inherit; text-decoration: underline; -webkit-tap-highlight-color: transparent;))</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/1_-thdCqzqVWw9o0oTk-lN0g.gif" alt="Slide animation" width="600" height="400" loading="lazy">
<em>Slide ([View Demo](https://animations-demo-ffcb4.web.app/slide" class="cd il" rel="noopener" style="box-sizing: inherit; color: inherit; text-decoration: underline; -webkit-tap-highlight-color: transparent;))</em></p>
<h1 id="heading-project-setup">Project Setup</h1>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>We will be using Angular 11 to create our project. And we'll use VS Code as our IDE.</p>
<p>In order to build the animations, we are going to use the fabulous <a target="_blank" href="https://greensock.com/gsap/">Green Sock Animation Platform (gsap)</a>. It’s one of the best JavaScript animation libraries out there.</p>
<h2 id="heading-create-the-project">Create the project</h2>
<p>Create an Angular project by entering the command below. <em>Make sure to enable routing when</em> it asks you<em>.</em></p>
<pre><code>ng <span class="hljs-keyword">new</span> animations --style css
code animations
</code></pre><p>This will create a new project named <em>animations</em> with the style format as CSS. Next, it will open the project in VS Code. </p>
<p>Now let’s install gsap. In your VS Code terminal, enter the command below:</p>
<pre><code>npm install --save gsap @types/gsap
</code></pre><p>This will install the gsap library and the typing files via <code>@types/gsap</code>.</p>
<p>Lastly, let’s create three components. Enter the commands below:</p>
<pre><code>ng g c parallax
ng g c fade
ng g c slide
</code></pre><h2 id="heading-how-to-set-up-the-routes">How to set up the routes</h2>
<p>Let’s create three separate routes: <code>/parallax</code>, <code>/fade</code>, and <code>/scroll</code>. Open your <code>app-routing.module.ts</code> and add the routes as below:</p>


<h1 id="heading-how-to-create-parallax-animation">How to Create Parallax Animation</h1>
<p>Since we have now set up the project, let’s start with parallax animation.</p>
<p>When you create page animations, you typically use sections. So, open your <code>parallax.component.html</code> file and paste in the code below:</p>


<p>Let’s add some styling to these sections. Since we are going to use sections in all three components, we will add styling to the common <code>styles.css</code> file. </p>
<p>Open your <code>styles.css</code> file and paste in the CSS below:</p>


<p>In the above code, we are making the height and width of the section equal to the viewport’s height and width. Second, we are aligning the content in the center of the section. Lastly, we are setting the font style for how we want to display the text.</p>
<p>Since the <code>bg</code> class used in <code>parallax.component.html</code> is specific to parallax, we will define its properties in <code>parallax.component.css</code><em>.</em> Open that file and paste in the CSS below:</p>


<p>In order to set the parallax animation, we need to add some TypeScript code. So, open your <code>parallax.component.ts</code> file and add the code below in your <code>ngOnInit</code> function:</p>


<p>I have added inline comments to help you understand the code. Message me if you need further explanation.</p>
<p>Finally, add the imports below at the top of your TS file so that you don’t get any compile-time errors:</p>
<pre><code><span class="hljs-keyword">import</span> { gsap } <span class="hljs-keyword">from</span> <span class="hljs-string">'gsap'</span>;
<span class="hljs-keyword">import</span> { ScrollTrigger } <span class="hljs-keyword">from</span> <span class="hljs-string">'gsap/all'</span>;
</code></pre><p>That’s it! You can now visit <a target="_blank" href="http://localhost:4200/parallax">http://localhost:4200/parallax</a> to see the beautiful animation.</p>
<h1 id="heading-how-to-create-fade-animation">How to Create Fade Animation</h1>
<p>For the fade animation, open the <code>fade.component.html</code> file and paste in the HTML code below:</p>


<p>In the <code>fade.component.css</code>, paste in the CSS below:</p>


<p>We are going to display only one section at a time. So we will hide all sections except the first one. Also, since we are not moving the sections along with the scroll, we'll mark its position as fixed.</p>
<p>Let’s add the animation code to make the other sections visible on scroll. Open the <code>fade.component.ts</code> file and paste in the following code:</p>


<p>I have added inline comments so as to make the code self-explanatory. For any clarifications, please let me know.</p>
<p>Visit <a target="_blank" href="http://localhost:4200/parallax">http://localhost:4200/fade</a> to see the smooth fading animation as you scroll.</p>
<h1 id="heading-how-to-create-slide-animation">How to Create Slide Animation</h1>
<p>This is typically the easiest of the lot to understand and implement. </p>
<p>Open your <code>slide.component.html</code> file and paste in the code below. It’s similar to <code>fade.component.html</code>, except the class is removed from the first section.</p>


<p>We don't need to add any CSS. </p>
<p>Next, open the <code>slide.component.ts</code> file and add the code below:</p>


<p>Again, I have added the inline comments for a better understanding of the code. For any queries, just reach out to me.</p>
<p>Open <a target="_blank" href="http://localhost:4200/slide">http://localhost:4200/slide</a> to see a mesmerizing slide animation as you scroll.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Animations add a lot of value to your site, and they help keep your users engaged. As with all things, don't go overboard and use animations in moderation. Don’t clutter or mess up the website with heavy images and funky animations. Keep It Simple &amp; Keep It Subtle (KIS &amp; KIS).</p>
<p>In this tutorial, we saw how to add simple parallax, fade, and slide animations for page sections. </p>
<p>Lastly, a great thanks to <a target="_blank" href="https://picsum.photos/">Lorem Picsum</a> for providing such great photos.</p>
<p>If you liked this article, you might also like the below articles:</p>
<ul>
<li><a target="_blank" href="https://betterprogramming.pub/lazy-loading-in-angular-a-beginners-guide-c09d09738d08">Lazy Loading Modules in Angular</a></li>
<li><a target="_blank" href="https://itnext.io/net-5-how-to-authenticate-authorise-apis-correctly-34b09d132d84">.NET 5: How to Authenticate &amp; Authorise API's correctly</a></li>
<li><a target="_blank" href="https://itnext.io/learn-tdd-with-integration-tests-in-net-5-0-937f126e7220">Learn TDD with Integration Tests in .NET 5.0</a></li>
</ul>
<p><em>Note: You can find the whole project</em> <a target="_blank" href="https://github.com/shenanigan/animations-demo"><em>on GitHub</em></a><em>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Make It Blink HTML Tutorial – How to Use the Blink Tag, with Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ In the earlier days of the web, HTML elements like the blink tag were native ways to add some animation effects to liven up a webpage. How can we use those animations today to add flare to our websites and apps? What is the HTML tag blink? How do yo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/make-it-blink-html-tutorial-how-to-use-the-blink-tag-with-code-examples/</link>
                <guid isPermaLink="false">66b8e37e68c5b9f37d1d1aef</guid>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Colby Fayock ]]>
                </dc:creator>
                <pubDate>Mon, 27 Jul 2020 23:21:14 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/07/blink-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In the earlier days of the web, HTML elements like the blink tag were native ways to add some animation effects to liven up a webpage. How can we use those animations today to add flare to our websites and apps?</p>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-the-html-tag-blink">What is the HTML tag blink?</a></li>
<li><a class="post-section-overview" href="#heading-how-do-you-use-the-blink-tag">How do you use the blink tag?</a></li>
<li><a class="post-section-overview" href="#heading-can-you-still-use-the-blink-tag">Can you still use the blink tag?</a></li>
<li><a class="post-section-overview" href="#heading-recreating-the-blink-tag-with-css-animations">Recreating the blink tag with CSS animations</a></li>
</ul>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/-gU-gkfEA1Q" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-what-is-the-html-tag-blink">What is the HTML tag blink?</h2>
<p>The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blink">blink</a> tag (<code>&lt;blink&gt;</code>) is an obsolete HTML tag that makes the content of that tag slowly flash.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/google-search-blink.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Google search of "blink tag"</em></p>
<p>This, along with some other obsolete tags like the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/marquee">marquee</a> tag (<code>&lt;marquee&gt;</code>), were an easy way to add simple animation effects to your site.</p>
<h2 id="heading-how-do-you-use-the-blink-tag">How do you use the blink tag?</h2>
<p>Being that the blink tag was a simple HTML element, you would use it right in line with your content.</p>
<p>For example, if you wanted the word "blink" in blink-182 to blink, you would write the following HTML:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">blink</span>&gt;</span>blink<span class="hljs-tag">&lt;/<span class="hljs-name">blink</span>&gt;</span>-182
<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<h2 id="heading-can-you-still-use-the-blink-tag">Can you still use the blink tag?</h2>
<p>As you might have noticed in the gif above, this tag is obsolete.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/html-blink-browser-compatability.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Blink tag browser compatibility</em></p>
<p>This means you can’t use the blink HTML tag itself. However, that shouldn't stop us from remaking it in all of its blinking glory.</p>
<p>_Note: the Blink tag was deprecated due to accessibility concerns. Please <a target="_blank" href="https://en.wikipedia.org/wiki/Blink_element#Usability_and_accessibility">do your research</a> before trying to use a solution that provides the same effect, as we should all be making an effort to make our projects as inclusive as possible._</p>
<h2 id="heading-recreating-the-blink-tag-with-css-animations">Recreating the blink tag with CSS animations</h2>
<p>In today’s web development world, animations are generally handled with CSS or JavaScript. Using CSS animations, we can recreate our blink tag with a few lines and be back in business.</p>
<p>With the following CSS:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.blink</span> {
  <span class="hljs-attribute">animation</span>: blink <span class="hljs-number">1s</span> <span class="hljs-built_in">steps</span>(<span class="hljs-number">1</span>, end) infinite;
}

<span class="hljs-keyword">@keyframes</span> blink {
  0% {
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
  }
  50% {
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
  }
  100% {
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
  }
}
</code></pre>
<p>You can add the <code>.blink</code> class to any HTML element to make it blink.</p>
<pre><code>&lt;p&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"blink"</span>&gt;</span>blink<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span></span><span class="hljs-number">-182</span>
&lt;/p&gt;
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2020/07/html-blink-effect.gif" alt="Image" width="600" height="400" loading="lazy">
<em>HTML CSS blink effect</em></p>
<h2 id="heading-modernizing-the-blink-tag">Modernizing the blink tag</h2>
<p>This is 2020, what if we wanted something a little smoother?</p>
<p>Well to start, we can make the animation fade by removing the <code>steps</code> from the animation definitions.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.blink</span> {
  <span class="hljs-attribute">animation</span>: blink <span class="hljs-number">1s</span> infinite;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/css-blink-fade.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Blink fade effect</em></p>
<p>Or what if we wanted to make it fade out like a sci-fi effect?</p>
<pre><code>.blink {
  <span class="hljs-attr">animation</span>: blink <span class="hljs-number">3</span>s infinite;
}

@keyframes blink {
  <span class="hljs-number">0</span>% {
    <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span>;
  }
  <span class="hljs-number">100</span>% {
    <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span>;
    color: blue;
  }
}
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2020/07/css-scfifi-fade.gif" alt="Image" width="600" height="400" loading="lazy">
<em>CSS blink fade sci-fi effect</em></p>
<p>Or even a nice grow and fade effect.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.blink</span> {
  <span class="hljs-attribute">animation</span>: blink <span class="hljs-number">3s</span> infinite;
}

<span class="hljs-keyword">@keyframes</span> blink {
  0% {
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
  }
  50% {
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">2</span>);
  }
  51% {
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">0</span>);
  }
  100% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1</span>);
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
  }
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/css-grow-fade.gif" alt="Image" width="600" height="400" loading="lazy">
<em>CSS blink grow and fade effect</em></p>
<h2 id="heading-taking-control-of-animations-with-css">Taking control of animations with CSS</h2>
<p>Though you might not be able to use the blink tag, you still have a lot of options. CSS provides a ton of animation options natively, so whether you want to recreate your favorite HTML pastime or <a target="_blank" href="https://codepen.io/colbyfayock/pen/aEqsL">recreate the Alien title sequence</a>, the possibilities are virtually endless.</p>
<div id="colbyfayock-author-card">
  <p>
    <a href="https://twitter.com/colbyfayock">
      <img src="https://res.cloudinary.com/fay/image/upload/w_2000,h_400,c_fill,q_auto,f_auto/w_1020,c_fit,co_rgb:007079,g_north_west,x_635,y_70,l_text:Source%20Sans%20Pro_64_line_spacing_-10_bold:Colby%20Fayock/w_1020,c_fit,co_rgb:383f43,g_west,x_635,y_6,l_text:Source%20Sans%20Pro_44_line_spacing_0_normal:Follow%20me%20for%20more%20JavaScript%252c%20UX%252c%20and%20other%20interesting%20things!/w_1020,c_fit,co_rgb:007079,g_south_west,x_635,y_70,l_text:Source%20Sans%20Pro_40_line_spacing_-10_semibold:colbyfayock.com/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_68,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_145,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_222,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_295,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/v1/social-footer-card" alt="Follow me for more Javascript, UX, and other interesting things!" width="2000" height="400" loading="lazy">
    </a>
  </p>
  <ul>
    <li>
      <a href="https://twitter.com/colbyfayock">? Follow Me On Twitter</a>
    </li>
    <li>
      <a href="https://youtube.com/colbyfayock">?️ Subscribe To My Youtube</a>
    </li>
    <li>
      <a href="https://www.colbyfayock.com/newsletter/">✉️ Sign Up For My Newsletter</a>
    </li>
  </ul>
</div>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
