<?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[ responsive images - 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[ responsive images - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 28 Jul 2026 11:53:29 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/responsive-images/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Learn CSS Media Queries by Building Three Projects ]]>
                </title>
                <description>
                    <![CDATA[ Today we're going to learn how to use CSS Media Queries to build responsive websites. And we'll practice what we learn by completing three projects. Let's go 🏅 Table of Contents What are CSS Media Queries? Steps to follow The Syntax Practice Projec... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-css-media-queries-by-building-projects/</link>
                <guid isPermaLink="false">66b2096252d7e556f48445f3</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ responsive design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ responsive images ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joy Shaheb ]]>
                </dc:creator>
                <pubDate>Mon, 26 Apr 2021 15:21:29 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/04/FCC-Thumbnail.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Today we're going to learn how to use CSS Media Queries to build responsive websites. And we'll practice what we learn by completing three projects. Let's go 🏅</p>
<h1 id="heading-table-of-contents">Table of Contents</h1>
<ul>
<li><a class="post-section-overview" href="#heading-what-are-css-media-queries">What are CSS Media Queries?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-project">Steps to follow</a></li>
<li><a class="post-section-overview" href="#heading-css-media-query-syntax">The Syntax</a></li>
<li><a class="post-section-overview" href="#heading-lets-build-some-projects-using-css-media-queries">Practice Projects</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<p>Topics to discuss at a glance:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7vrrjohwnmdvbtexg1r2.png" alt="Alt Text" width="2824" height="1743" loading="lazy"></p>
<h2 id="heading-you-can-watch-this-tutorial-on-youtube-as-well-if-you-like">You can watch this tutorial on YouTube as well if you like:</h2>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/HY8q4TD3KGM" 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>
<h1 id="heading-what-are-css-media-queries">What are CSS Media Queries?</h1>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kyjadc0b95rjuzjlcgck.png" alt="Alt Text" width="3080" height="1377" loading="lazy"></p>
<p>CSS Media Queries allow you to create responsive websites across all screen sizes, ranging from desktop to mobile. So you can see why it's important to learn this topic.</p>
<p>Here's a demo of the magic of Media Queries 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bb0qwxrhg0705lvs6ihs.png" alt="Alt Text" width="2679" height="1368" loading="lazy"></p>
<p>We'll build this in project 2 below. This layout is called the <strong>Card Layout</strong>. You can see more Layout Examples <a target="_blank" href="https://csslayout.io/patterns/">here!</a></p>
<h1 id="heading-how-to-set-up-the-project">How to Set Up the Project</h1>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9wa8xgu2o74y2d60cq3g.png" alt="Alt Text" width="2093" height="1051" loading="lazy"></p>
<p>For this project, you need to know little bit of HTML, CSS, and how to work with VS code. Follow along with me -&gt;</p>
<ol>
<li>Create a folder named "Project-1"</li>
<li>Open VS Code</li>
<li>Create <strong>index.html, style.scss,</strong> and <strong>main.js</strong> files</li>
<li>Install Live Server and SASS Compiler</li>
<li>Run Live Server and SASS Compiler</li>
</ol>
<h2 id="heading-html">HTML</h2>
<p>In HTML, write this code inside the body tag 👇</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">"container"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>We also need to see the exact size of our window. Here's a demo of what I mean:</p>
<p><img src="https://media.giphy.com/media/06zg3tXmCsfA6hX5zo/giphy.gif" alt="Demo" width="480" height="330" loading="lazy"></p>
<p>So, write this line inside the html file:</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">"size"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h2 id="heading-what-is-scss">What is SCSS?</h2>
<p>We'll Use SCSS, not CSS. But..... what is SCSS?</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q5a3hp7070ls26dovja2.png" alt="Alt Text" width="1602" height="687" loading="lazy"></p>
<p>SCSS is a pre-processor of CSS which is more powerful than regular CSS. Using SCSS we can -&gt;</p>
<ol>
<li>Nest our selectors like a branch of a tree and better manage our code.</li>
<li>Store various values into variables</li>
<li>Use Mixins to stop code repetition and save time</li>
</ol>
<p>And much more!</p>
<p>In our SCSS, we'll remove our default browser settings, and we'll change box-sizing, font-size, and font-family like this: 👇</p>
<pre><code class="lang-scss">*{
  <span class="hljs-attribute">margin</span> : <span class="hljs-number">0px</span>;
  <span class="hljs-attribute">padding</span> : <span class="hljs-number">0px</span>;
  <span class="hljs-attribute">box-sizing</span> : border-box; 

  <span class="hljs-selector-tag">body</span>{
    <span class="hljs-attribute">font-size</span> : <span class="hljs-number">35px</span>;
    <span class="hljs-attribute">font-family</span> : sans-serif;
  }
}
</code></pre>
<p><strong>Don't forget</strong> to set the <strong>height</strong> of the <strong>.container class.</strong> Otherwise we'll fail to achieve our desired results:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.container</span>{
  <span class="hljs-attribute">height</span> : <span class="hljs-number">100vh</span>;
}
</code></pre>
<p>Remember the additional id we wrote in HTML? We'll style it and position it in our browser here:</p>
<pre><code class="lang-scss"><span class="hljs-selector-id">#size</span> {
  <span class="hljs-attribute">position</span>: absolute;

<span class="hljs-comment">// positioning screen size below our main text</span>
  <span class="hljs-attribute">top</span> : <span class="hljs-number">60%</span>;
  <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;

  <span class="hljs-attribute">transform</span>: translateX(-<span class="hljs-number">50%</span>);

  <span class="hljs-attribute">color</span> : red;
  <span class="hljs-attribute">font-size</span> : <span class="hljs-number">35px</span>;
}
</code></pre>
<h2 id="heading-javascript">JavaScript</h2>
<p>We need to update our screen size inside our id every time we resize our window. So, write this code in your <code>main.js</code> file:</p>
<pre><code class="lang-javascript">
<span class="hljs-comment">// 'screen' is name 👇 of a function</span>
<span class="hljs-built_in">window</span>.onresize = screen;
<span class="hljs-built_in">window</span>.onload = screen;

<span class="hljs-comment">// Function named 'screen' 👇</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">screen</span>(<span class="hljs-params"></span>) </span>{
  Width = <span class="hljs-built_in">window</span>.innerWidth;
  <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"size"</span>).innerHTML 
   = <span class="hljs-string">"Width : "</span> + Width + <span class="hljs-string">" px"</span> 
}
</code></pre>
<h2 id="heading-download-the-images-for-the-project">Download the images for the project</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u72rvfe5181640ikqa32.png" alt="Alt Text" width="1694" height="693" loading="lazy"></p>
<p>Responsive website also means <strong>Responsive Images</strong>. So we're also going to make our images responsive in this project. The images are on my <strong><a target="_blank" href="https://github.com/JoyShaheb/Project-image-repo/tree/main/Media-Query-Project">GitHub repository</a></strong>. Here's how to get them:</p>
<ol>
<li>Visit and copy the link above ☝️</li>
<li>Go to <strong><a target="_blank" href="https://minhaskamal.github.io/DownGit/#/home">downgit</a></strong> and paste the link you copied</li>
<li>Follow the steps in this video 👇</li>
</ol>
<p><img src="https://cloud.githubusercontent.com/assets/5456665/17822364/940bded8-6678-11e6-9603-b84d75bccec1.gif" alt="Down Git Steps to follow" width="984" height="538" loading="lazy"></p>
<p>And.... we're all set! Let's start coding. 😊</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u5qj78v41btdq7sewdzs.png" alt="Alt Text" width="1794" height="714" loading="lazy"></p>
<h1 id="heading-css-media-query-syntax">CSS Media Query Syntax</h1>
<p>Here's the syntax of a Media Query:</p>
<pre><code class="lang-scss"><span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (max-width: <span class="hljs-number">768px</span>){
  <span class="hljs-selector-class">.container</span>{
   <span class="hljs-comment">//Your code's here</span>
  }
}
</code></pre>
<p>And here's an illustrated explanation -&gt;</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e1wvg9w8co1hq3d24uxi.png" alt="Alt Text" width="2053" height="1281" loading="lazy"></p>
<p>Let's divide the syntax into four sections:</p>
<ol>
<li>Media Query Declaration</li>
<li>The Media Type</li>
<li>min-width &amp; max-width Functions</li>
<li>The Code itself</li>
</ol>
<h3 id="heading-to-understand-all-4-section-of-the-syntax-lets-start-our-first-project">To understand all 4 section of the syntax, let's start our <strong>First Project</strong>:</h3>
<p><img src="https://media.giphy.com/media/t4QOOfmnupAqnHcI9H/giphy.gif" alt="Project-1 Video" width="480" height="330" loading="lazy"></p>
<p>We'll build this. ☝️ It's a small project where the background-color changes on resizing the window by taking one small step at a time. Let's start!</p>
<h3 id="heading-the-html">The HTML</h3>
<p>Place the following code inside your HTML, like this:</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">"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">"text"</span>&gt;</span>
      Hello Screen !
   <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>
<h3 id="heading-the-scss">The SCSS</h3>
<p>Now, we'll store four color codes inside variables like this:👇</p>
<pre><code class="lang-scss"><span class="hljs-variable">$color-1</span> : <span class="hljs-number">#cdb4db</span> ; <span class="hljs-comment">// Mobile</span>
<span class="hljs-variable">$color-2</span> : <span class="hljs-number">#fff1e6</span> ; <span class="hljs-comment">// Tablet</span>
<span class="hljs-variable">$color-3</span> : <span class="hljs-number">#52b788</span> ; <span class="hljs-comment">// Laptop</span>
<span class="hljs-variable">$color-4</span> : <span class="hljs-number">#bee1e6</span> ; <span class="hljs-comment">// Desktop</span>
</code></pre>
<p>You can find more colors at <a target="_blank" href="https://coolors.co/palettes/trending">coolors.co</a> if you want to choose your own.</p>
<p>Now, at the bottom, target the <code>.container</code> and <code>.text</code> classes. We'll also center our text like this👇</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.container</span>{
<span class="hljs-comment">//To place text at center</span>

  <span class="hljs-attribute">display</span> : grid;
  place-items : center;

  <span class="hljs-attribute">background-color</span> : <span class="hljs-variable">$color-1</span>;
  <span class="hljs-attribute">height</span> : <span class="hljs-number">100vh</span>;
}

<span class="hljs-selector-class">.text</span>{
 <span class="hljs-comment">// keep it blank for now</span>
}
</code></pre>
<p>So far so good!</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/grc7r9mbpw7yvoisgj6c.png" alt="Alt Text" width="1388" height="586" loading="lazy"></p>
<h2 id="heading-1-how-to-declare-media-queries">1. How to declare media queries</h2>
<p>Media Queries start with the <code>@media</code> declaration. The main purpose of writing this is to <strong>tell the browser</strong> that we have specified a media query. In your CSS, write it like this:👇</p>
<pre><code class="lang-scss"><span class="hljs-keyword">@media</span>
</code></pre>
<h2 id="heading-2-how-to-set-the-media-type">2. How to Set the Media Type</h2>
<p>This is used to specify the nature of the device we're working with. The four values are:</p>
<ul>
<li>all</li>
<li>print</li>
<li>screen</li>
<li>speech</li>
</ul>
<p>Here's the purpose of each of the values at a glance 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ea8yqchxnmdlqyq9es0m.png" alt="Alt Text" width="1739" height="799" loading="lazy"></p>
<p>We declare the <strong>media type</strong> after the <code>@media</code> declaration, like this:</p>
<pre><code class="lang-scss"><span class="hljs-keyword">@media</span> screen
</code></pre>
<h2 id="heading-why-do-we-write-the-and-operator">Why do we write the "and" operator?</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t8qezvhk9m896ns97jta.png" alt="Alt Text" width="1416" height="642" loading="lazy"></p>
<p>Let's say we're placing an order at a restaurant, "A burger <strong>and</strong> a pizza". Notice that the two orders are separated by <strong>[and]</strong>.</p>
<p>Likewise, the media type, min-width, and max-width functions are basically conditions we are giving to the browser. We don't write the <strong>"and"</strong> operator if we have one condition. Like this -&gt;</p>
<pre><code class="lang-scss"><span class="hljs-keyword">@media</span> screen {
  <span class="hljs-selector-class">.container</span>{
     <span class="hljs-comment">// Your code here </span>
  }
}
</code></pre>
<p>We write the <strong>and</strong> operator if we have two conditions, like this:</p>
<pre><code class="lang-scss"><span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (max-width : <span class="hljs-number">768px</span>) {
  <span class="hljs-selector-class">.container</span>{
     <span class="hljs-comment">// Your code here </span>
  }
}
</code></pre>
<p>You can also skip the media type and work with just min-width &amp; max-width, like this:</p>
<pre><code class="lang-scss"><span class="hljs-comment">//Targeting screen sizes between 480px &amp; 768px </span>

<span class="hljs-keyword">@media</span> (min-width : <span class="hljs-number">480px</span>) <span class="hljs-keyword">and</span> (max-width : <span class="hljs-number">768px</span>) {
  <span class="hljs-selector-class">.container</span>{
     <span class="hljs-comment">// Your code here </span>
  }
}
</code></pre>
<p>If you have three conditions or more, you can use a <strong>comma</strong>, like this:</p>
<pre><code class="lang-scss"><span class="hljs-comment">//Targeting screen sizes between 480px &amp; 768px </span>

<span class="hljs-keyword">@media</span> screen, (min-width : <span class="hljs-number">480px</span>) <span class="hljs-keyword">and</span> (max-width : <span class="hljs-number">768px</span>) {
  <span class="hljs-selector-class">.container</span>{
     <span class="hljs-comment">// Your code here </span>
  }
}
</code></pre>
<h2 id="heading-3-how-to-use-the-min-width-amp-max-width-functions">3. How to Use the min-width &amp; max-width Functions</h2>
<p>Let's discuss the Most important component of a media query, screen breakpoints.</p>
<p>To be honest, there's no such thing as a standard screen break-point guide because there are so many screen sizes on the market. But, for our project, we'll follow <a target="_blank" href="https://getbootstrap.com/docs/5.0/layout/breakpoints/">The Official Bootstrap 5</a> screen break-point values. Here they are:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7pqqlkxksxgouje83vhw.png" alt="Alt Text" width="1739" height="1016" loading="lazy"></p>
<p>Here's a list of every device screen resolution on <a target="_blank" href="https://css-tricks.com/snippets/css/media-queries-for-standard-devices/">CSS-Tricks</a>.</p>
<h3 id="heading-the-max-width-function">The max-width function:</h3>
<p>Using this function, we are creating a boundary. This will work as long as we are <strong>inside the boundary</strong>. Here's a sample 👇</p>
<p>Our Boundary is 500px:</p>
<p><img src="https://media.giphy.com/media/50L0raPo5ZSdxCOlmP/giphy.gif" alt="max-width" width="480" height="336" loading="lazy"></p>
<p>Notice how the light purple color gets <strong>Disabled</strong> when we hit above 500px.</p>
<p>To recreate this, write this code in SCSS:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.container</span>{
  <span class="hljs-attribute">background-color</span>: white ;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">display</span>: grid;
  place-items: center;
}
</code></pre>
<p>At the bottom, insert the media query like this 👇</p>
<pre><code class="lang-scss"><span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (max-width : <span class="hljs-number">500px</span>){
  <span class="hljs-selector-class">.container</span>{
    <span class="hljs-attribute">background-color</span>: <span class="hljs-variable">$color-1</span>;
  }
}
</code></pre>
<h3 id="heading-the-min-width-function">The min-width function:</h3>
<p>We are also creating a boundary here. But this will work if we go <strong>outside the boundary</strong>. Here's a sample: 👇</p>
<p>Our boundary is 500px:</p>
<p><img src="https://media.giphy.com/media/iThpfWPRTBSQXn2gpO/giphy.gif" alt="Min-width" width="480" height="336" loading="lazy"></p>
<p>Notice how the light purple color gets <strong>enabled</strong> after we hit above 500px width.</p>
<p>To recreate this, write this code in SCSS:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.container</span>{
  <span class="hljs-attribute">background-color</span>: white ;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">display</span>: grid;
  place-items: center;
}
</code></pre>
<p>At the bottom, insert the media query like this: 👇</p>
<pre><code class="lang-scss"><span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (min-width : <span class="hljs-number">500px</span>){
  <span class="hljs-selector-class">.container</span>{
    <span class="hljs-attribute">background-color</span>: <span class="hljs-variable">$color-1</span>;
  }
}
</code></pre>
<p>To sum it up, remember that:</p>
<ul>
<li><strong>max-width</strong> sets styles inside the set boundary</li>
</ul>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/227jg6drq6faqc47e2ox.png" alt="Alt Text" width="999" height="560" loading="lazy"></p>
<ul>
<li><strong>min-width</strong> sets styles outside the set boundary</li>
</ul>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e8ds85udh6l20hdh6lbm.png" alt="Alt Text" width="999" height="560" loading="lazy"></p>
<h2 id="heading-the-code-itself">The code itself</h2>
<p>Let's put our first project together!</p>
<p>We will have four screen breakpoints:</p>
<ul>
<li>Mobile  -&gt; 576px</li>
<li>Tablet  -&gt; 768px</li>
<li>Laptop  -&gt; 992px</li>
<li>Desktop -&gt; 1200px</li>
</ul>
<p>Yes, we are following the official <a target="_blank" href="https://getbootstrap.com/docs/5.0/layout/breakpoints/">bootstrap 5</a> screen breakpoints. And each breakpoint will get these colors:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d42pdgggmovcrsq8p61n.png" alt="Alt Text" width="1065" height="540" loading="lazy"></p>
<p>For four device types, we will have four Media Queries. Before touching the media queries, first let's store the breakpoint values in variables, like this:</p>
<p><strong>Note:</strong> Don't forget to add the <strong>$</strong> sign:</p>
<pre><code class="lang-scss"><span class="hljs-variable">$mobile</span>  : <span class="hljs-number">576px</span>;
<span class="hljs-variable">$tablet</span>  : <span class="hljs-number">768px</span>;
<span class="hljs-variable">$laptop</span>  : <span class="hljs-number">992px</span>; 
<span class="hljs-variable">$desktop</span> : <span class="hljs-number">1200px</span>;
</code></pre>
<p>And our <code>.container</code> class should look like this:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.container</span>{
  <span class="hljs-attribute">background-color</span>: white ;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">display</span>: grid;
  place-items: center;
}
</code></pre>
<p>We're all 50% done! Now let's setup the four media queries.</p>
<h2 id="heading-but-wait">But Wait...</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/net2cuugxdaz9idwbwhl.png" alt="Alt Text" width="1488" height="600" loading="lazy"></p>
<p>You need to follow the proper order while writing the media queries. Start writing from the <strong>largest display to the smallest display.</strong></p>
<h3 id="heading-first-breakpoint-for-desktop-1200px">First breakpoint for desktop – 1200px</h3>
<p>For the desktop screen, write this code in SCSS:👇</p>
<pre><code class="lang-scss"><span class="hljs-comment">// using variable here which is  👇 1200px</span>
<span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (max-width: <span class="hljs-variable">$desktop</span>){
  <span class="hljs-selector-class">.container</span>{
    <span class="hljs-attribute">background-color</span>: <span class="hljs-variable">$color-4</span>;
  }
}
</code></pre>
<p>And here's the result:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w1cuuy0m4zw57sh9zdzf.png" alt="Alt Text" width="1231" height="837" loading="lazy"></p>
<h3 id="heading-second-breakpoint-for-laptop-992px">Second breakpoint for laptop – 992px</h3>
<p>For laptop screens, write this code in SCSS: 👇</p>
<pre><code class="lang-scss"><span class="hljs-comment">// using variable here which is  👇 992px</span>
<span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (max-width: <span class="hljs-variable">$laptop</span>){
  <span class="hljs-selector-class">.container</span>{
    <span class="hljs-attribute">background-color</span>: <span class="hljs-variable">$color-3</span>;
  }
}
</code></pre>
<p>And here's the result:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fng9y622xtb9pa6ngfwj.png" alt="Alt Text" width="1234" height="850" loading="lazy"></p>
<h3 id="heading-third-breakpoint-for-tablet-768px">Third breakpoint for tablet – 768px</h3>
<p>For tablets screens, write this code in SCSS: 👇</p>
<pre><code class="lang-scss"><span class="hljs-comment">// using variable here which is  👇 768px</span>
<span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (max-width: <span class="hljs-variable">$tablet</span>){
  <span class="hljs-selector-class">.container</span>{
    <span class="hljs-attribute">background-color</span>: <span class="hljs-variable">$color-2</span>;
  }
}
</code></pre>
<p>And here's the result:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7wqp9xjt4gg272pc3hkt.png" alt="Alt Text" width="1233" height="847" loading="lazy"></p>
<h3 id="heading-fourth-breakpoint-for-mobile-576px">Fourth breakpoint for mobile – 576px</h3>
<p>For mobile screens, write this code in SCSS: 👇</p>
<pre><code class="lang-scss"><span class="hljs-comment">// using variable here which is  👇 576px</span>
<span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (max-width : <span class="hljs-variable">$mobile</span>){
  <span class="hljs-selector-class">.container</span>{
    <span class="hljs-attribute">background-color</span>: <span class="hljs-variable">$color-1</span>;
  }
}
</code></pre>
<p>And here's the result:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z10764qm7cjjc8a2yb7j.png" alt="Alt Text" width="1233" height="846" loading="lazy"></p>
<h2 id="heading-take-a-break">Take a Break</h2>
<p>Congratulations on completing project 1! Now <strong>take a break. You deserve it.</strong></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p6j0uyekswj04ag3p2cl.png" alt="Alt Text" width="1543" height="657" loading="lazy"></p>
<h1 id="heading-lets-build-some-projects-using-css-media-queries">Let's build some projects using CSS Media Queries</h1>
<h2 id="heading-how-to-build-a-responsive-portfolio">How to Build a Responsive Portfolio</h2>
<p>We'll build a small responsive Website for our second project.</p>
<h3 id="heading-heres-what-the-desktop-view-will-look-like">Here's what the desktop view will look like:</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ay01oqdseulalsw3gpdh.png" alt="Alt Text" width="1631" height="913" loading="lazy"></p>
<h3 id="heading-and-heres-the-mobile-view">And here's the mobile view:</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hob05vxov52hrm5quz0a.png" alt="Alt Text" width="738" height="1187" loading="lazy"></p>
<p>Okay then, let's start coding! First, let's work with the desktop view by taking small baby steps.</p>
<h3 id="heading-before-we-start">Before we start</h3>
<p>Create a folder named 'images' inside our Project-1 Folder. Place all the images you downloaded from my <a target="_blank" href="https://github.com/JoyShaheb/Project-image-repo/tree/main/Media-Query-Project">GitHub Repository</a> inside the images folder.</p>
<h2 id="heading-the-html-1">The HTML</h2>
<h3 id="heading-step-1-create-the-sections">Step 1 – Create the sections</h3>
<p>We'll create three sections for our website. Write this code in your HTML:</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">"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">"header"</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">class</span>=<span class="hljs-string">"main"</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">class</span>=<span class="hljs-string">"footer"</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>
<h3 id="heading-step-2-logo-and-menu-items">Step 2 – Logo and menu items</h3>
<p>We'll place the logo and menu items inside the .header div, like this:</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">"header"</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header__logo"</span>&gt;</span>Miya Ruma<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">class</span>=<span class="hljs-string">"header__menu"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header__menu-1"</span>&gt;</span> Home <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">class</span>=<span class="hljs-string">"header__menu-2"</span>&gt;</span> Portfolio <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">class</span>=<span class="hljs-string">"header__menu-3"</span>&gt;</span> Contacts <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>
<h3 id="heading-step-3-image-and-text">Step 3 – Image and text</h3>
<p>We'll place the image and text inside the .main div, like this:</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">"main"</span>&gt;</span>

     <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"main__image"</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">class</span>=<span class="hljs-string">"main__text"</span>&gt;</span>

       <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"main__text-1"</span>&gt;</span>Hello 👋<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">class</span>=<span class="hljs-string">"main__text-2"</span>&gt;</span>I'm <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Miya Ruma<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">class</span>=<span class="hljs-string">"main__text-3"</span>&gt;</span>A Designer From<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">class</span>=<span class="hljs-string">"main__text-4"</span>&gt;</span>Tokyo, Japan<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>
<h3 id="heading-step-4-social-media-icons">Step 4 – Social media icons</h3>
<p>We'll place the social media icons inside the .footer div, like this:</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">"footer"</span>&gt;</span>

   <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"footer__instagram"</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/instagram.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>&gt;</span>

   <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"footer__twitter"</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/twitter-sign.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>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"footer__dribbble"</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/dribbble-logo.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>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"footer__behance"</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/behance.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>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h2 id="heading-the-scss-1">The SCSS</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ou3jrlk5g9mjodfh88n.png" alt="Alt Text" width="1488" height="639" loading="lazy"></p>
<h3 id="heading-step-1-update-the-scss">Step 1 – Update the SCSS</h3>
<p>Delete everything inside our SCSS and write this code instead:</p>
<pre><code class="lang-scss">* {
  <span class="hljs-comment">// placing Margin to left &amp; right</span>
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0px</span> <span class="hljs-number">5px</span>;

  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0px</span>;
  <span class="hljs-attribute">box-sizing</span>: border-box;

  <span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">font-family</span>: sans-serif;
  }
}
</code></pre>
<p>This is what we have so far:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3egdxy9f5wf8xgc2ekn8.png" alt="Alt Text" width="608" height="282" loading="lazy"></p>
<h3 id="heading-step-2-select-all-classes-in-html">Step 2 – Select all classes in HTML</h3>
<p>Select all the classes we created in HTML on our stylesheet.</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.container</span>{}

<span class="hljs-selector-class">.header</span>{}

<span class="hljs-selector-class">.main</span>{}

<span class="hljs-selector-class">.footer</span>{}
</code></pre>
<h3 id="heading-step-3-select-all-children">Step 3 – Select all children</h3>
<p>Now select all the children of the parent classes.</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.header</span>{

  &amp;__logo{}

  &amp;__menu{}
}

<span class="hljs-selector-class">.main</span>{

  &amp;__image{}

  &amp;__text{}
}

<span class="hljs-selector-class">.footer</span>{

  <span class="hljs-selector-attr">[class ^="footer__"]</span>{}

}
</code></pre>
<p><strong>Note</strong> that <code>&amp;__logo</code> nested inside <code>.header</code> is a shortcut of <code>.header__logo</code>.</p>
<h3 id="heading-step-4-define-the-container">Step 4 – Define the .container</h3>
<p>Define the <code>.container</code> for the desktop layout, like this:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.container</span>{

<span class="hljs-comment">// Defining height</span>
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;

  <span class="hljs-attribute">display</span>: flex;

  <span class="hljs-attribute">flex-direction</span>: column;
}
</code></pre>
<p>Apply <code>display: flex;</code> to <code>.header</code> and to the menu items so that it behaves like a row, not a column:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.header</span>{
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: row;

  &amp;__logo{}

  &amp;__menu{
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">flex-direction</span>: row;
  }
}
</code></pre>
<p>Divide each section and create borders to see what we are doing:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.header</span>{
  <span class="hljs-attribute">display</span>: flex;

<span class="hljs-comment">// The border &amp; height</span>
  <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid red;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">10%</span>;

<span class="hljs-comment">// Other selectors are here</span>

}

<span class="hljs-selector-class">.main</span>{

<span class="hljs-comment">//The border &amp; height</span>
  <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid black;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">80%</span>;

<span class="hljs-comment">// Other selectors are here</span>

}

<span class="hljs-selector-class">.footer</span>{

<span class="hljs-comment">// Border &amp; height</span>
  <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid green;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">10%</span>;

<span class="hljs-comment">// Other selectors are here</span>
}
</code></pre>
<p>And here's the result:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o77rk1bj2m722jf41mju.png" alt="Alt Text" width="760" height="273" loading="lazy"></p>
<h3 id="heading-step-5-complete-header-styling">Step 5 – Complete .header styling</h3>
<p>Let's complete the styling of our <code>.header</code> section using flex-box properties and the appropriate font-size:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.header</span> {
<span class="hljs-comment">// height</span>
  <span class="hljs-attribute">height</span>: <span class="hljs-number">10%</span>;

  <span class="hljs-attribute">display</span>: flex;
<span class="hljs-comment">// Aligning logo &amp; menu at center</span>
  <span class="hljs-attribute">align-items</span>: center;

<span class="hljs-comment">// space between logo &amp; menu</span>
  <span class="hljs-attribute">justify-content</span>: space-between;

  &amp;__logo {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">4vw</span>;
  }

  &amp;__menu {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2.5vw</span>;

<span class="hljs-comment">// to put gap between menu items</span>
    gap: <span class="hljs-number">15px</span>;
  }
}
</code></pre>
<p>And here's the result:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kx4d43xmeggdaw2h2pdf.png" alt="Alt Text" width="1029" height="183" loading="lazy"></p>
<h3 id="heading-step-6-add-the-image">Step 6 – Add the image</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7tyojtcpe7o1o9mukum6.png" alt="Alt Text" width="1488" height="639" loading="lazy"></p>
<p>Let's add the image inside <code>.main</code> section and create a partition for image and text.</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.main</span> {
  <span class="hljs-comment">// image &amp; text will act like a row</span>
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: row;

  <span class="hljs-comment">//The border &amp; height</span>
  <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid black;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">80%</span>;

  &amp;__image {
    <span class="hljs-comment">//Adding the image</span>
    <span class="hljs-attribute">background-image</span>: url(<span class="hljs-string">"./images/Portrait.png"</span>);
    <span class="hljs-comment">// will cover half of screen width</span>
    <span class="hljs-attribute">width</span>: <span class="hljs-number">50%</span>;
  }

  &amp;__text {
    <span class="hljs-comment">// will cover half of screen width</span>
    <span class="hljs-attribute">width</span>: <span class="hljs-number">50%</span>;
  }
}
</code></pre>
<p>The result is a bit ugly at the moment, but don't lose hope~</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2q13at8wcniamqpwh7jv.png" alt="Alt Text" width="1207" height="622" loading="lazy"></p>
<h3 id="heading-step7-make-the-image-responsive">Step7 – Make the image responsive</h3>
<p>Style the image to be responsive like this:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.main</span>{
  &amp;__image{
  <span class="hljs-comment">//make image fluid</span>
    <span class="hljs-attribute">background-size</span>: contain;

  <span class="hljs-comment">// stop image repetition</span>
    <span class="hljs-attribute">background-repeat</span>: no-repeat;

  <span class="hljs-comment">// position the image</span>
    <span class="hljs-attribute">background-position</span>: left center;
  }
}
</code></pre>
<p>And here's what we have so far:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/24r955u9wwww9vdwwhk5.png" alt="Alt Text" width="1408" height="778" loading="lazy"></p>
<p>The image is responsive all the way from <strong>4k</strong> to your <strong>smart watch screen</strong>. Don't believe me? Open chrome developer tools and test it yourself and see.</p>
<p>You can learn more about <a target="_blank" href="https://www.freecodecamp.org/news/learn-css-background-properties/">Background Properties here</a> if you want to make responsive images for responsive websites.</p>
<p><img src="https://media.giphy.com/media/7Us5yEqyNW6IkOR1fs/giphy.gif" alt="4k test" width="480" height="270" loading="lazy"></p>
<h3 id="heading-step-8-style-the-text">Step 8 – Style the text</h3>
<p>Let's style our text now. First, we'll bring it to the exact center with this code:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.main</span>{

  &amp;__text {
    <span class="hljs-comment">// will cover half of screen width</span>
    <span class="hljs-attribute">width</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">flex-direction</span>: column;

<span class="hljs-comment">// To bring it at the center </span>
    <span class="hljs-attribute">justify-content</span>: center;
    <span class="hljs-attribute">align-items</span>: center;
  }

<span class="hljs-comment">// To color The name </span>
  <span class="hljs-selector-tag">span</span>{
    <span class="hljs-attribute">color</span>: red;
  }

}
</code></pre>
<p>Now, let's set font sizes for the text:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.main</span>{


  &amp;__text{

<span class="hljs-comment">// To add gaps between texts vertically</span>
    gap: <span class="hljs-number">15px</span>;

<span class="hljs-comment">// font size for "hello"</span>
    &amp;-1{
      <span class="hljs-attribute">font-size</span>: <span class="hljs-number">10vw</span>;
    }

<span class="hljs-comment">// font size for other texts</span>
    &amp;-2,&amp;-3,&amp;-4{
      <span class="hljs-attribute">font-size</span>: <span class="hljs-number">5vw</span>;

    }

  }
}
</code></pre>
<p>The result looks like this:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kne4bezy1ft0ro6ore0p.png" alt="Alt Text" width="1089" height="523" loading="lazy"></p>
<p>At this point, you can remove all the borders we placed inside our header, main, and footer classes.</p>
<h3 id="heading-step-9-the-footer-section">Step 9 – The footer section</h3>
<p>First, resize the images like this:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.footer</span>{
  <span class="hljs-selector-attr">[class^="footer__"]</span> {
    <span class="hljs-selector-tag">img</span> {
      <span class="hljs-attribute">width</span>: <span class="hljs-number">5.3vw</span>;
    }
  }
}
</code></pre>
<p>Then, position the images to our desired place, with a small gap between the icons, like this:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.footer</span>{
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: row;

<span class="hljs-comment">// To align icons along x-axis</span>
  <span class="hljs-attribute">align-items</span>: center;
<span class="hljs-comment">// placing image to the right side</span>
  <span class="hljs-attribute">justify-content</span>: flex-end;
<span class="hljs-comment">// Gap between icons</span>
  gap: <span class="hljs-number">20px</span>;

<span class="hljs-comment">// margin to right side of icons </span>
  <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">10%</span>;
}
</code></pre>
<p>And here's the result, without the guides:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/itzk2rwz621vjm1k833c.png" alt="Alt Text" width="1631" height="913" loading="lazy"></p>
<h3 id="heading-step-10-the-mobile-layout">Step 10 – The mobile layout</h3>
<p>We're almost there...</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9w8h1owma15wmrzqb5cd.png" alt="Alt Text" width="1541" height="639" loading="lazy"></p>
<p>Create a media query at the 650px mark and style the <code>.header</code> class like this:</p>
<pre><code class="lang-scss"><span class="hljs-keyword">@media</span> (max-width: <span class="hljs-number">650px</span>) {

  <span class="hljs-selector-class">.header</span> {

<span class="hljs-comment">// To place logo at center</span>
    <span class="hljs-attribute">justify-content</span>: center;

    &amp;__logo {
      <span class="hljs-attribute">font-size</span>: <span class="hljs-number">40px</span>;
    }
<span class="hljs-comment">//hiding the menu on mobile device</span>
    &amp;__menu {
      <span class="hljs-attribute">display</span>: none;
    }
  }
}
</code></pre>
<h3 id="heading-step-11-center-main">Step 11 – Center .main</h3>
<p>Now, place the .main section at the exact center with this code:</p>
<pre><code class="lang-scss"><span class="hljs-keyword">@media</span> (max-width: <span class="hljs-number">650px</span>){
<span class="hljs-comment">// styles of header section of step-10...</span>

<span class="hljs-comment">// main section here </span>
  <span class="hljs-selector-class">.main</span> {
    <span class="hljs-attribute">flex-direction</span>: column;
    <span class="hljs-attribute">justify-content</span>: center;
    <span class="hljs-attribute">align-items</span>: center;
}
</code></pre>
<h3 id="heading-step-12-style-the-image-and-text-for-mobile">Step 12 – Style the image and text for mobile</h3>
<p>Style the image and text for mobile layout like this:</p>
<pre><code class="lang-scss"><span class="hljs-keyword">@media</span> (max-width: <span class="hljs-number">650px</span>){

 <span class="hljs-selector-class">.main</span> {
   &amp;__image {
<span class="hljs-comment">// Image size </span>
      <span class="hljs-attribute">height</span>: <span class="hljs-number">200px</span>;
      <span class="hljs-attribute">width</span>: <span class="hljs-number">200px</span>;
      <span class="hljs-attribute">background-size</span>: <span class="hljs-number">100%</span>;

<span class="hljs-comment">// To have rounded image </span>
      <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">100%</span>;
      <span class="hljs-attribute">background-position</span>: center;
    }

<span class="hljs-comment">// Styles for the text -&gt;</span>
    &amp;__text {
      <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;

      &amp;-1 {
        <span class="hljs-attribute">display</span>: none;
      }
      &amp;-2, &amp;-3, &amp;-4 {
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">30px</span>;
      }
    }
}
</code></pre>
<h3 id="heading-step-13-style-the-footer-for-mobile">Step 13 – Style the footer for mobile</h3>
<p>The last step is to style the footer section for the mobile layout:</p>
<pre><code class="lang-scss"><span class="hljs-keyword">@media</span> (max-width: <span class="hljs-number">650px</span>){
  <span class="hljs-selector-class">.footer</span> {
<span class="hljs-comment">// placing icons along the X-axis</span>
    <span class="hljs-attribute">justify-content</span>: center;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0px</span>;

    <span class="hljs-selector-attr">[class^="footer__"]</span> {

<span class="hljs-comment">// Resizing images for mobile layout</span>
      <span class="hljs-selector-tag">img</span> {
        <span class="hljs-attribute">width</span>: <span class="hljs-number">45px</span>;
        <span class="hljs-attribute">height</span>: <span class="hljs-number">45px</span>;
      }
    }
  }
}
</code></pre>
<p>And here's our result:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7dxzqtz8it2xhzpxf4ll.png" alt="Alt Text" width="738" height="1187" loading="lazy"></p>
<h2 id="heading-take-a-break-1">Take a break</h2>
<p>Good job so far! Take a break before moving on to the next project. 😊</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hdd7i01tivcfgg4nki0m.png" alt="Alt Text" width="899" height="383" loading="lazy"></p>
<h2 id="heading-project-3-how-to-build-a-card-layout">Project 3 – How to Build a Card Layout</h2>
<p>In project 3, we'll build this:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tf2o5njarct4ew24dnqj.png" alt="Alt Text" width="2679" height="1368" loading="lazy"></p>
<p>So let's start.</p>
<h2 id="heading-the-scss-2">The SCSS</h2>
<p>On your stylesheet, delete everything except the styles of <code>#size</code>. And then add this code there:</p>
<pre><code class="lang-scss">* {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0px</span> <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">box-sizing</span>: border-box;

  <span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">font-family</span>: sans-serif;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">55px</span>;
  }
}

<span class="hljs-selector-id">#size</span>{
  <span class="hljs-attribute">position</span>: absolute;
<span class="hljs-comment">// Positioning the text</span>
  <span class="hljs-attribute">top</span>: <span class="hljs-number">60%</span>;
  <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">transform</span>: translateX(-<span class="hljs-number">50%</span>);
<span class="hljs-comment">// color &amp; size of text</span>
  <span class="hljs-attribute">color</span>: red;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">40px</span>;
}
</code></pre>
<h2 id="heading-the-html-2">The HTML</h2>
<p>Your HTML should look like this inside the body tags: 👇</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">"container"</span>&gt;</span> 
   // We'll place code here
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

// This will show our window width Live 
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"size"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Now, create three classes with class names <code>.row-*</code> like this 👇 inside <code>.container</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">"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">"row-1"</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">class</span>=<span class="hljs-string">"row-2"</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">class</span>=<span class="hljs-string">"row-3"</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>Each row will have three boxes with class names <code>.box-*</code> like this. 👇 And yes, you'll insert letters inside the boxes:</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">"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">"row-1"</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"box-1"</span>&gt;</span>A<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">class</span>=<span class="hljs-string">"box-2"</span>&gt;</span>B<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">class</span>=<span class="hljs-string">"box-3"</span>&gt;</span>C<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> <span class="hljs-attr">class</span>=<span class="hljs-string">"row-2"</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"box-4"</span>&gt;</span>D<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">class</span>=<span class="hljs-string">"box-5"</span>&gt;</span>E<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">class</span>=<span class="hljs-string">"box-6"</span>&gt;</span>F<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> <span class="hljs-attr">class</span>=<span class="hljs-string">"row-3"</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"box-7"</span>&gt;</span>G<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">class</span>=<span class="hljs-string">"box-8"</span>&gt;</span>H<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">class</span>=<span class="hljs-string">"box-9"</span>&gt;</span>I<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're done with the HTML part, and the result should look like this: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u3jg1iphmhefdpn8gy12.png" alt="Alt Text" width="1233" height="669" loading="lazy"></p>
<h2 id="heading-the-scss-3">The SCSS</h2>
<p>Follow these small baby steps one by one to style the project.</p>
<h3 id="heading-step-1-add-some-scss-code">Step 1 – Add some SCSS code</h3>
<p>To select and style all the boxes and rows together, this is what we write in our CSS: 👇</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.container</span>{
  <span class="hljs-comment">// styles here </span>
}

<span class="hljs-selector-attr">[class ^="row-"]</span>{
  <span class="hljs-comment">// Styles applied on all rows</span>
}

<span class="hljs-selector-attr">[class ^="box-"]</span>{
  <span class="hljs-comment">// Styles applied on all boxes</span>
}
</code></pre>
<h3 id="heading-step-2-make-boxes-behave-like-rows">Step 2 – Make boxes behave like rows</h3>
<p>Boxes should behave like a row. This code will make that happen:</p>
<pre><code class="lang-scss"><span class="hljs-selector-attr">[class ^="row-"]</span>{
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: row;
}
</code></pre>
<p>And here's the result: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4utfjrr1bfmwwh81rb1a.png" alt="Alt Text" width="1155" height="601" loading="lazy"></p>
<h3 id="heading-step-3-define-the-boxes">Step 3 – Define the boxes</h3>
<p>Expand the boxes across the width and height and place the letters at the center.</p>
<pre><code class="lang-scss"><span class="hljs-selector-attr">[class ^="box-"]</span>{

  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#c4c4c4</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid black;

<span class="hljs-comment">// Defining the size of the boxes </span>
  <span class="hljs-attribute">width</span> : (<span class="hljs-number">100%</span>)/<span class="hljs-number">3</span>;
  <span class="hljs-attribute">height</span>: (<span class="hljs-number">100vh</span>)/<span class="hljs-number">3</span>;

<span class="hljs-comment">// Place letter at the center</span>
  <span class="hljs-attribute">display</span>: grid;
  place-items: center;
}
</code></pre>
<p>Here's the result:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g4m7snz4kklns6xjinzh.png" alt="Alt Text" width="1920" height="867" loading="lazy"></p>
<h3 id="heading-step-4-create-gaps-between-rows">Step 4 – Create gaps between rows</h3>
<p>Next we'll create a gap between the rows, like this:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.container</span>{
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;

<span class="hljs-comment">// Creating gap between rows </span>
  gap: <span class="hljs-number">30px</span>;
}
</code></pre>
<p>Now let's create a gap between the boxes:</p>
<pre><code class="lang-scss"><span class="hljs-selector-attr">[class ^="row-"]</span>{
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: row;

<span class="hljs-comment">// Creating gap between boxes</span>
  gap : <span class="hljs-number">30px</span>;
}
</code></pre>
<p>And here's what it looks like:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xpus9dx40nxzysz9iceh.png" alt="Alt Text" width="1894" height="867" loading="lazy"></p>
<h3 id="heading-step-5-set-up-the-mobile-layout">Step 5 – Set up the mobile layout</h3>
<p>Create the media query which will be applied at the 650px mark:</p>
<pre><code class="lang-scss"><span class="hljs-keyword">@media</span> (max-width: <span class="hljs-number">650px</span>){
  <span class="hljs-comment">// We'll write code here</span>
}
</code></pre>
<p>Change the orientation of the boxes on the mobile screen from row to column, and stretch the boxes to 100% of the width with this code:</p>
<pre><code class="lang-scss"><span class="hljs-keyword">@media</span> (max-width: <span class="hljs-number">650px</span>){

<span class="hljs-comment">//Change orientation</span>
  <span class="hljs-selector-attr">[class ^="row-"]</span>{
    <span class="hljs-attribute">flex-direction</span>: column;
  }

<span class="hljs-comment">// Change width of boxes</span>
  <span class="hljs-selector-attr">[class ^="box-"]</span>{
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  }
}
</code></pre>
<p>And here's the final mobile result:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pyis7sloasdv03lljhn9.png" alt="Alt Text" width="1225" height="847" loading="lazy"></p>
<p>By the way, project 2 is a part of <a target="_blank" href="https://www.freecodecamp.org/news/learn-flexbox-build-5-layouts/">this article</a> of mine. If you're interested to learn more and practice both your Flexbox and media query skills, then go for it!</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Here's your medal for reading all the way until the end ❤️</p>
<h3 id="heading-suggestions-and-criticisms-are-highly-appreciated">Suggestions and criticisms are highly appreciated ❤️</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/i/usxsz1lstuwry3jlly4d.png" alt="Alt Text" width="1000" height="245" loading="lazy"></p>
<p><strong>YouTube <a target="_blank" href="https://youtube.com/c/joyshaheb">/ Joy Shaheb</a></strong></p>
<p><strong>Twitter <a target="_blank" href="https://twitter.com/JoyShaheb">/ JoyShaheb</a></strong></p>
<p><strong>Instagram <a target="_blank" href="https://www.instagram.com/joyshaheb/">/ JoyShaheb</a></strong></p>
<h2 id="heading-credits">Credits</h2>
<ul>
<li><a target="_blank" href="https://css-tricks.com/a-complete-guide-to-css-media-queries/">CSS Tricks</a></li>
<li><a target="_blank" href="https://www.pexels.com/photo/woman-wearing-brown-bucket-cap-732425/">Portrait</a> used for the example project</li>
<li><a target="_blank" href="https://www.vecteezy.com/members/joyshaheb/collections/blog-idea-1">Images from Vecteesy</a></li>
<li><a target="_blank" href="https://www.freepik.com/free-vector/cute-panda-hug-boba-milk-tea-cartoon-icon-illustration-animal-drink-icon-concept-premium-flat-cartoon-style_12571361.htm#position=0">Panda</a>,  <a target="_blank" href="https://www.freepik.com/free-vector/kawaii-fast-food-cute-ice-cream-cookie-illustration_5769154.htm#position=1">Ice-cream</a> &amp; <a target="_blank" href="https://www.freepik.com/free-vector/cute-cats-set-funny-character-cartoon-illustration_12566246.htm">Cute Cat</a></li>
<li><a target="_blank" href="https://www.flaticon.com/packs/unicorn-4">Unicorn Pack</a> &amp; <a target="_blank" href="https://www.flaticon.com/packs/kitty-avatars-3">Kitty Avatar</a></li>
<li><a target="_blank" href="https://www.flaticon.com/free-icon/instagram_1384031">instagram</a>,<a target="_blank" href="https://www.flaticon.com/free-icon/twitter-sign_25347">Twitter</a>,<a target="_blank" href="https://www.flaticon.com/free-icon/behance_254383">Behance</a> and <a target="_blank" href="https://www.flaticon.com/free-icon/dribbble-logo_87400">Dribbble icons</a></li>
<li><a target="_blank" href="https://www.freepik.com/free-vector/collection-kawaii-bubble-tea_10048123.htm#position=6">Bubble tea</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ CSS Responsive Image Tutorial: How to Make Images Responsive with CSS ]]>
                </title>
                <description>
                    <![CDATA[ By Cem Eygi The majority of today’s websites are responsive. And if you need to center and align image on those site, you need to learn how to make images fluid or responsive with CSS. I posted a tutorial video that explains how to make a responsive ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/css-responsive-image-tutorial/</link>
                <guid isPermaLink="false">66d45de255db48792eed3f4b</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ responsive design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ responsive images ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 30 Sep 2020 01:28:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9879740569d1a4ca1a40.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Cem Eygi</p>
<p>The majority of today’s websites are responsive. And if you need to <a target="_blank" href="https://www.freecodecamp.org/news/how-to-center-an-image-in-css/">center and align image</a> on those site, you need to learn how to make images fluid or responsive with CSS.</p>
<p>I posted a tutorial video that explains how to make a <a target="_blank" href="https://youtu.be/rKtOarvKeZE">responsive website step by step</a> a couple of weeks ago. In the video we made an image responsive. But in this post, I would like to give a bit more detail about how to make images responsive.</p>
<p>You will also learn some of the general problems that can occur when you're trying to make images responsive – and I will try to explain how to solve them.</p>
<h2 id="heading-how-to-make-images-responsive-with-css">How to Make Images Responsive with CSS</h2>
<h3 id="heading-should-i-use-relative-or-absolute-units">Should I Use Relative or Absolute Units?</h3>
<p>Making an image fluid, or responsive, is actually pretty simple. When you upload an image to your website, it has a default width and height. You can change them both with CSS.</p>
<p>To make an image responsive, you need to give a new value to its width property. Then the height of the image will adjust itself automatically. </p>
<p>The important thing to know is that you should always use relative units for the width property like percentage, rather than absolute ones like pixels.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">500px</span>;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/Animated-GIF-downsized_large.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>For example, if you define a fixed width of 500px, your image won’t be responsive – because the unit is absolute.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">50%</span>;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/Animated-GIF-downsized-1-.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>That’s why you should instead assign a relative unit like 50%. This approach will make your images fluid and they will be able to resize themselves regardless of the screen size.</p>
<h3 id="heading-should-i-use-media-queries">Should I Use Media Queries?</h3>
<p>One of the questions I get asked the most is whether you should use media queries or not.</p>
<p>A media query is another important feature of CSS that helps make a website responsive. I won’t go into further details here but you can read <a target="_blank" href="https://www.freecodecamp.org/news/css-media-queries-breakpoints-media-types-standard-resolutions-and-more/">my other post</a> later to learn how to use media queries in more detail.</p>
<p>The answer to that question is: “it depends”. If you want your image to have different sizes from one device to another, then you will need to use media queries. Otherwise, you won’t.</p>
<p>Now for this example, your image has a 50% width for any kind of screen. But when you want to make it full-size for mobile devices you need to get help from media queries:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@media</span> <span class="hljs-keyword">only</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">480px</span>) {
  <span class="hljs-selector-tag">img</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  }
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/Animated-GIF-downsized-2-.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>So based on the media query rule, any device smaller than 480px will take the full size of the width of the screen.</p>
<p>You can also watch the video version of this post below:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/5MeogG-ZFs8" 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>
<h3 id="heading-why-is-the-max-width-property-not-great">Why is the max-width property not great?</h3>
<p>Another way that developers can make responsive images is the max-width property. However, this is not always the best method to use, because it may not work for every kind of screen size or device.</p>
<p>The first thing to understand before we move on with an example is what exactly the max-width property does.</p>
<p>The max-width property sets a maximum width for an element, which does not allow the width of that element to be larger than its max-width value (but it can be smaller).</p>
<p>For example, if the image has a default width of 500px, and if your screen size has only 360px, then you won’t be able to see the complete image, because there is not enough space:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">500px</span>;  // assume this is the default size
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/Animated-GIF-downsized-3-.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Therefore, you can define a max-width property for the image and set it to 100%, which shrinks the image of 500px to the space of 360px. So you will be able to see the complete image on a smaller size screen.</p>
<p>The good thing is that, since you are using a relative unit, the image will be fluid in any device smaller than 500px.</p>
<p>Unfortunately, the screen size will get somewhat larger than 500px, but the image won’t because it has a default 500px of width. This approach will break the responsiveness of the image.</p>
<p>To fix this, you need to use the width property again, which makes the max-width property useless.</p>
<h3 id="heading-what-about-heights">What about Heights?</h3>
<p>Another common problem you may run across has to do with the height property. Normally, the height of an image automatically resizes itself, so you don’t need to assign a height property to your images (because it kinda breaks the image).</p>
<p>But in some cases, you might have to work with images that must have a fixed-height. So when you assign a fixed height to the image, it will still be responsive but it won’t look good.</p>
<pre><code class="lang-css"><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">300px</span>;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/Animated-GIF-downsized-4-.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Fortunately, there is another property that CSS offers to fix this problem…</p>
<h3 id="heading-solution-the-object-fit-property">Solution: The Object-Fit Property</h3>
<p>To have more control over your images, CSS provides another property called object-fit. Let’s use the object-fit property and assign a value, which will make your image look better:</p>
<pre><code class="lang-css"><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">300px</span>;
  <span class="hljs-attribute">object-fit</span>: cover;
  <span class="hljs-attribute">object-position</span>: bottom;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/Animated-GIF-downsized-5-.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If needed, you can also use the object-position property (in addition to object-fit) to focus on a specific part of the image. Many people are not aware of the object-fit property, but it can be helpful to fix these kinds of problems.</p>
<p>I hope this post has helped you understand and solve your problems with responsive images. If you want to learn more about web development, feel free to check out my <a target="_blank" href="https://www.youtube.com/channel/UC1EgYPCvKCXFn8HlpoJwY3Q">Youtube channel</a>.</p>
<p>Thank you for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to generate product images for Amazon, Instagram, Zalando, and Tmall ]]>
                </title>
                <description>
                    <![CDATA[ By Anton Garcia Diaz Millions of people have already shifted from traditional tv to online content, and from traditional malls to online stores. Because of this, e-commerce and marketing teams need to deploy and maintain strong online presences for t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/generation-of-product-images-for-amazon-zalando-tmall-instagram-asos/</link>
                <guid isPermaLink="false">66d45d9c052ad259f07e4a61</guid>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image optimization  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image processing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ responsive images ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 26 Nov 2019 15:54:54 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/11/123brand.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Anton Garcia Diaz</p>
<p>Millions of people have already shifted from traditional tv to online content, and from traditional malls to online stores. Because of this, e-commerce and marketing teams need to deploy and maintain strong online presences for their businesses. </p>
<p>This usually means running the brand's own online store and having a presence in different marketplaces that cover different regions and population segments. The never-ending list of possible marketplaces in which to showcase, promote, and sell products just gets longer and longer.</p>
<p>To make matters worse, different marketplaces have different requirements and restrictions on images, which can add a burden for the devops and marketing teams. It's also a source of inconsistency in the public image of a brand.</p>
<p>Here, we'll review the main aspects to consider when setting up a clean pipeline for the seamless production of omnichannel images.</p>
<h2 id="heading-a-single-master-image-through-a-single-pipeline">A single master image through a single pipeline</h2>
<p>To simplify workflows and keep them sustainable, a good practice is to apply the principles of omnichannel to images. This basically means to set a single, easy to configure pipeline for the creation of variants, from the same master or pristine images. Under this approach, we can use <strong>the same product image for every channel</strong>. </p>
<p>Our pipeline should receive master images and produce the derivatives needed to feed the marketplaces. At a minimum, it should cope with a workflow like this.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://store.abraia.me/05bf471cbb3f9fa9ed785718e6f60e28/product-images-for-amazon-zalando-tmall-lamoda-ssg/generation-of-variants/index.html">https://store.abraia.me/05bf471cbb3f9fa9ed785718e6f60e28/product-images-for-amazon-zalando-tmall-lamoda-ssg/generation-of-variants/index.html</a></div>
<p>Of course, a front-end and cloud storage are not necessary. The pipeline may just work by watching a hot folder and creating the variants as master images land there. We'll also take a look at this.</p>
<h2 id="heading-image-transformation-and-optimization">Image transformation and optimization</h2>
<p>Each web channel has its own web design and layout. As for images, this means different and specific aspect ratios. Besides, each marketplace usually has an image policy in place, which limits the resolution and the weight of the image and sets the admissible image format. Usually, it also specifies other style guidelines.</p>
<p>Let's look at the main operations we'll want to accomplish with our pipeline.</p>
<h3 id="heading-resizing-cropping-padding">Resizing, cropping, padding</h3>
<p>To change the aspect ratio of an image we may crop it or pad it. To get a squared image from a vertical one we may cut out the upper and bottom parts or we may fill in the left and right sides with white stripes. </p>
<p>There are open source tools – like ImageMagick – that allow you to perform these operations effectively. Resizing an image with ImageMagick to limit its maximum dimensions to 800 px is as simple as this:</p>
<pre><code>convert input.jpg -resize <span class="hljs-number">800</span>x800 resized.jpg
</code></pre><p>This instruction respects the aspect ratio. If the original image is not squared, then the resized image has one dimension lower than 800 px.  Let's say the image is vertical and we want it for Tmall, which requires a squared image of 800x800 px. Then we may pad it like this:</p>
<pre><code>convert resized.jpg  -gravity center -extent <span class="hljs-number">800</span>x800 padded.jpg
</code></pre><p>Also, we may simply crop it to fit the dimensions:</p>
<pre><code>convert input.jpg -gravity Center  -crop <span class="hljs-number">800</span>x800+<span class="hljs-number">0</span>+<span class="hljs-number">0</span> +repage crop.jpg
</code></pre><p>While some marketplaces like Tmall encourage padding images with white stripes and branding them with logos to use them in category pages, others like Amazon or Lamoda forbid this practice. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/crop_pad.png" alt="Image" width="600" height="400" loading="lazy">
<em>Cropping (left), Resizing (center), Resizing and padding (right)</em></p>
<p>When we pad an image to match the aspect ratio, we don’t risk cropping out important parts. In fact, padding is a trick to keep the aspect ratio unchanged. However, the risk is real when we crop the image. </p>
<p>So, it is a good practice to ensure in the studio that we comply with some composition requirements set by each channel. We should produce master images with a view of the product compatible with the different aspect ratios that we'll deliver.</p>
<h3 id="heading-smart-cropping">Smart cropping</h3>
<p>There are algorithms inspired by human attention and aesthetic perception that provide an enhanced protection against bad automatic crops. In the next example, with smart image cropping (white line) we avoid cutting the face unlike a simple center cropping (red line) would do.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/smart-cropping-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Example of smart cropping with a <a target="_blank" href="https://abraia.me/workflows/">cloud service</a> vs center cropping</em></p>
<p>This option is available in some cloud services. If we're going to use it, we should verify that it works properly for us because many solutions only use an attention map and do not consider aesthetic aspects. Usually, choosing a number of representative images, making some tests with them, and finally verifying the results is enough to get a good grasp.</p>
<h3 id="heading-overlaying-logos-and-text">Overlaying logos and text</h3>
<p>We may also need to add our brand logo or to add a message to the image by overlaying a vector graphic or a text. Moreover, in many cases we need some content localization strategy in place – like tailoring discounts and language to a market region. Sticking to our example, with ImageMagick we can overlay text on a padded image.</p>
<pre><code>convert -fill black -pointsize <span class="hljs-number">70</span> -gravity center -draw <span class="hljs-string">"rotate -90 text 0,-330 'MyBrandHere'"</span> padded.jpg padded-<span class="hljs-keyword">with</span>-brand.jpg
</code></pre><p>Once we configure it for one image, we may apply it to any other with the same dimensions. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/brand.png" alt="Image" width="600" height="400" loading="lazy">
<em>Examples of batch image branding using <a target="_blank" href="https://abraia.me/workflows/">Abraia's cloud service</a></em></p>
<p>Otherwise, handling typographies and different settings may end being tricky in workflows with certain complexity. In this regard, a <a target="_blank" href="https://abraia.me/workflows/">cloud service</a> usually provides a front-end to make the configuration intuitive and fast, and more convenient to handle. It also deals with other stuff like typographies or quality preservation in image recompression. </p>
<h2 id="heading-the-workflows">The workflows</h2>
<p>There are many ways to deploy an image processing pipeline. Depending on the flow rate of images, we may need to support different types of workflows.  </p>
<h3 id="heading-batch-processing">Batch processing</h3>
<p>In the most simple case – when the flow rate is low – a batch image processing solution may be enough. With ImageMagick, we can use <em>mogrify</em> (instead of convert) to process all the images inside a folder. </p>
<p>In certain cases, like image versions with a text in different languages, we may need to code a script, but that's not a big deal either. To make it even easier, we may use a cloud batch processing tool in which we drop images and it gives us back all the variants we need, like in the video at the beginning of the post.</p>
<h3 id="heading-hot-folders">Hot folders</h3>
<p>For in-house deployments where we need something more than simple batch image processing, the use of hot folders may be a good option. In this case, we should set a worker that watches a folder. Any time an image lands the folder the watcher triggers the process that creates all the variants we need.</p>
<p>In this regard, Gulp comes very handy to implement a folder watching pipeline. <a target="_blank" href="https://github.com/abraia/workflows">This GitHub repository brings a ready-to-use implementation of hot folder</a> based on Gulp. It allows us to transform images using Abraia's cloud service or optimize them using Imagemin (an open source solution). Once installed, the watcher is easily started with just one command in the terminal.</p>
<pre><code>$ gulp
</code></pre><p>This video shows the process at work.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://store.abraia.me/05bf471cbb3f9fa9ed785718e6f60e28/product-images-for-amazon-zalando-tmall-lamoda-ssg/hot-folder-gulp/index.html">https://store.abraia.me/05bf471cbb3f9fa9ed785718e6f60e28/product-images-for-amazon-zalando-tmall-lamoda-ssg/hot-folder-gulp/index.html</a></div>
<h3 id="heading-full-cloud">Full cloud</h3>
<p>Cloud services usually bring the most flexible and fast-to-deploy solution. Still, there are different ways to go full cloud. In the most simple approach from a user perspective, an image management and optimization service takes charge of the transformation. It also manages the delivery to end users (through a CDN) or other web channels like marketplaces and social networks. The user only needs to upload the master images and to configure the transformations, usually with an intuitive graphic interface.</p>
<p>In medium to large companies that manage their own cloud, services from different providers are usually combined. In this case, we are likely to have to manage private and public buckets. We can have a service accessing a bucket, creating the variants, and delivering the resources or just returning them to a different bucket. </p>
<p>Also, a cloud pipeline may be partially implemented in-house. In this case we have endless possibilities. However, such development effort only makes sense when no service complies with the requirements and there is a justified need for a tailored solution.</p>
<h2 id="heading-summary">Summary</h2>
<p>Studio shooting and photography retouching are time-consuming and costly operations. Being able to use the same master material everywhere is very important to keep times and cost under control.</p>
<p>We have reviewed the main aspects of a complete pipeline in charge of creating image variants. On one hand, we looked at the transformations you need to perform from resizing, cropping, or padding, to the overlay of texts and graphics. On the other, we looked at the workflows to implement from batch processing to hot folders or full cloud solutions. We have reviewed some important open source resources (like ImageMagick or Gulp) that make it possible to implement a pipeline you develop yourself. </p>
<p>In the end, there are two main factors to consider when deciding whether to use an in-house or a cloud service. First, you must evaluate your willingness to take on the development effort. Second, you need to decide what features you require, from an easy to use interface for the configuration of variants to advanced features like smart cropping.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Building the React Image Optimization Component for Tueri.io ]]>
                </title>
                <description>
                    <![CDATA[ By Dane Stevens Let’s face it, image optimization is hard. We want to make it effortless. When we set out to build our React Component there were a few problems we wanted to solve: Automatically decide image width for any device based on the parent... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/building-the-react-image-optimization-component-for-tueri-io/</link>
                <guid isPermaLink="false">66d84e855a0b456f4d321452</guid>
                
                    <category>
                        <![CDATA[ Image Placeholder ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image optimization  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ responsive images ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 11 Jun 2019 18:37:17 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/06/progressive.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Dane Stevens</p>
<p><img src="https://cdn.tueri.io/274877906967/low-quality-image-placeholder-example.png" alt="Low-quality Image Placeholder" width="1428" height="1046" loading="lazy"></p>
<p>Let’s face it, image optimization is hard. We want to make it effortless.</p>
<p>When we set out to build our React Component there were a few problems we wanted to solve:</p>
<ul>
<li><p>Automatically decide image width for any device based on the parent container.</p>
</li>
<li><p>Use the best possible image format the user’s browser supports.</p>
</li>
<li><p>Automatic image lazy loading.</p>
</li>
<li><p>Automatic low-quality image placeholders (LQIP).</p>
</li>
</ul>
<p>Oh, and it had to be effortless for React Developers to use.</p>
<h2 id="heading-this-is-what-we-came-up-with">This is what we came up with:</h2>
<pre><code class="lang-jsx">&lt;Img src={ tueriImageId } alt=<span class="hljs-string">'Alt Text'</span> /&gt;
</code></pre>
<p>Easy right? Let’s dive in.</p>
<h2 id="heading-calculating-the-image-size">Calculating the image size:</h2>
<p>Create a <code>&lt;figure /&gt;</code> element, detect the width and build an image URL:</p>
<pre><code class="lang-jsx"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Img</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{

    <span class="hljs-keyword">constructor</span>(props) {
        <span class="hljs-built_in">super</span>(props)
        <span class="hljs-built_in">this</span>.state = {
            <span class="hljs-attr">width</span>: <span class="hljs-number">0</span>
        }
        <span class="hljs-built_in">this</span>.imgRef = React.createRef()
    }

    componentDidMount() {
        <span class="hljs-keyword">const</span> width = <span class="hljs-built_in">this</span>.imgRef.current.clientWidth
        <span class="hljs-built_in">this</span>.setState({
            width
        })
    }

    render() {

        <span class="hljs-comment">// Destructure props and state</span>
        <span class="hljs-keyword">const</span> { src, alt, options = {}, ext = <span class="hljs-string">'jpg'</span> } = <span class="hljs-built_in">this</span>.props
        <span class="hljs-keyword">const</span> { width } = <span class="hljs-built_in">this</span>.state

        <span class="hljs-comment">// Create an empty query string</span>
        <span class="hljs-keyword">let</span> queryString = <span class="hljs-string">''</span>        

        <span class="hljs-comment">// If width is specified, otherwise use auto-detected width</span>
        options[<span class="hljs-string">'w'</span>] = options[<span class="hljs-string">'w'</span>] || width

        <span class="hljs-comment">// Loop through option object and build queryString</span>
        <span class="hljs-built_in">Object</span>.keys(options).map(<span class="hljs-function">(<span class="hljs-params">option, i</span>) =&gt;</span> {
            <span class="hljs-keyword">return</span> queryString +=  <span class="hljs-string">`<span class="hljs-subst">${i &lt; <span class="hljs-number">1</span> ? <span class="hljs-string">'?'</span> : <span class="hljs-string">'&amp;'</span>}</span><span class="hljs-subst">${option}</span>=<span class="hljs-subst">${options[option]}</span>`</span>
        })

        <span class="hljs-keyword">return</span>(
            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">figure</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{this.imgRef}</span>&gt;</span>
                { 
                    // If the container width has been set, display the image else null
                    width &gt; 0 ? (
                        <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
                            <span class="hljs-attr">src</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">https:</span>//<span class="hljs-attr">cdn.tueri.io</span>/${ <span class="hljs-attr">src</span> }/${ <span class="hljs-attr">kebabCase</span>(<span class="hljs-attr">alt</span>) }<span class="hljs-attr">.</span>${ <span class="hljs-attr">ext</span> }${ <span class="hljs-attr">queryString</span> }`}
                            <span class="hljs-attr">alt</span>=<span class="hljs-string">{</span> <span class="hljs-attr">alt</span> }
                        /&gt;</span>
                    ) : null 
                }
            <span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span></span>
        )

    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Img
</code></pre>
<p>This returns the following HTML:</p>
<pre><code class="lang-jsx">&lt;figure&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
        <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.tueri.io/tueriImageId/alt-text.jpg?w=autoCalculatedWidth"</span> 
        <span class="hljs-attr">alt</span>=<span class="hljs-string">"Alt Text"</span> 
    /&gt;</span></span>
&lt;/figure&gt;
</code></pre>
<h2 id="heading-use-the-best-possible-image-format">Use the best possible image format:</h2>
<p>Next, we needed to add support for detecting WebP images and having the Tueri service return the image in the WebP format:</p>
<pre><code class="lang-jsx"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Img</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{

    <span class="hljs-keyword">constructor</span>(props) {
        <span class="hljs-comment">// ...</span>
        <span class="hljs-built_in">this</span>.window = <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">window</span> !== <span class="hljs-string">'undefined'</span> &amp;&amp; <span class="hljs-built_in">window</span>
        <span class="hljs-built_in">this</span>.isWebpSupported = <span class="hljs-built_in">this</span>.isWebpSupported.bind(<span class="hljs-built_in">this</span>)
    }

    <span class="hljs-comment">// ...</span>

    isWebpSupported() {
        <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.window.createImageBitmap) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

    render() {

        <span class="hljs-comment">// ...</span>

        <span class="hljs-comment">// If a format has not been specified, detect webp support</span>
        <span class="hljs-comment">// Set the fm (format) option in the image URL</span>
        <span class="hljs-keyword">if</span> (!options[<span class="hljs-string">'fm'</span>] &amp;&amp; <span class="hljs-built_in">this</span>.isWebpSupported) {
            options[<span class="hljs-string">'fm'</span>] = <span class="hljs-string">'webp'</span>
        }

        <span class="hljs-comment">// ...</span>

        <span class="hljs-keyword">return</span> (
            <span class="hljs-comment">// ...</span>
        )

    }
}

<span class="hljs-comment">// ...</span>
</code></pre>
<p>This returns the following HTML:</p>
<pre><code class="lang-jsx">&lt;figure&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
        <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.tueri.io/tueriImageId/alt-text.jpg?w=autoCalculatedWidth&amp;fm=webp"</span> 
        <span class="hljs-attr">alt</span>=<span class="hljs-string">"Alt Text"</span> 
    /&gt;</span></span>
&lt;/figure&gt;
</code></pre>
<h2 id="heading-automatic-image-lazy-loading">Automatic image lazy loading:</h2>
<p>Now, we need to find out if the <code>&lt;figure /&gt;</code> element is in the viewport, plus we add a little buffer area so the images load just before being scrolled into view.</p>
<pre><code class="lang-jsx">   <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Img</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{

   <span class="hljs-keyword">constructor</span>(props) {
       <span class="hljs-comment">// ...</span>
       <span class="hljs-built_in">this</span>.state = {
           <span class="hljs-comment">// ...</span>
           <span class="hljs-attr">isInViewport</span>: <span class="hljs-literal">false</span>
           <span class="hljs-attr">lqipLoaded</span>: <span class="hljs-literal">false</span>
       }
       <span class="hljs-comment">// ...</span>
       <span class="hljs-built_in">this</span>.handleViewport = <span class="hljs-built_in">this</span>.handleViewport.bind(<span class="hljs-built_in">this</span>)
   }

   componentDidMount() {
       <span class="hljs-comment">// ...</span>
       <span class="hljs-built_in">this</span>.handleViewport()
       <span class="hljs-built_in">this</span>.window.addEventListener(<span class="hljs-string">'scroll'</span>, <span class="hljs-built_in">this</span>.handleViewport)
   }

   handleViewport() {
       <span class="hljs-comment">// Only run if the image has not already been loaded</span>
       <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.imgRef.current &amp;&amp; !<span class="hljs-built_in">this</span>.state.lqipLoaded) {
           <span class="hljs-comment">// Get the viewport height</span>
           <span class="hljs-keyword">const</span> windowHeight = <span class="hljs-built_in">this</span>.window.innerHeight
           <span class="hljs-comment">// Get the top position of the &lt;figure /&gt; element</span>
           <span class="hljs-keyword">const</span> imageTopPosition = <span class="hljs-built_in">this</span>.imgRef.current.getBoundingClientRect().top
           <span class="hljs-comment">// Multiply the viewport * buffer (default buffer: 1.5)</span>
           <span class="hljs-keyword">const</span> buffer = <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">this</span>.props.buffer === <span class="hljs-string">'number'</span> &amp;&amp; <span class="hljs-built_in">this</span>.props.buffer &gt; <span class="hljs-number">1</span> &amp;&amp; <span class="hljs-built_in">this</span>.props.buffer &lt; <span class="hljs-number">10</span> ? <span class="hljs-built_in">this</span>.props.buffer : <span class="hljs-number">1.5</span>
           <span class="hljs-comment">// If &lt;figure /&gt; is in viewport</span>
           <span class="hljs-keyword">if</span> (windowHeight * buffer &gt; imageTopPosition) {
               <span class="hljs-built_in">this</span>.setState({
                   <span class="hljs-attr">isInViewport</span>: <span class="hljs-literal">true</span>
               })
           }
       }
   }

   <span class="hljs-comment">// ...</span>

   componentWillUnmount() {
       <span class="hljs-built_in">this</span>.window.removeEventListener(<span class="hljs-string">'scroll'</span>, <span class="hljs-built_in">this</span>.handleViewport)
   }

   render() {

       <span class="hljs-comment">// Destructure props and state</span>
       <span class="hljs-comment">// ...</span>
       <span class="hljs-keyword">const</span> { isInViewport, width } = <span class="hljs-built_in">this</span>.state

       <span class="hljs-comment">// ...</span>

       <span class="hljs-keyword">return</span> (
           <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">figure</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{this.imgRef}</span>&gt;</span>
               { 
                   // If the container width has been set, display the image else null
                   isInViewport &amp;&amp; width &gt; 0 ? (
                       <span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
                           <span class="hljs-attr">onLoad</span>=<span class="hljs-string">{</span> () =&gt;</span> { this.setState({ lqipLoaded: true }) } }
                           // ...
                       /&gt;
                   ) : null 
               }
           <span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span></span>
       )

   }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Img
</code></pre>
<h2 id="heading-automatic-low-quality-image-placeholders-lqip">Automatic low-quality image placeholders (LQIP):</h2>
<p>Finally, when an image is in the viewport, we want to load a 1/10 size blurred image, then fade out the placeholder image when the full-size image is loaded:</p>
<pre><code class="lang-jsx"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Img</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{

    <span class="hljs-keyword">constructor</span>(props) {
        <span class="hljs-comment">// ...</span>
        <span class="hljs-built_in">this</span>.state = {
            <span class="hljs-comment">// ...</span>
            <span class="hljs-attr">fullsizeLoaded</span>: <span class="hljs-literal">false</span>
        }

        <span class="hljs-comment">// ...</span>

    }

    <span class="hljs-comment">// ...</span>

    render() {

        <span class="hljs-comment">// Destructure props and state</span>
        <span class="hljs-comment">// ...</span>
        <span class="hljs-keyword">const</span> { isInViewport, width, fullsizeLoaded } = <span class="hljs-built_in">this</span>.state

        <span class="hljs-comment">// ...</span>

        <span class="hljs-comment">// Modify the queryString for the LQIP image: replace the width param with a value 1/10 the fullsize</span>
        <span class="hljs-keyword">const</span> lqipQueryString = queryString.replace(<span class="hljs-string">`w=<span class="hljs-subst">${ width }</span>`</span>, <span class="hljs-string">`w=<span class="hljs-subst">${ <span class="hljs-built_in">Math</span>.round(width * <span class="hljs-number">0.1</span>) }</span>`</span>)

        <span class="hljs-comment">// Set the default styles. The full size image should be absolutely positioned within the &lt;figure /&gt; element</span>
        <span class="hljs-keyword">const</span> styles = {
            <span class="hljs-attr">figure</span>: {
                <span class="hljs-attr">position</span>: <span class="hljs-string">'relative'</span>,
                <span class="hljs-attr">margin</span>: <span class="hljs-number">0</span>
            },
            <span class="hljs-attr">lqip</span>: {
                <span class="hljs-attr">width</span>: <span class="hljs-string">'100%'</span>,
                <span class="hljs-attr">filter</span>: <span class="hljs-string">'blur(5px)'</span>,
                <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span>,
                <span class="hljs-attr">transition</span>: <span class="hljs-string">'all 0.5s ease-in'</span>
            },
            <span class="hljs-attr">fullsize</span>: {
                <span class="hljs-attr">position</span>: <span class="hljs-string">'absolute'</span>,
                <span class="hljs-attr">top</span>: <span class="hljs-string">'0px'</span>,
                <span class="hljs-attr">left</span>: <span class="hljs-string">'0px'</span>,
                <span class="hljs-attr">transition</span>: <span class="hljs-string">'all 0.5s ease-in'</span>
            }
        }

        <span class="hljs-comment">// When the fullsize image is loaded, fade out the LQIP</span>
        <span class="hljs-keyword">if</span> (fullsizeLoaded) {
            styles.lqip.opacity = <span class="hljs-number">0</span>
        }

        <span class="hljs-keyword">return</span>(
            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">figure</span>
                <span class="hljs-attr">style</span>=<span class="hljs-string">{</span> <span class="hljs-attr">styles.figure</span> }
                // <span class="hljs-attr">...</span>
            &gt;</span>
                {
                    isInViewport &amp;&amp; width &gt; 0 ? (
                        <span class="hljs-tag">&lt;<span class="hljs-name">React.Fragment</span>&gt;</span>

                            {/* Load fullsize image in background */}
                            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
                                <span class="hljs-attr">onLoad</span>=<span class="hljs-string">{</span> () =&gt;</span> { this.setState({ fullsizeLoaded: true }) } }
                                style={ styles.fullsize }
                                src={`https://cdn.tueri.io/${ src }/${ kebabCase(alt) }.${ ext }${ queryString }`}
                                alt={ alt }
                            /&gt;

                            {/* Load LQIP in foreground */}
                            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
                                <span class="hljs-attr">onLoad</span>=<span class="hljs-string">{</span> () =&gt;</span> { this.setState({ lqipLoaded: true }) } }
                                style={ styles.lqip }
                                src={`https://cdn.tueri.io/${ src }/${ kebabCase(alt) }.${ ext }${ lqipQueryString }`} 
                                alt={ alt } 
                            /&gt;
                        <span class="hljs-tag">&lt;/<span class="hljs-name">React.Fragment</span>&gt;</span>
                    ) : null
                }            
            <span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span></span>
        )

    }
}

<span class="hljs-comment">// ...</span>
</code></pre>
<h2 id="heading-putting-it-all-together">Putting it all together:</h2>
<p>Image optimization made effortless. Just swap out your regular <code>&lt;img /&gt;</code> elements for the Tueri <code>&lt;Img /&gt;</code> and never worry about optimization again.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> PropTypes <span class="hljs-keyword">from</span> <span class="hljs-string">'prop-types'</span>
<span class="hljs-keyword">import</span> { TueriContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'./Provider'</span>
<span class="hljs-keyword">import</span> kebabCase <span class="hljs-keyword">from</span> <span class="hljs-string">'lodash.kebabcase'</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Img</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{

    <span class="hljs-keyword">constructor</span>(props) {
        <span class="hljs-built_in">super</span>(props)
        <span class="hljs-built_in">this</span>.state = {
            <span class="hljs-attr">isInViewport</span>: <span class="hljs-literal">false</span>,
            <span class="hljs-attr">width</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">height</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">lqipLoaded</span>: <span class="hljs-literal">false</span>,
            <span class="hljs-attr">fullsizeLoaded</span>: <span class="hljs-literal">false</span>
        }

        <span class="hljs-built_in">this</span>.imgRef = React.createRef()
        <span class="hljs-built_in">this</span>.window = <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">window</span> !== <span class="hljs-string">'undefined'</span> &amp;&amp; <span class="hljs-built_in">window</span> 
        <span class="hljs-built_in">this</span>.handleViewport = <span class="hljs-built_in">this</span>.handleViewport.bind(<span class="hljs-built_in">this</span>)       
        <span class="hljs-built_in">this</span>.isWebpSupported = <span class="hljs-built_in">this</span>.isWebpSupported.bind(<span class="hljs-built_in">this</span>)

    }

    componentDidMount() {

        <span class="hljs-keyword">const</span> width = <span class="hljs-built_in">this</span>.imgRef.current.clientWidth

        <span class="hljs-built_in">this</span>.setState({
            width
        })

        <span class="hljs-built_in">this</span>.handleViewport()

        <span class="hljs-built_in">this</span>.window.addEventListener(<span class="hljs-string">'scroll'</span>, <span class="hljs-built_in">this</span>.handleViewport)

    }

    handleViewport() {
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.imgRef.current &amp;&amp; !<span class="hljs-built_in">this</span>.state.lqipLoaded) {
            <span class="hljs-keyword">const</span> windowHeight = <span class="hljs-built_in">this</span>.window.innerHeight
            <span class="hljs-keyword">const</span> imageTopPosition = <span class="hljs-built_in">this</span>.imgRef.current.getBoundingClientRect().top
            <span class="hljs-keyword">const</span> buffer = <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">this</span>.props.buffer === <span class="hljs-string">'number'</span> &amp;&amp; <span class="hljs-built_in">this</span>.props.buffer &gt; <span class="hljs-number">1</span> &amp;&amp; <span class="hljs-built_in">this</span>.props.buffer &lt; <span class="hljs-number">10</span> ? <span class="hljs-built_in">this</span>.props.buffer : <span class="hljs-number">1.5</span>
            <span class="hljs-keyword">if</span> (windowHeight * buffer &gt; imageTopPosition) {
                <span class="hljs-built_in">this</span>.setState({
                    <span class="hljs-attr">isInViewport</span>: <span class="hljs-literal">true</span>
                })
            }

        }
    }

    isWebpSupported() {
        <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.window.createImageBitmap) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

    componentWillUnmount() {
        <span class="hljs-built_in">this</span>.window.removeEventListener(<span class="hljs-string">'scroll'</span>, <span class="hljs-built_in">this</span>.handleViewport)
    }

    render() {

        <span class="hljs-comment">// Destructure props and state</span>
        <span class="hljs-keyword">const</span> { src, alt, options = {}, ext = <span class="hljs-string">'jpg'</span> } = <span class="hljs-built_in">this</span>.props
        <span class="hljs-keyword">const</span> { isInViewport, width, fullsizeLoaded } = <span class="hljs-built_in">this</span>.state

        <span class="hljs-comment">// Create an empty query string</span>
        <span class="hljs-keyword">let</span> queryString = <span class="hljs-string">''</span>

        <span class="hljs-comment">// If width is specified, otherwise use auto-detected width</span>
        options[<span class="hljs-string">'w'</span>] = options[<span class="hljs-string">'w'</span>] || width

        <span class="hljs-comment">// If a format has not been specified, detect webp support</span>
        <span class="hljs-keyword">if</span> (!options[<span class="hljs-string">'fm'</span>] &amp;&amp; <span class="hljs-built_in">this</span>.isWebpSupported) {
            options[<span class="hljs-string">'fm'</span>] = <span class="hljs-string">'webp'</span>
        }

        <span class="hljs-comment">// Loop through option prop and build queryString</span>
        <span class="hljs-built_in">Object</span>.keys(options).map(<span class="hljs-function">(<span class="hljs-params">option, i</span>) =&gt;</span> {
            <span class="hljs-keyword">return</span> queryString +=  <span class="hljs-string">`<span class="hljs-subst">${i &lt; <span class="hljs-number">1</span> ? <span class="hljs-string">'?'</span> : <span class="hljs-string">'&amp;'</span>}</span><span class="hljs-subst">${option}</span>=<span class="hljs-subst">${options[option]}</span>`</span>
        })

        <span class="hljs-comment">// Modify the queryString for the LQIP image: replace the width param with a value 1/10 the fullsize</span>
        <span class="hljs-keyword">const</span> lqipQueryString = queryString.replace(<span class="hljs-string">`w=<span class="hljs-subst">${ width }</span>`</span>, <span class="hljs-string">`w=<span class="hljs-subst">${ <span class="hljs-built_in">Math</span>.round(width * <span class="hljs-number">0.1</span>) }</span>`</span>)

        <span class="hljs-keyword">const</span> styles = {
            <span class="hljs-attr">figure</span>: {
                <span class="hljs-attr">position</span>: <span class="hljs-string">'relative'</span>,
                <span class="hljs-attr">margin</span>: <span class="hljs-number">0</span>
            },
            <span class="hljs-attr">lqip</span>: {
                <span class="hljs-attr">width</span>: <span class="hljs-string">'100%'</span>,
                <span class="hljs-attr">filter</span>: <span class="hljs-string">'blur(5px)'</span>,
                <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span>,
                <span class="hljs-attr">transition</span>: <span class="hljs-string">'all 0.5s ease-in'</span>
            },
            <span class="hljs-attr">fullsize</span>: {
                <span class="hljs-attr">position</span>: <span class="hljs-string">'absolute'</span>,
                <span class="hljs-attr">top</span>: <span class="hljs-string">'0px'</span>,
                <span class="hljs-attr">left</span>: <span class="hljs-string">'0px'</span>,
                <span class="hljs-attr">transition</span>: <span class="hljs-string">'all 0.5s ease-in'</span>
            }
        }

        <span class="hljs-comment">// When the fullsize image is loaded, fade out the LQIP</span>
        <span class="hljs-keyword">if</span> (fullsizeLoaded) {
            styles.lqip.opacity = <span class="hljs-number">0</span>
        }

        <span class="hljs-keyword">const</span> missingALt = <span class="hljs-string">'ALT TEXT IS REQUIRED'</span>

        <span class="hljs-keyword">return</span>(
            <span class="hljs-comment">// Return the CDN domain from the TueriProvider</span>
            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TueriContext.Consumer</span>&gt;</span>
                {({ domain }) =&gt; (
                    <span class="hljs-tag">&lt;<span class="hljs-name">figure</span>
                        <span class="hljs-attr">style</span>=<span class="hljs-string">{</span> <span class="hljs-attr">styles.figure</span> }
                        <span class="hljs-attr">ref</span>=<span class="hljs-string">{this.imgRef}</span>
                    &gt;</span>
                        {
                            // 
                            isInViewport &amp;&amp; width &gt; 0 ? (
                                <span class="hljs-tag">&lt;<span class="hljs-name">React.Fragment</span>&gt;</span>

                                    {/* Load fullsize image in background */}
                                    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
                                        <span class="hljs-attr">onLoad</span>=<span class="hljs-string">{</span> () =&gt;</span> { this.setState({ fullsizeLoaded: true }) } }
                                        style={ styles.fullsize }
                                        src={`${ domain }/${ src }/${ kebabCase(alt || missingALt) }.${ ext }${ queryString }`}
                                        alt={ alt || missingALt }
                                    /&gt;

                                    {/* Load LQIP in foreground */}
                                    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
                                        <span class="hljs-attr">onLoad</span>=<span class="hljs-string">{</span> () =&gt;</span> { this.setState({ lqipLoaded: true }) } }
                                        style={ styles.lqip }
                                        src={`${ domain }/${ src }/${ kebabCase(alt || missingALt) }.${ ext }${ lqipQueryString }`} 
                                        alt={ alt || missingALt } 
                                    /&gt;
                                <span class="hljs-tag">&lt;/<span class="hljs-name">React.Fragment</span>&gt;</span>
                            ) : null
                        }            
                    <span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span>
                )}

            <span class="hljs-tag">&lt;/<span class="hljs-name">TueriContext.Consumer</span>&gt;</span></span>
        )

    }
}

Img.propTypes = {
    <span class="hljs-attr">src</span>: PropTypes.string.isRequired,
    <span class="hljs-attr">alt</span>: PropTypes.string.isRequired,
    <span class="hljs-attr">options</span>: PropTypes.object,
    <span class="hljs-attr">ext</span>: PropTypes.string,
    <span class="hljs-attr">buffer</span>: PropTypes.number
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Img
</code></pre>
<h2 id="heading-see-it-in-action">See it in action:</h2>
<p>Try out a live demo on CodeSandbox:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codesandbox.io/embed/qjzqw7w3q?fontsize=14" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodeSandbox embed" allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin" loading="lazy"></iframe></div>
<hr>
<p>_Originally published at <a target="_blank" href="https://tueri.io/blog/2019-03-21-building-the-react-image-optimization-component/?utm_source=Freecodecamp&amp;utm_medium=Post&amp;utm_campaign=">Tueri.io</a>_</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
