<?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[ Felix Favour Chinemerem - 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[ Felix Favour Chinemerem - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 14 May 2026 17:33:12 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/felixfavour/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Camera App on the Web – No Plugins Required ]]>
                </title>
                <description>
                    <![CDATA[ Ever had to make a video call right on your browser with Google Meet, Zoom, or any other video chat app? Well, here’s what you might have never thought to ask—how does it work? Well, there are a number of things that make a real-time video chat appli... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-camera-app-on-the-web/</link>
                <guid isPermaLink="false">66bc54a6a085c9ae30a3c96c</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Felix Favour Chinemerem ]]>
                </dc:creator>
                <pubDate>Fri, 23 Feb 2024 00:36:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/supercharged-animations.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Ever had to make a video call right on your browser with Google Meet, Zoom, or any other video chat app? Well, here’s what you might have never thought to ask—how does it work?</p>
<p>Well, there are a number of things that make a real-time video chat application fully functional on the web. In this article, we’ll explore how you can access media content through your device’s camera. And we'll build a camera app in the course of our exploration.</p>
<p>Let’s face it, using the MediaStream API to build a camera application does not tell the whole story. But here’s what I can promise you: we are taking the first step in the right direction.</p>
<p>Before we begin, have a peek at what you should be able to create by the end of this article <a target="_blank" href="https://camera-demo-rho.vercel.app/">here</a>. Now that you are all geared up, let’s get to work!</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we dive in, let's be sure of a few things. This article is designed to be for beginners, but having the right resources will ensure a seamless experience. Here's what you'll need:</p>
<ul>
<li>A very basic understanding of HTML, CSS, and JavaScript — beginner level knowledge is absolutely fine.</li>
<li>A basic understanding of the <a target="_blank" href="https://www.freecodecamp.org/news/javascript-dom/">Document Object Model</a> in JavaScript.</li>
<li>Last but not the 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 all set.</p>
<h2 id="heading-what-is-the-mediastream-api">What is the MediaStream API?</h2>
<p>The MediaStream Recording API helps the browser capture audio-visual data streams. It's important for our use case, because any image we capture has to be stored in a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStream">MediaStream</a> object.</p>
<p>The MediaStream API does more than capture photos and videos. It also helps process and analyze the MediaStream data right on the browser. As complex as all of this might seem, it’ll interest you to know that the MediaStream API is surprisingly easy to work with.</p>
<p>Our camera app makes it even easier.</p>
<h2 id="heading-components-of-our-camera-app">Components of Our Camera App</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/supercharged-animations--3-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Our camera app has a very simple user interface — heavily inspired by the Samsung Camera UI. Some notable components/features of the camera are:</p>
<ul>
<li>Camera Preview</li>
<li>Camera mode options</li>
<li>Photo Gallery</li>
</ul>
<p>For the sake of this tutorial, only a few actions on the browser are enabled — the “photo” camera mode, the camera shutter button, and the photo gallery button just to the right of the shutter button.</p>
<h2 id="heading-step-1-simple-html-for-our-camera-app">Step 1: Simple HTML for Our Camera app</h2>
<p>To begin, we'll lay the foundation for our camera application with some simple markup. Understanding the structure of our camera app is crucial as it comprises four major sections, each playing a vital role in its overall functionality:</p>
<ol>
<li><code>&lt;video&gt;</code> section</li>
<li>Snapshot <code>&lt;button&gt;</code> section</li>
<li><code>&lt;canvas&gt;</code> section</li>
<li>Snapshot <code>&lt;img&gt;</code> section</li>
</ol>
<h3 id="heading-1-section">1. <code>&lt;video&gt;</code> section</h3>
<p>Our camera app must include a <code>&lt;video&gt;</code> tag for streaming the visual media from our webcam to our browser’s display. Let’s give it an <code>id</code> of <code>camera-stream</code>.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">video</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"camera-stream"</span> <span class="hljs-attr">autoplay</span> <span class="hljs-attr">loop</span> <span class="hljs-attr">muted</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">src</span>=<span class="hljs-string">""</span> &gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">video</span>&gt;</span>
</code></pre>
<h3 id="heading-2-snapshot-section">2. Snapshot <code>&lt;button&gt;</code> section</h3>
<p>We'll also need a button to trigger the capture of the visual media when it is clicked. This will act as the shutter button. Let’s give it an <code>id</code> of <code>shutter</code>.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"shutter-ctn"</span>&gt;</span>
  ...
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"shutter"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"shutter"</span>&gt;</span>
  <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>
</code></pre>
<h3 id="heading-3-section">3. <code>&lt;canvas&gt;</code> section</h3>
<p>A canvas tag helps us capture the image data from the video stream, while being able to export the data as an image that can be saved. The <code>&lt;canvas&gt;</code> element does not need to be visible to the user, but it must be accessible by the DOM. Let’s give it an <code>id</code> of <code>canvas</code>.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">canvas</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"canvas"</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">canvas</span>&gt;</span>
</code></pre>
<h3 id="heading-4-snapshot-section">4. Snapshot <code>&lt;img&gt;</code> section</h3>
<p>For the final HTML section, we need a view to see all images that have been captured. Let’s identify this with an id of  <code>gallery-view</code>.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"gallery-view"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"prev"</span>&gt;</span>
    PREV
  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">data-index</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">""</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"current viewed image"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"next"</span>&gt;</span>
    NEXT
  <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>
</code></pre>
<h2 id="heading-step-2-beautiful-css-styles-to-make-our-app-pop">Step 2: Beautiful CSS Styles to Make Our App Pop</h2>
<p>Adding styles to the HTML of our camera app greatly improves its user-friendliness. Don't hesitate to get creative while adding these styles, and feel free to skip this section to Step 3 if you would rather add your own styles.</p>
<p>First, lets add some global styles to ensure that each component fits perfectly when they are layered.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">max-height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">overflow</span>: hidden;
}
<span class="hljs-selector-tag">canvas</span> {
  <span class="hljs-attribute">display</span>: none;
}
<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">border</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">outline</span>: none;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#00000070</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#FFFFFF</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">4px</span> <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">30px</span>;
  <span class="hljs-attribute">min-width</span>: <span class="hljs-number">30px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">24px</span>;
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">place-items</span>: center;
  <span class="hljs-attribute">cursor</span>: pointer;
}
</code></pre>
<p>Afterwards, we'll apply styling to the <code>&lt;video&gt;</code> element, which displays a preview of the shot to be captured.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.camera-ctn</span> {
  <span class="hljs-attribute">position</span>: relative;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#000000</span>;
}
<span class="hljs-selector-class">.camera-view</span> <span class="hljs-selector-tag">video</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100vw</span>;
  <span class="hljs-attribute">object-fit</span>: cover;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scaleX</span>(-<span class="hljs-number">1</span>);
}
</code></pre>
<p>Lastly, the styling task left for us involves customizing the bottom section of our camera interface — the section typically housing the shutter button.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* CAMERA BOTTOM */</span>
<span class="hljs-selector-class">.camera-bottom</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">250px</span>;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#00000050</span>;
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">inset</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">top</span>: auto;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span> <span class="hljs-number">5%</span>;
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">place-items</span>: center;
}
<span class="hljs-selector-class">.camera-bottom</span> &gt; <span class="hljs-selector-class">.inner</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">place-items</span>: center;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">500px</span>;
}

<span class="hljs-comment">/* SHUTTER CONTAINER */</span>
<span class="hljs-selector-class">.shutter-ctn</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: space-around;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}
<span class="hljs-selector-class">.shutter</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">80px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">80px</span>;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#FFFFFF</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}
<span class="hljs-selector-class">.shutter</span><span class="hljs-selector-pseudo">:active</span> {
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">0.8</span>);
}
<span class="hljs-selector-class">.switch-device</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">55px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">55px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}
</code></pre>
<p>To have a full view of the CSS styles originally used on this project, have a look at them <a target="_blank" href="https://github.com/felixfavour/camera-demo/blob/master/assets/styles/main.css">here</a>.</p>
<h2 id="heading-step-3-javascript-code-to-make-our-app-fully-functional">Step 3: JavaScript Code to Make Our App Fully Functional</h2>
<p>Finally, after laying a solid foundation with our HTML structure and improving the usability of our camera app with some CSS styles, our focus now shifts to ensuring our camera app does what it’s supposed to do — take pictures.</p>
<p>We do this by heavily relying on the MediaStream API in JavaScript while following these three steps:</p>
<ol>
<li>Linking our HTML elements to JS.</li>
<li>Connecting the webcam to JS code.</li>
<li>Capturing and saving media from the webcam.</li>
</ol>
<h3 id="heading-1-linking-html-elements-to-js">1. Linking HTML elements to JS</h3>
<p>As we proceed with adding functionality to our HTML, we must link these elements to our JavaScript code via the DOM. Recall that we assigned IDs to the primary elements we defined in the HTML step.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> cameraVideoStream = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'camera-stream'</span>)
<span class="hljs-keyword">const</span> shutterButton = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'shutter'</span>)
<span class="hljs-keyword">const</span> canvas = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'canvas'</span>)
...
</code></pre>
<h3 id="heading-2-connecting-the-webcam-to-javascript-code">2. Connecting the webcam to JavaScript code</h3>
<p>Upon linking our HTML elements to our JS code, we can now establish the connection to our webcam. This involves initially verifying whether the user’s browser supports this operation using the <code>navigator.mediaDevices</code> boolean expression.</p>
<p>If the expression returns a truthy value, we can invoke <code>getUserMedia()</code> and specify the video option by passing <code>{video: true}</code> as a function argument like below:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">if</span> (navigator.mediaDevices &amp;&amp; navigator.mediaDevices.getUserMedia({ <span class="hljs-attr">video</span>: <span class="hljs-literal">true</span> })) {
  navigator.mediaDevices
    .getUserMedia({ <span class="hljs-attr">video</span>: <span class="hljs-literal">true</span> })
    .then (<span class="hljs-function">(<span class="hljs-params">stream</span>) =&gt;</span> {
            cameraVideoStream.srcObject = stream
            cameraVideoStream.play()
    })
}
</code></pre>
<p>The <code>getUserMedia()</code> function invokes an asynchronous operation, which means it doesn't return a response immediately. Also, it might encounter failures — this could happen if the user denies permission for us to access their webcam or if their device lacks a webcam altogether. </p>
<p>If the operation is successful, the video stream is collected and transferred to the <code>video</code> element that was earlier created.</p>
<p>But the video does not start playing immediately. A brief delay occurs to allow for a buffer — this delay is often unnoticed. We have to create a <code>streaming</code> variable in conjunction with the <code>canplay</code> event of the <code>&lt;video&gt;</code> element to know when a portion of the video is buffered and ready to play. We can do that like below:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">let</span> width = <span class="hljs-built_in">window</span>.innerWidth
<span class="hljs-keyword">let</span> height = <span class="hljs-number">0</span>
<span class="hljs-keyword">let</span> streaming = <span class="hljs-literal">false</span>

cameraVideoStream.addEventListener(
  <span class="hljs-string">"canplay"</span>,
  <span class="hljs-function">(<span class="hljs-params">ev</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (!streaming) {
      height = cameraVideoStream.videoHeight / (cameraVideoStream.videoWidth / width);

      canvas.setAttribute(<span class="hljs-string">"width"</span>, width);
      canvas.setAttribute(<span class="hljs-string">"height"</span>, height);
      cameraVideoStream.setAttribute(<span class="hljs-string">"width"</span>, width);
      cameraVideoStream.setAttribute(<span class="hljs-string">"height"</span>, height);
      streaming = <span class="hljs-literal">true</span>;
    }
  },
  <span class="hljs-literal">false</span>
);
</code></pre>
<p>Notice that before <code>streaming</code> is set to true, the <code>&lt;video&gt;</code> element and the <code>&lt;canvas&gt;</code> height are set to match the <code>height</code> value (which might be a fraction of the <code>width</code> based on the desired dimensions). This adjustment helps prevent any glitches, particularly when capturing the image.</p>
<h3 id="heading-3-capture-and-save-media-from-the-webcam">3. Capture and save media from the webcam</h3>
<p>Now, the hardest work is complete. All that is left is to capture snapshots from the video stream and store them in an array as images.</p>
<p>To accomplish this, we use the context of the <code>&lt;canvas&gt;</code> element defined earlier, accessed through <code>canvas.getContext('2d')</code>. Afterwards, we transfer the current frame of data from the video stream to compose an image using the <code>canvasContext.drawImage()</code> function just like below.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// Capture snapshots using HTML Canvas</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">captureImage</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> canvasContext = canvas.getContext(<span class="hljs-string">'2d'</span>)
  canvas.width = width
  canvas.height = height
  canvasContext.drawImage(cameraVideoStream, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, width, height)

  <span class="hljs-comment">// Convert captured data to image (base64)</span>
  <span class="hljs-keyword">const</span> data = canvas.toDataURL(<span class="hljs-string">'image/png'</span>)
  currentImageElement.src = data
}

<span class="hljs-comment">// Add click listener to shutter button to capture image</span>
shutterButton.addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function">() =&gt;</span> captureImage())
</code></pre>
<p>With the data now captured as an image, the absolute final step is to convert the image to a transferable format suitable for the <code>&lt;img&gt;</code> tag or any other image viewing resource. One of the many transferable formats is base64, and fortunately, the <code>&lt;canvas&gt;</code> element enables us to achieve this effortlessly with <code>canvas.toDataURL('image/png')</code>.</p>
<p>And voilà! You've successfully constructed your own camera app. Well done, genius!</p>
<p>As soon as we are done implementing these three steps, all that’s left is to say “cheese” and take some nice pictures.</p>
<p>If you mixed up a few instructions, feel free to take a look at the complete JS code <a target="_blank" href="https://github.com/felixfavour/camera-demo">here</a>. If that does not help much, I’m always happy to assist personally when you <a target="_blank" href="https://favourfelix.com">send a message</a>.</p>
<h2 id="heading-the-fun-doesnt-stop-here">The Fun Doesn't Stop Here</h2>
<p>Wanna have fun building more features for the camera app? You can pick up where I left off on GitHub. Whether it’s your own gallery, or a quick photo editing tool in the gallery view, or a timer feature, or even if you wish to extend this to a video recorder – go for it!</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/felixfavour/camera-demo">https://github.com/felixfavour/camera-demo</a></div>
<p>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 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 Use Container Queries – Responsive Design Beyond the Viewport ]]>
                </title>
                <description>
                    <![CDATA[ Before now, making your website responsive was limited to resizing HTML elements with media queries. This was, and still is, a brilliant innovation for web development in general.  But web development has evolved with the advent of JavaScript framewo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/container-queries-responsive-design-beyond-the-viewport/</link>
                <guid isPermaLink="false">66bc54aaa085c9ae30a3c96e</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ responsive design ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Felix Favour Chinemerem ]]>
                </dc:creator>
                <pubDate>Mon, 22 May 2023 16:24:14 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/05/container-queries-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Before now, making your website responsive was limited to resizing HTML elements with media queries. This was, and still is, a brilliant innovation for web development in general. </p>
<p>But web development has evolved with the advent of JavaScript frameworks—particularly with the use of components as building blocks in developing User Interfaces.</p>
<p>In the component-driven world we are living in, we can see the benefits of container queries in Responsive Web Design. In fact, in some cases, we can achieve a fully-responsive webpage without using media queries.</p>
<p>In this article, we will explore responsive design beyond the viewport with Container Queries and analyze an example of a fully responsive site using just container queries.</p>
<h2 id="heading-so-what-are-container-queries">So, What are Container Queries?</h2>
<p>Container queries allow you to style HTML elements based on the size of their containers. It is similar in execution to media queries, except elements are styled based on the size of a viewport with media queries.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/container-queries-explanation.png" alt="Image" width="600" height="400" loading="lazy">
<em>Image illustrating Container Queries in CSS</em></p>
<h2 id="heading-how-to-use-container-queries">How to Use Container Queries</h2>
<h3 id="heading-the-containment-context">The containment context</h3>
<p>To use container queries, you need to tell the browser which HTML element you wish to use as a container. We do this by declaring a “containment context”. </p>
<p>A containment context instructs the browser to start paying attention to the size of a container (or an element). This way, the browser knows when to apply the styles specified in your container query.</p>
<p>To declare a containment context, we use the <code>container-type</code> property with a value of <code>size</code>, <code>inline-size</code>, or <code>normal</code>. See the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/container-type">container-type</a> API reference to understand what each of these values means.</p>
<p>Consider the following example of a soft drink card component below:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"drink-card-container"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"drink-card"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"images/coke.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"info"</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">div</span>&gt;</span>
</code></pre>
<p>We can then add a containment context to the container:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.drink-card-container</span> {
  <span class="hljs-attribute">container-type</span>: inline-size; 
}
</code></pre>
<p>And now, the browser pays attention to the size of <code>.drink-card-container</code>. Although, we still need to apply specific styles based on this container size, so we need the <code>@container</code> at-rule.</p>
<h3 id="heading-the-container-at-rule">The <code>@container</code> at-rule</h3>
<p>The <code>@container</code> at-rule allows you to style elements based on the size of their container. The container condition is evaluated when the container changes in size. Also, the @container at-rule is what primarily defines a container query. It takes this form:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@container</span> &lt;container-condition&gt; {
  &lt;<span class="hljs-selector-tag">stylesheet</span>&gt;
}
</code></pre>
<p>It has a similar syntax to the <code>@media</code> at-rule in media queries.</p>
<p>Recall our soft drink card example. We can now add a <code>@container</code> at-rule that modifies the <code>flex-direction</code> of our <code>.drink-card</code> when the container’s size is less than or equal to <code>450px</code>.</p>
<pre><code class="lang-css"><span class="hljs-keyword">@container</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">450px</span>) {
  <span class="hljs-selector-class">.drink-card-container</span> <span class="hljs-selector-class">.drink-card</span> {
    <span class="hljs-attribute">flex-direction</span>: column;
  }
}
</code></pre>
<p>And that’s it! That’s all you need to know to start using container queries.</p>
<h3 id="heading-the-container-name-property">The container-name property</h3>
<p>Now that you know how container queries work, let's think about it at scale—what happens when we have multiple containers or containment contexts to work with? </p>
<p>This introduces the need for specificity when writing container queries, which is why the <code>container-name</code> property exists.</p>
<p>Let’s reconsider the example from our soft drink card component.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"drink-card-container"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"drink-card"</span>&gt;</span>
    . . .
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"info"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Coke<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>On May 8, 1886, the first glass of Coke was sold.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h5</span>&gt;</span>₦ 150 <span class="hljs-tag">&lt;<span class="hljs-name">sup</span>&gt;</span>estimated RRP<span class="hljs-tag">&lt;/<span class="hljs-name">sup</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"&lt;https://www.coca-cola.com/&gt;"</span>&gt;</span>See Official Website<span class="hljs-tag">&lt;/<span class="hljs-name">a</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">div</span>&gt;</span>
</code></pre>
<p>We can then add a containment context to the <code>.info</code> element by giving it a <code>container-type</code> property, as we did earlier. But this time, we include a <code>container-name</code> property to give the container a specific identity.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.info</span> {
  <span class="hljs-attribute">container-type</span>: inline-size;
  <span class="hljs-attribute">container-name</span>: drink-info;
}
</code></pre>
<p>Our container query will then take this shape:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@container</span> drink-info (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">200px</span>) {
  <span class="hljs-selector-class">.info</span> <span class="hljs-selector-tag">p</span> {
    <span class="hljs-attribute">display</span>: none;
  }
}
</code></pre>
<p>The code above tracks the size of the <code>.info</code> container (named <code>drink-info</code>) and hides the paragraph element when the container’s size is less than or equal to <code>200px</code>.</p>
<h2 id="heading-source-code-for-a-responsive-site-using-only-container-queries">Source Code for a Responsive Site Using Only Container Queries</h2>
<p>To access the complete source code where all of the snippets in this article were extracted, you can visit this <a target="_blank" href="https://github.com/felixfavour/container-queries">GitHub repository</a>.</p>
<h3 id="heading-live-preview">Live Preview</h3>
<p>You can see a live preview of the GitHub code <a target="_blank" href="https://felixfavour.github.io/container-queries.">here</a>. To see the responsiveness in action, resize the browser window. Alternatively, you can interact with the codepen below.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/felixfavour/embed/ZEqqRyr" 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-browser-compatibility-for-container-queries">Browser Compatibility for Container Queries</h2>
<p>Container queries are available on all the major browser engines and are stable in all modern browsers. This means you can use it today for personal and work projects.</p>
<p>I hope this article helped you learn the basics of container queries. Now, you’re won't be confined to just using media queries—container queries are also a valid way to make your websites responsive.</p>
<p>I hope you found this article helpful. If you did, feel free to connect with me on LinkedIn and check out <a target="_blank" href="http://favourfelix.com/">favourfelix.com</a> to see what else I'm writing and up to.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How Web Pages Get Rendered on the Browser – Different Methods Explained ]]>
                </title>
                <description>
                    <![CDATA[ Today, all over the world, computers and networks are getting faster. This is good for web development and user experience in general. And the possibilities of what people can achieve have taken a massive leap forward. But although growth is evident ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/web-page-rendering-on-the-browser-different-methods/</link>
                <guid isPermaLink="false">66bc54ade35f27b35395073d</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Felix Favour Chinemerem ]]>
                </dc:creator>
                <pubDate>Wed, 26 Oct 2022 22:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/10/fav-poster.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Today, all over the world, computers and networks are getting faster. This is good for web development and user experience in general. And the possibilities of what people can achieve have taken a massive leap forward.</p>
<p>But although growth is evident in many places, others are left behind in this sprint. The big question is how do we level the web experience given this digital divide and make the web more accessible to people with less efficient computers and networks?</p>
<p>In many cases, an answer to this question lies in understanding how we render webpages on the browser.</p>
<h2 id="heading-terms-used-in-this-article">Terms Used in this Article</h2>
<p>Before you go on, I want to make sure you're familiar with the terms used in this article. Some of them might be particularly difficult to grasp for new developers. Feel free to skip to the next section if you are familiar with these already.</p>
<ul>
<li><strong>Server</strong>: A server is a computer that resides in a remote location (mostly the internet). Its job is to handle requests from the client and process a response.</li>
<li><strong>Client</strong>: A client is any device communicating with a server to access resources. A client, in many cases, is any device that can access the internet. In this article, your web browser plays the role of the client.</li>
<li><strong>CDN</strong>: Acronym for Content Delivery Network. A CDN is "a network of interconnected servers that speeds up webpage loading for data-heavy applications" (from <a target="_blank" href="https://aws.amazon.com/what-is/cdn/">AWS</a>).</li>
<li><strong>Build-time</strong>: During build-time, your application code is prepared for another environment. Most times — a hosted environment on the internet.</li>
</ul>
<p>Now let's learn about the different ways websites can be rendered.</p>
<h2 id="heading-what-is-client-side-rendering-csr">What is Client-Side Rendering (CSR)?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/csr.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Client-Side Rendering generates webpages in the browser, fully relying on your JavaScript Code. The browser fully processes your JS code before your web page's content is visible to the user.</p>
<p>Your JavaScript code helps to dynamically define the website's <strong>architecture</strong> as soon as it is downloaded. Architecture in this context means data fetching from an <a target="_blank" href="https://aws.amazon.com/what-is/restful-api/">API</a>, website navigation, and simple business logic on your website.</p>
<h3 id="heading-client-side-rendering-and-javascript-frameworks">Client-Side Rendering  and JavaScript Frameworks</h3>
<p>Client-Side Rendering gained popularity with the release of JavaScript frameworks and libraries like React, Vue and Angular. These frameworks are only functional by including a CDN at the head of an HTML page —  and these CDNs typically contain JS code that is large in size.</p>
<p>It's no secret that large files result in increased download time, but there is a catch here: downloading large files at the initial load of the application means significantly less loading time in accessing other pages on that website.</p>
<p>The website primarily fetches data from an API. This data is then used to populate pages rendered on the client.</p>
<p>You can find common examples of a real-life application that use CSR in many of the Progressive Web Applications (PWA) we use today, like Spotify, Figma, and Google Drive.</p>
<h2 id="heading-what-is-server-side-rendering-ssr">What is Server-Side Rendering (SSR)?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/ssr.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Client-Side Rendering was a game-changer and still is — in many cases. Although, a closer look at performance in CSR showed that the more features a website had, the more JS code it had. Recall that more JS code means more download time.</p>
<p>Heavy downloads during the initial load to ensure faster access to all web pages did not seem like a trade-off some people were willing to make. This gave rise to Server-Side rendering.</p>
<p>SSR doesn't solve all the problems of rendering on the web. But it solved many of the issues faced by CSR like faster load times on initial visit and a few others highlighted in the Benefits and Trade-offs section of this article.</p>
<p>Server-Side Rendering helps generate a webpage on the server just after receiving a request from the browser. With SSR, the server renders the full HTML, CSS, and JavaScript required for the requested resource and sends it back to the browser.</p>
<p>This means you can always be sure that the website content contains the most recent information from the server. You can think of it as an integration of a <a target="_blank" href="https://aws.amazon.com/what-is/restful-api/">REST API</a> — content from the backend is always updated.</p>
<p>Like all other methods of rendering on the web, SSR has its fair share of drawbacks. For one, having to make network requests to the server to load a webpage could impact users with less internet bandwidth. SSR also requires a relatively higher volume of computing power to be active.</p>
<h2 id="heading-what-is-static-site-generation-ssg">What is Static Site Generation (SSG)?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/ssg.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Static Site Generation is a very common approach to rendering on the web. This is because most websites, if not all before JavaScript frameworks, were statically generated.</p>
<p>Static sites are still very popular, but there are better ways to generate them. This goes to show how important they are in terms of performance on the web.</p>
<h3 id="heading-but-what-is-a-static-site">But, What is a Static Site?</h3>
<p>A static site is rendered on a browser exactly how it was generated. The content of a static site is typically unaffected by the user viewing, unlike a web app rendered in CSR, or SSR, where each user can see content based on authentication or authorization.</p>
<p>Static sites are ideal for showing content that never changes or is updated once in a while.</p>
<h3 id="heading-static-site-generation-explained">Static Site Generation Explained</h3>
<p>Static Site Generation largely involves automating the process of building webpages. JavaScript frameworks today (like Nuxt.js, Next.js, and so on), provide template engines for building multiple static webpages with one template. As you can imagine, this saves time.</p>
<p>Static Site Generation is different from SSR and CSR in the sense that your HTML webpages are rendered and generated during build-time — before the user attempts to access your webpage. This is why SSG is commonly referred to as pre-rendering. It does the hard work beforehand.</p>
<p>Though SSG seems all bliss, there are tradeoffs. A major drawback of rendering with SSG is that a page must be generated for every accessible URL on your website. This could get even more tedious when you have <a target="_blank" href="https://nuxtjs.org/docs/directory-structure/pages#dynamic-pages">dynamic pages</a>.</p>
<p>Recall that static sites are ideal for showing content that rarely gets updated, so this rendering method doesn't work for all use cases.</p>
<h2 id="heading-benefits-and-trade-offs-of-different-rendering-methods">Benefits and Trade-offs of Different Rendering Methods</h2>
<p>Now that you understand how all these rendering methods generate pages for the browser, we should consolidate all of this information and do some comparisons. </p>
<p>We'll look at the three major metrics — Performance, SEO, and Cost.</p>
<h3 id="heading-performance">Performance</h3>
<p>To build websites that are accessible regardless of the user’s internet or computer speed, we need to consider performance. Performance in this context could be how fast a website loads or fetches data from an API.</p>
<p>The subsequent paragraphs shows how CSR, SSR and SSG translate in terms of performance.</p>
<h4 id="heading-client-side-rendering-performance">Client-side rendering performance</h4>
<p>A client-side-rendered website can be relatively slow to load. This is because JS code is first downloaded and used to generate actual content that users see. </p>
<p>Oftentimes, JS downloads are heavy, especially with JS frameworks. Client-side rendered webpages might also need to make API calls to fetch data from the backend. This increases load time for the user.</p>
<h4 id="heading-server-side-rendering-performance">Server-side rendering performance</h4>
<p>SSR Rendered webpages can be very fast. This is majorly dependent on the server's speed and the user's speed. If both conditions are met, SSR could take an easy win in terms of performance.</p>
<h4 id="heading-static-site-rendering-performance">Static site rendering performance</h4>
<p>Webpages generated with SSG are relatively fast as actual rendering does not take place on the browser. </p>
<p>SSG feeds the browser with content that it requires without extra work. SSG-rendered webpages, like CSR, might also need to make API calls to fetch data from the backend. This also increases load time for the user.</p>
<p>Ultimately, the amount of JavaScript used in a webpage can determine its performance.</p>
<h3 id="heading-search-engine-optimization-seo">Search Engine Optimization (SEO)</h3>
<p>Every website that needs visibility should value Search Engine Optimization. SEO determines how accessible your content is on search engines like Google. It also determines how high you rank in the Search Engine Result Pages (SERPs).</p>
<p>Let's see how all three rendering methods perform when they are indexed by search engines.</p>
<h4 id="heading-csr-search-engine-optimization">CSR Search Engine Optimization</h4>
<p>Webpages rendered with CSR typically have no meaningful content and depend on JS to generate content. The downside is not all web crawlers support JS, so your website might not be indexed properly on search engines.</p>
<h4 id="heading-ssr-search-engine-optimization">SSR Search Engine Optimization</h4>
<p>SSR renders complete webpages with updated content from the server. Webpages rendered with SSR can be crawled and indexed by search engines.</p>
<h4 id="heading-ssg-search-engine-optimization">SSG Search Engine Optimization</h4>
<p>A web crawler very easily crawls webpages generated with SSG. They do not rely on JS to render fully.</p>
<h3 id="heading-cost">Cost</h3>
<p>It’s important that users have the best experience when they visit a website, but the bills don’t pay themselves, so the cumulative cost of this experience has to be as lean as possible.</p>
<p>The three rendering methods do not share the same financial implications. The paragraphs beneath takes a closer look into the cost of using each.</p>
<h4 id="heading-csr-cost">CSR Cost</h4>
<p>Client-Side Rendering runs 100% on the browser. This means no additional cost is incurred.</p>
<h4 id="heading-ssr-cost">SSR Cost</h4>
<p>Server-Side Rendering generates a fully functional webpage remotely on the server. This means extra computing resources and extra costs.</p>
<h4 id="heading-ssg-cost">SSG Cost</h4>
<p>No Cost. Static Website Generation is during build-time. Hence, generated webpages are hosted, and no extra rendering is done on the server.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>When selecting a rendering method, consider your use case and what works best for it based on what you have learned from this article. Different rendering methods are suitable for different kinds of websites.</p>
<p>An e-commerce website developer might choose to go the SSR route or feel more secure using static sites. A web application developer, on the other hand, might not mind a lengthy initial load as long as it means a better experience for the user in the long run.</p>
<p>Whichever rendering method you select, ensure your website is as accessible as possible — beyond conditions you would not necessarily experience. Finally, never forget to stay on a healthy JS diet.</p>
<p>I hope you found this article helpful. If you did, feel free to connect with me on LinkedIn and check out <a target="_blank" href="http://favourfelix.com/">favourfelix.com</a> to see what else I'm writing and up to.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
