<?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[ css properties - 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[ css properties - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 16 May 2026 19:39:41 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/css-properties/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ CSS Properties – Max-width, Min-width, Max-height, and Min-height Explained with Examples ]]>
                </title>
                <description>
                    <![CDATA[ By Nelson Michael If you're building a website, making it responsive is one of the most important things you'll do. It can be difficult to create websites that look good across a variety of screen sizes. You'll have to handle rendering an element's w... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/css-properties-examples/</link>
                <guid isPermaLink="false">66d45f63b3016bf139028d4e</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ css properties ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 20 Jul 2021 17:09:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/07/pexels-scott-webb-1544944.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Nelson Michael</p>
<p>If you're building a website, making it responsive is one of the most important things you'll do.</p>
<p>It can be difficult to create websites that look good across a variety of screen sizes. You'll have to handle rendering an element's width or height, and specifying varied width sizes using media queries is not easy. </p>
<p>While relative units such as "percentage percent" can be useful in some contexts, they can also be disastrous in others.</p>
<p>But don't worry – characteristics like max-width and min-width are here to help. These properties allow us to avoid using media queries to solve some responsive challenges.</p>
<p>By the end of this article, you'll know what max-width, min-width, and max-height are and how to use them.</p>
<h2 id="heading-the-max-width-property">The Max-width Property</h2>
<p>The max-width property lets you specify an element's maximum width. This means that an element can increase in width until it reaches a specific <a target="_blank" href="https://www.freecodecamp.org/news/css-unit-guide/">absolute or relative unit</a>, at which point it should fix its width to that unit.</p>
<p>Here's what I'm talking about:</p>
<p>Imagine setting the width of an element to <strong>80%</strong> of the viewport's width. If the viewport has a width of <strong>375px</strong>, our element will have a width of <strong>300px</strong>, which isn't too shabby.</p>
<p>(80/100) * 375 = 300px</p>
<p>But what if we had a wider viewport, say <strong>1300px</strong>, in which case our element will be <strong>1040px</strong> wide.</p>
<p>(80/100) * 1300 = 1040px</p>
<p>This is where the max-width property comes in handy. When you're using relative units like a percentage, setting a max-width property on an element causes it to keep increasing in width until it reaches a point we designate.</p>
<p>Here's an example:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/D_kingnelson/embed/mdmeEOV" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p>Notice how our card's size never exceeded <strong>350px</strong>? That's how max-width works. It allows our card to grow on smaller screens. </p>
<p>If the width is less than 350px, it takes 80% of whatever the current screen size is. But as soon as the width reaches 350px, it clamps down and doesn’t exceed that set width.</p>
<p>Here’s what the code looks like:</p>
<pre><code><span class="hljs-comment">//The card can not get larger than 350px.</span>

.card{
  <span class="hljs-attr">margin</span>:<span class="hljs-number">0</span> auto;
  padding:<span class="hljs-number">1.5</span>em;
  width:<span class="hljs-number">80</span>%;
  max-width:<span class="hljs-number">350</span>px;
  height:<span class="hljs-number">50</span>%;
  background: #FFFFFF;
  box-shadow: <span class="hljs-number">0</span>px <span class="hljs-number">0</span>px <span class="hljs-number">5</span>px rgba(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.3</span>);
  border-radius:<span class="hljs-number">4</span>px;
  overflow:hidden;
}
</code></pre><h2 id="heading-the-min-width-property">The Min-Width Property</h2>
<p>In contrast to the max-width property, the min-width property specifies the minimum width. It indicates the minimal possible width for an element.</p>
<p>In some cases, you may want your element to have flexible width, so you give it a width in a relative unit such as a percentage. But as the screen shrinks, the element's width shrinks as well. </p>
<p>This is where min-width comes in – you can set a minimum width so that the card knows not to shrink smaller than the specified width.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/D_kingnelson/embed/zYwdzxW" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<pre><code><span class="hljs-comment">//Here the card element can not get smaller than 250px</span>
.card{
  <span class="hljs-attr">margin</span>:<span class="hljs-number">0</span> auto;
  padding:<span class="hljs-number">1.5</span>em;
  width:<span class="hljs-number">80</span>%;
  max-width:<span class="hljs-number">350</span>px;
  <span class="hljs-comment">//here we set the min-width property</span>
  min-width : <span class="hljs-number">250</span>px;
  height:<span class="hljs-number">50</span>%;
  background: #FFFFFF;
  box-shadow: <span class="hljs-number">0</span>px <span class="hljs-number">0</span>px <span class="hljs-number">5</span>px rgba(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.3</span>);
  border-radius:<span class="hljs-number">4</span>px;
  overflow:hidden;
}
</code></pre><h2 id="heading-the-max-height-property">The Max-Height Property</h2>
<p>The max-height property operates similarly to the max-width property, but it affects the height instead of the width.</p>
<p>Here's an example :</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/D_kingnelson/embed/gOWxRrb" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<pre><code><span class="hljs-comment">// it fixes the height of an element to a specified unit, effectively stopping it from increasing in height</span>

.card{
  <span class="hljs-attr">margin</span>:<span class="hljs-number">0</span> auto;
  padding:<span class="hljs-number">1.5</span>em;
  width:<span class="hljs-number">80</span>%;
  max-width:<span class="hljs-number">350</span>px;
  height:<span class="hljs-number">70</span>%;
  <span class="hljs-comment">//here we set the max-height for the card.</span>
  max-height: <span class="hljs-number">400</span>px;
  background: #FFFFFF;
  box-shadow: <span class="hljs-number">0</span>px <span class="hljs-number">0</span>px <span class="hljs-number">5</span>px rgba(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.3</span>);
  border-radius:<span class="hljs-number">4</span>px;
  overflow:hidden;
}
</code></pre><h2 id="heading-the-min-height-property">The Min-Height Property</h2>
<p>In contrast to max-height, the min-height property provides a minimum height for an element.</p>
<p>This occurs when the viewport shrinks and the element's height cannot be reduced beyond a defined height unit.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/D_kingnelson/embed/yLboXVz" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<pre><code>.element{
    <span class="hljs-attr">height</span>:<span class="hljs-number">40</span>vh;
    min-height:<span class="hljs-number">200</span>px;
}
</code></pre><h2 id="heading-conclusion">Conclusion</h2>
<p>Responsiveness is an important factor to consider in web development. Keeping track of how things appear across multiple screen sizes may be challenging, but the max-width, min-width and max-height, and min-height properties help tackle these challenges. </p>
<p>These properties let you adjust the size of elements without needing to use media queries.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is Website Theming? How to Use CSS Custom Properties and Gatsby.js to Customize Your Site ]]>
                </title>
                <description>
                    <![CDATA[ In this article, I'm going to show you how to theme your website so users can customize certain elements to their tastes. We'll talk about website themes, how theming works, and we'll end with a demo so you can see it in action. Let's dive in. Table ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/website-theming-with-css-custom-properties-and-gatsbyjs/</link>
                <guid isPermaLink="false">66d4616c73634435aafcefef</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ css properties ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Gatsby ]]>
                    </category>
                
                    <category>
                        <![CDATA[ themes ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Thu, 01 Jul 2021 18:19:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/06/theming-website-preview-1-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, I'm going to show you how to theme your website so users can customize certain elements to their tastes.</p>
<p>We'll talk about website themes, how theming works, and we'll end with a demo so you can see it in action. Let's dive in.</p>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-a-theme">What is a Website Theme?</a><br>  What is theming?</p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-should-you-care-about-website-theming">Why Should You Care About Theming?</a><br>  “It’s their screen, machine and software”<br>  Theming increases readability<br>  All the cool cats are using it - theming in the wild</p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-theme-properties">How to Use Theme Properties</a><br>  What are theme properties?<br>  What are CSS custom properties?<br>  How to set up theme properties in Gatsby.js<br>  How to store the theme properties<br>  How to transform theme properties to CSS custom properties</p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-the-theme-switcher-component">How to Use the Theme Switcher Component</a><br>  The markup<br>  How to set up the state<br>  How to update the state<br>  How to persist state to <code>LocalStorage</code></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-who-is-this-article-for">Who is this article for?</h2>
<p>This article is aimed at developers who already have a basic knowledge of CSS, React, and Gatsby who want to learn how to create a user theme-able Gatsby or React app.</p>
<p>By the end of this article, you should understand how theming works and how to implement theming on your Gatsby sites.</p>
<h2 id="heading-what-is-a-theme">What is a theme?</h2>
<p>In order to understand what website theming is, let's first look at what a <strong>website theme</strong> is and what make up a theme.</p>
<p>A theme in the context of a website is the overall look, feel, and style of your <strong>website.</strong> A theme may include:</p>
<ul>
<li><p>fonts</p>
</li>
<li><p>font size</p>
</li>
<li><p>color schemes</p>
</li>
<li><p>layouts</p>
</li>
<li><p>aesthetics</p>
</li>
</ul>
<p>A theme controls the design of your website. It determines what your website looks like from the surface, and it is the part of your website that has a direct impact on your users.</p>
<p>A theme is also a set of styles worn by a website.</p>
<h2 id="heading-what-is-theming">What is Theming?</h2>
<p>Theming is to a website what clothes are to our bodies. Imagine wearing the same clothes to a meeting, a wedding, and a farm - sounds funny right? Of course you probably wouldn't do that if you had the choice.</p>
<p>For each occasion you would wear the appropriate type or style of dress. That’s what website theming is – it allows our users to choose the look and feel of our website with a set of styles based on different occasions.</p>
<p>Theming is simply giving users the ability to make customizations to our websites and apps. You can also think about theming as a set of customizations users can make to our websites or applications based on their choices.</p>
<p>Theming happens when the user is able to tell your website what they prefer to see, for example:</p>
<ul>
<li><p>Clicking a button to change the background of a website to red or black</p>
</li>
<li><p>Increasing or decreasing the font size of a site website/application</p>
</li>
<li><p>Clicking a button to remove content not relevant to the user.</p>
</li>
</ul>
<p>Here’s a tip: letting or asking your users to determine your website theme from scratch is a bad idea. You or your team should provide users with an accessible and usable default theme, since in most cases many users will never customize “their view” on your website no matter how easy it is. |</p>
<h2 id="heading-why-should-you-care-about-website-theming">Why should you care about website theming?</h2>
<p>Apart from letting users know you care about their personal preferences, there are other reasons to let your users theme your website. Some of them include:</p>
<h3 id="heading-its-their-screen-machine-and-software">“It’s their Screen, Machine and Software”</h3>
<p>This is a quote from Jakob Nielsen's 2002 article: <a target="_blank" href="https://www.nngroup.com/articles/let-users-control-font-size/">Let users control font size</a>.</p>
<p>The fact that your website is running on the user’s screen, machine, and software (and probably draining their batteries too) is enough reason them to be able to customize their experience on your site.</p>
<h3 id="heading-theming-improves-website-readability">Theming improves website readability</h3>
<p>Quoting D. Bnonn from the article: <a target="_blank" href="https://www.smashingmagazine.com/2011/10/16-pixels-body-copy-anything-less-costly-mistake/">16 Pixels Font Size: For Body Copy. Anything Less Is A Costly Mistake</a></p>
<blockquote>
<p>Fact: Most Web Users Hate The “Normal” Font Size.</p>
</blockquote>
<p>With this fact in mind, theming can help readers out by allowing them to choose the font size that suites their eyes best.</p>
<p>Oh and here is another quote from the same article.</p>
<blockquote>
<p>Readership = Revenue.</p>
</blockquote>
<h3 id="heading-all-the-cool-cats-are-using-it-theming-in-the-wild">All the cool cats are using it – theming in the wild</h3>
<p>A lot of developers have used the idea of theming to create dark mode versions of their websites. Other’s have taken this idea further to allow users change font-size, colors, and background based on individual preferences.</p>
<p>Here's an example of this kind of customization in the Twitter web app:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/twitter.com_home.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Twitter customize theme UI</em></p>
<p>Still not feeling motivated yet? If you still need more proof that theming is a good idea, <a target="_blank" href="https://darkmodelist.com/">here’s a whole list of websites, apps, and software</a> that use theming to provide dark and light modes for their users.</p>
<h2 id="heading-how-to-use-theme-properties">How to Use Theme Properties</h2>
<p>Now that you know what theming is and have seen sites that use this idea of theming in their websites and applications, let’s learn what theme properties are.</p>
<h3 id="heading-what-are-theme-properties">What are theme properties?</h3>
<p>Theme properties are a set of CSS custom properties that make up a theme. Remember that “a theme is a set of styles worn by a website” – so theme properties are all the properties that make up the styles a site wears. For example:</p>
<pre><code class="lang-css"><span class="hljs-selector-attr">[data-theme=<span class="hljs-string">"default"</span>]</span> {
  <span class="hljs-attribute">--font-size</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">--background</span>: red;
}
</code></pre>
<p>In the example above, <code>[data-theme="default"]</code> is our theme, while all the CSS custom properties inside are the theme properties. You get the idea, right?</p>
<p>Here’s a tip: your theme properties don’t have to be just CSS custom properties. They can also be any valid CSS properties that you want to apply to a specific theme.</p>
<p>Before we move forward, let’s first understand what CSS custom properties are</p>
<h3 id="heading-what-are-css-custom-properties-also-known-as-css-variables">What are CSS Custom Properties (also known as CSS variables)?</h3>
<p>CSS custom properties are entities which hold values that you can reuse throughout an entire site or document.</p>
<p>For the sake of this tutorial we are not going to cover CSS custom properties in depth. You can <a target="_blank" href="https://www.freecodecamp.org/news/css-customs-properties-cheatsheet-c86778541f7d/">read more about custom properties here</a>.</p>
<p>Also there are a lot of great tutorials out there that cover CSS custom properties and how to use them for theming, so we’ll leave the theory to those other articles.</p>
<p>For a strategic guide on how to use CSS custom properties for theming check out this awesome article: <a target="_blank" href="https://www.smashingmagazine.com/2018/05/css-custom-properties-strategy-guide/">A Strategy Guide To CSS Custom Properties</a>.</p>
<p>Although we are not covering CSS custom properties in depth, I want to point out a few reasons why CSS custom properties are ideal for website theming:</p>
<ul>
<li><p>They are reusable – you can use them throughout your CSS</p>
</li>
<li><p>They reduce the complexity of our code, since you no longer need to create different stylesheet to achieve a theme-able website</p>
</li>
<li><p>They are available at runtime, which means you can update their value in the browser, via JavaScript, with immediate results.</p>
</li>
</ul>
<h2 id="heading-how-to-set-up-theme-properties-in-gatsbyjs">How to Set Up Theme Properties in Gatsby.js</h2>
<p>Of course you can hard code theme properties directly inside your CSS file like any other CSS properties. But having to scroll up a few lines of your CSS code anytime you want to make a few changes to your themes sounds tedious, right?</p>
<p><a target="_blank" href="https://mxb.dev/about/">Max Böck</a> in his article <a target="_blank" href="https://mxb.dev/blog/color-theme-switcher/">“Color Theme Switcher”</a> advises defining our themes in a central location.</p>
<p>Having a central location (file) where you can easily access and manage your themes sounds like an interesting idea. And this is the kind of thing Gatsby was made for.</p>
<p>Quoting the Gatsby docs:</p>
<blockquote>
<p>“A core feature of Gatsby.js is it’s ability to load data from anywhere.”</p>
</blockquote>
<p>This means you can source data from a JSON file which will be available at build time. When you import this data you can then iterate over it with the <code>Array.map</code> method and render it in a React component.</p>
<h3 id="heading-how-to-store-theme-properties">How to Store Theme Properties</h3>
<p>In your Gatsby project folder, create a directory called content if it doesn't already exists. Then add a new file called <code>themes.json</code> with the following content:</p>
<pre><code class="lang-json">[
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"default"</span>,
    <span class="hljs-attr">"colors"</span>: {
      <span class="hljs-attr">"primary-color"</span>: <span class="hljs-string">"#0250bb"</span>,
      <span class="hljs-attr">"text"</span>: <span class="hljs-string">"#20123a"</span>,
      <span class="hljs-attr">"text-alt"</span>: <span class="hljs-string">"#42425a"</span>,
      <span class="hljs-attr">"border"</span>: <span class="hljs-string">"#ededf0"</span>,
      <span class="hljs-attr">"background"</span>: <span class="hljs-string">"#ffffff"</span>,
      <span class="hljs-attr">"background-alt"</span>: <span class="hljs-string">"#f9f9fa"</span>,
      <span class="hljs-attr">"color-scheme"</span>: <span class="hljs-string">"light"</span>
    }
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"dark"</span>,
    <span class="hljs-attr">"colors"</span>: {
      <span class="hljs-attr">"primary-color"</span>: <span class="hljs-string">"#7f5af0"</span>,
      <span class="hljs-attr">"text"</span>: <span class="hljs-string">"#fffffe"</span>,
      <span class="hljs-attr">"text-alt"</span>: <span class="hljs-string">"#94a1b2"</span>,
      <span class="hljs-attr">"border"</span>: <span class="hljs-string">"#010101"</span>,
      <span class="hljs-attr">"background"</span>: <span class="hljs-string">"#16161a"</span>,
      <span class="hljs-attr">"background-alt"</span>: <span class="hljs-string">"#242629"</span>,
      <span class="hljs-attr">"color-scheme"</span>: <span class="hljs-string">"dark"</span>
    }
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"warm"</span>,
    <span class="hljs-attr">"colors"</span>: {
      <span class="hljs-attr">"primary-color"</span>: <span class="hljs-string">"#ff8e3c"</span>,
      <span class="hljs-attr">"text"</span>: <span class="hljs-string">"#0d0d0d"</span>,
      <span class="hljs-attr">"text-alt"</span>: <span class="hljs-string">"#2a2a2a"</span>,
      <span class="hljs-attr">"background"</span>: <span class="hljs-string">"#eff0f3"</span>,
      <span class="hljs-attr">"background-alt"</span>: <span class="hljs-string">"#fff"</span>,
      <span class="hljs-attr">"border"</span>: <span class="hljs-string">"rgba(0,0,0,.1)"</span>,
      <span class="hljs-attr">"color-scheme"</span>: <span class="hljs-string">"light"</span>
    }
  },
<span class="hljs-comment">// Add other themes here</span>
]
</code></pre>
<p>Each theme gets an <code>id</code>, a set of theme properties, and a CSS <code>color-scheme</code> property.</p>
<p>Here’s a tip – we use the CSS <code>color-scheme</code> property to tell which color scheme (light/dark) our webpage should be rendered in. For a better understanding of <code>color-scheme</code> please refer to this <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme">color scheme</a> guide.</p>
<h3 id="heading-how-to-transform-theme-properties-to-css-custom-properties">How to Transform Theme Properties to CSS Custom Properties</h3>
<p>Right now, the color themes stored in our <code>content/themes.json</code> files are just raw <strong>data</strong>. They need to be transformed into CSS custom properties before they can actually do anything meaningful.</p>
<blockquote>
<p><strong>Data</strong> is a collection of facts, such as numbers, <strong>words</strong>, measurements, observations or just descriptions of things.</p>
</blockquote>
<p>We are going to need our CSS custom properties to be dynamically generated and added as an inline <code>&lt;style&gt;</code> to the <code>&lt;head&gt;</code> of all our site pages.</p>
<p>You need to install two important plugins for this tutorial: react-helmet, a document head manager for React, and gatsby-plugin-react-helmet to allow server rendering of data that's added with React Helmet.</p>
<p>Install these plugins with this command:</p>
<pre><code class="lang-plaintext">npm installl gatsby-plugin-react-helmet react-helmet
</code></pre>
<p>To use these plugins you need to add it to the plugin array in your gatsby-config.js file located at the root of the project directory:</p>
<pre><code class="lang-plaintext">plugins: [gatsby-plugin-react-helmet]
</code></pre>
<p>Since you are going to use React helmet on all your pages, it makes sense to use it in your <code>Layout.js</code> file. In your <code>layout.js</code> file add the following code:</p>
<pre><code class="lang-js"><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> { Helmet } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-helmet"</span>
<span class="hljs-keyword">import</span> themes <span class="hljs-keyword">from</span> <span class="hljs-string">"../../content/themes.json"</span>
<span class="hljs-comment">// other imports</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Layout</span>(<span class="hljs-params">{ children }</span>) </span>{
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">colors</span>(<span class="hljs-params">theme</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">`
          --primary-color: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"primary-color"</span>]}</span>;
          --text: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"text"</span>]}</span>;
          --text-alt: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"text-alt"</span>]}</span>;
          --background: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"background"</span>]}</span>;
          --background-alt: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"background-alt"</span>]}</span>;
          --border: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"border"</span>]}</span>;
          --shadow: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"shadow"</span>]}</span>;
          color-scheme: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"color-scheme"</span>]}</span>;
    `</span>
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Helmet</span>&gt;</span>
        // other head meta tags

        <span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/css"</span>&gt;</span>{`
    ${themes
      .map(theme =&gt; {
        if (theme.id === "default") {
          return `
          :root {
            ${colors(theme)}
          }
        `
        } else if (theme.id === "dark") {
          return `
          @media (prefers-color-scheme: dark) {
            ${colors(theme)}
          }
        `
        }
      })
      .join("")}
    ${themes
      .map(theme =&gt; {
        return `
        [data-theme="${theme.id}"] {
          ${colors(theme)}
        }
      `
      })
      .join("")}
  `}
        <span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Helmet</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Header</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"main"</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Footer</span> /&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  )
}
</code></pre>
<p>Let's break this down a bit.</p>
<p>First, the themes and react-helmet are imported from <code>content/themes.json</code> and React respectively:</p>
<pre><code class="lang-js"><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> { Helmet } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-helmet"</span>
<span class="hljs-keyword">import</span> themes <span class="hljs-keyword">from</span> <span class="hljs-string">"../../content/themes.json"</span>
<span class="hljs-comment">// other imports</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Layout</span>(<span class="hljs-params">{ children }</span>) </span>{
  <span class="hljs-keyword">return</span> (

  )
}
</code></pre>
<p>It creates a function which will transform our themes to CSS custom properties:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">colors</span>(<span class="hljs-params">theme</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">`
          --primary-color: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"primary-color"</span>]}</span>;
          --text: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"text"</span>]}</span>;
          --text-alt: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"text-alt"</span>]}</span>;
          --background: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"background"</span>]}</span>;
          --background-alt: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"background-alt"</span>]}</span>;
          --border: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"border"</span>]}</span>;
          --shadow: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"shadow"</span>]}</span>;
          color-scheme: <span class="hljs-subst">${theme.colors[<span class="hljs-string">"color-scheme"</span>]}</span>;
    `</span>
  }
</code></pre>
<p>Inside our <code>&lt;Helmet&gt;</code> we add a <code>&lt;style&gt;</code> tag to our document’s head.</p>
<p>Here’s a tip – if you need to add a style to the document’s head, you have to render the style as a string within curly braces.</p>
<p>In the first <code>Array.map</code> method, we check if there’s a theme with <code>id</code> equal to <code>default</code>. If there is, we set it as our default color scheme in the <code>:root{}</code>. We also check if there’s a theme with <code>id</code> equal to <code>dark</code>. If there is, we use it when the <code>prefers-color-scheme</code> of the user is dark:</p>
<pre><code class="lang-js">${themes
      .map(<span class="hljs-function"><span class="hljs-params">theme</span> =&gt;</span> {
        <span class="hljs-keyword">if</span> (theme.id === <span class="hljs-string">"default"</span>) {
          <span class="hljs-keyword">return</span> <span class="hljs-string">`
          :root {
            <span class="hljs-subst">${colors(theme)}</span>
          }
        `</span>
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (theme.id === <span class="hljs-string">"dark"</span>) {
          <span class="hljs-keyword">return</span> <span class="hljs-string">`
          @media (prefers-color-scheme: dark) {
            <span class="hljs-subst">${colors(theme)}</span>
          }
        `</span>
        }
      })
      .join(<span class="hljs-string">""</span>)}
</code></pre>
<p>In the last <code>Array.map</code> method, we iterate over our themes and each theme gets a <code>[data-theme=""]</code> attribute selector:</p>
<pre><code class="lang-js"> ${themes
      .map(<span class="hljs-function"><span class="hljs-params">theme</span> =&gt;</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-string">`
        [data-theme="<span class="hljs-subst">${theme.id}</span>"] {
          <span class="hljs-subst">${colors(theme)}</span>
        }
      `</span>
      })
      .join(<span class="hljs-string">""</span>)}
</code></pre>
<p>Now if you inspect the head of your site you should see all the theme properties in your <code>content/themes.json</code> file nicely generated as CSS custom properties. In fact if you add the attribute <code>data-theme="name of your theme"</code> to your <code>html</code> tag via the dev tools, your theme should work perfectly well.</p>
<h2 id="heading-how-to-use-the-theme-switcher-component">How to Use the Theme Switcher Component</h2>
<p>Well, we can't have users manually editing our site via dev tools anytime they want to use a different theme on our site. So all that’s left in this tutorial is to create a UI so that users can easily <strong>Theme</strong> our website.</p>
<h3 id="heading-the-markup">The Markup</h3>
<p>Create a new file called <code>themes.js</code> in your components directory and add the following code:</p>
<pre><code class="lang-js"><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> themes <span class="hljs-keyword">from</span> <span class="hljs-string">"../../content/theme.json"</span>

<span class="hljs-keyword">const</span> Theme = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"theme"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"theme-close text-right"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>x<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"theme-wrapper__inner"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"theme-header text-center"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">strong</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"theme-title"</span>&gt;</span>Select Theme<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
            Please Note that Changes made here will affect other pages across
            the entire site.
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"theme-content"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"schemes"</span>&gt;</span>
            {theme.map(data =&gt; {
              return (
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"scheme"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"scheme-btn js-scheme-btn"</span>
                    <span class="hljs-attr">aria-label</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">data.id</span>}`}
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"scheme"</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">data.id</span>}`}
                    <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">backgroundColor:</span> `${<span class="hljs-attr">data.colors</span>["<span class="hljs-attr">background</span>"]}` }}
                  &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              )
            })}
          <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"theme-content"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"theme-range"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"font"</span> <span class="hljs-attr">title</span>=<span class="hljs-string">{state.font}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xsmall"</span>&gt;</span>Aa<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"range"</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"font"</span>
                <span class="hljs-attr">min</span>=<span class="hljs-string">"10"</span>
                <span class="hljs-attr">max</span>=<span class="hljs-string">"20"</span>
                <span class="hljs-attr">step</span>=<span class="hljs-string">"2"</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"theme-range__slider"</span>
              /&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-large"</span>&gt;</span>Aa<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Theme
</code></pre>
<p>Let’s break down this code a bit so we know what's going on.</p>
<p>First we import our themes from content/themes.js and iterate over it with a <code>Array.map</code> method. For each theme, I created a button with a background color equal to its <code>background-color</code> with a value equal to its <code>id</code>.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"schemes"</span>&gt;</span>
            {theme.map(data =&gt; {
              return (
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"scheme"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"scheme-btn js-scheme-btn"</span>
                    <span class="hljs-attr">aria-label</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">data.id</span>}`}
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"scheme"</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">data.id</span>}`}
                    <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">backgroundColor:</span> `${<span class="hljs-attr">data.colors</span>["<span class="hljs-attr">background</span>"]}` }}
                  &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              )
            })}
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
</code></pre>
<p>To change the font size of our text, I also added an <code>input</code> field of type <code>range</code> with a <code>min</code> value of <code>10px</code> and <code>max</code> value of <code>20px</code>.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span>
  <span class="hljs-attr">type</span>=<span class="hljs-string">"range"</span>
  <span class="hljs-attr">name</span>=<span class="hljs-string">"font"</span>
  <span class="hljs-attr">min</span>=<span class="hljs-string">"10"</span>
  <span class="hljs-attr">max</span>=<span class="hljs-string">"20"</span>
  <span class="hljs-attr">step</span>=<span class="hljs-string">"2"</span>
  <span class="hljs-attr">className</span>=<span class="hljs-string">"theme-range__slider"</span>
  /&gt;</span>
</code></pre>
<p>With some added CSS (which we won't cover in this tutorial) we now have a UI that looks like the one below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/localhost_8000_--13-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>iamspruce.dev customize theme UI</em></p>
<h3 id="heading-how-to-set-up-the-state">How to Set Up the State</h3>
<p>We'll start by importing the <code>useState()</code> hook from React:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState} <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-keyword">const</span> Theme = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">return</span> (
  )
}
</code></pre>
<p>We use React <a target="_blank" href="https://reactjs.org/docs/hooks-reference.html#lazy-initial-state">Lazy Initialization</a>, which lets us pass a function to <code>useState()</code> that we'll use during the initial render.</p>
<p>Quoting the React docs:</p>
<blockquote>
<p>"If the initial state is the result of an expensive calculation, you may provide a function instead, which will be executed only in the initial render."</p>
</blockquote>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState} <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> themes <span class="hljs-keyword">from</span> <span class="hljs-string">"../../content/theme.json"</span>

<span class="hljs-keyword">const</span> Theme = <span class="hljs-function">() =&gt;</span> {
 <span class="hljs-keyword">const</span> [state, setState] = useState(<span class="hljs-function">() =&gt;</span> {
     <span class="hljs-keyword">const</span> localVal =
       <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>.localStorage.getItem(<span class="hljs-string">"theme"</span>)
     <span class="hljs-keyword">let</span> obj = {
       <span class="hljs-attr">font</span>: <span class="hljs-number">15</span>,
       <span class="hljs-attr">scheme</span>: <span class="hljs-string">"default"</span>,
     }
     <span class="hljs-keyword">return</span> localVal !== <span class="hljs-literal">null</span> ? <span class="hljs-built_in">JSON</span>.parse(localVal) : obj
   })
  <span class="hljs-keyword">return</span> (

  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Theme
</code></pre>
<p>In our case, we’re using it to check for the value in <code>localStorage()</code>. If the value exists, will use that as our initial value. Otherwise, will use the default <code>obj</code>.</p>
<p>We’re checking if the window object exists <code>(typeof window !== “undefined”)</code> because at build time the window’s object does not exist. If you run <code>gatsby build</code> without checking if the windows object exists or not, you’ll get an error that looks like this:</p>
<p><code>WebpackError: ReferenceError: localStorage is not defined</code></p>
<h3 id="heading-how-to-update-the-state">How to Update the State</h3>
<p>The next step is to have an <code>onClick</code> and <code>onChange</code> eventListener update our state. For that we are going to create a function:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState} <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> themes <span class="hljs-keyword">from</span> <span class="hljs-string">"../../content/theme.json"</span>

<span class="hljs-keyword">const</span> Theme = <span class="hljs-function">() =&gt;</span> {
 <span class="hljs-keyword">const</span> [state, setState] = useState(<span class="hljs-function">() =&gt;</span> {
     <span class="hljs-keyword">const</span> localVal =
       <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>.localStorage.getItem(<span class="hljs-string">"theme"</span>)
     <span class="hljs-keyword">let</span> obj = {
       <span class="hljs-attr">font</span>: <span class="hljs-number">15</span>,
       <span class="hljs-attr">scheme</span>: <span class="hljs-string">"default"</span>,
     }
     <span class="hljs-keyword">return</span> localVal !== <span class="hljs-literal">null</span> ? <span class="hljs-built_in">JSON</span>.parse(localVal) : obj
   })
<span class="hljs-comment">// the update function</span>
  <span class="hljs-keyword">const</span> update = <span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
    <span class="hljs-keyword">const</span> { name, value } = e.target
    setState(<span class="hljs-function"><span class="hljs-params">prevState</span> =&gt;</span> ({
      ...prevState,
      [name]: value,
    }))
  }

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

  )
}
</code></pre>
<p>We passed in a Object as an initial value for our <code>useState</code> because we can update multiple states with one <code>useState</code> hook. We now need to set the update function on our UI:</p>
<pre><code class="lang-js">...
{theme.map(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"scheme"</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
       <span class="hljs-attr">onClick</span>=<span class="hljs-string">{update}</span> // <span class="hljs-attr">set</span> <span class="hljs-attr">the</span> <span class="hljs-attr">update</span> <span class="hljs-attr">function</span> <span class="hljs-attr">to</span> <span class="hljs-attr">an</span> <span class="hljs-attr">Onclick</span> <span class="hljs-attr">event</span> 
       <span class="hljs-attr">className</span>=<span class="hljs-string">"scheme-btn js-scheme-btn"</span>
       <span class="hljs-attr">aria-label</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">data.id</span>}`}
       <span class="hljs-attr">name</span>=<span class="hljs-string">"scheme"</span>
       <span class="hljs-attr">value</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">data.id</span>}`}
       <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">backgroundColor:</span> `${<span class="hljs-attr">data.colors</span>["<span class="hljs-attr">background</span>"]}` }}
       &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
   )
})}

&lt;input
  type=<span class="hljs-string">"range"</span>
  name=<span class="hljs-string">"font"</span>
  min=<span class="hljs-string">"10"</span>
  max=<span class="hljs-string">"20"</span>
  step=<span class="hljs-string">"2"</span>
  className=<span class="hljs-string">"theme-range__slider"</span>
  onChange={update} <span class="hljs-comment">// set the update function to an Onchange event</span>
  value={state.font}
/&gt;
</code></pre>
<h3 id="heading-how-to-persist-our-changes-in-localstorage">How to Persist Our Changes In LocalStorage</h3>
<p>The final step is to make sure we update <code>localStorage</code> and our website with the current values from our state whenever the state value changes. For that we’ll use the <code>useEffect</code> Hook, which lets us <strong>run some code after React has updated the DOM.</strong></p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState} <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> themes <span class="hljs-keyword">from</span> <span class="hljs-string">"../../content/theme.json"</span>

<span class="hljs-keyword">const</span> Theme = <span class="hljs-function">() =&gt;</span> {
 <span class="hljs-keyword">const</span> [state, setState] = useState(<span class="hljs-function">() =&gt;</span> {
     <span class="hljs-keyword">const</span> localVal =
       <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>.localStorage.getItem(<span class="hljs-string">"theme"</span>)
     <span class="hljs-keyword">let</span> obj = {
       <span class="hljs-attr">font</span>: <span class="hljs-number">15</span>,
       <span class="hljs-attr">scheme</span>: <span class="hljs-string">"default"</span>,
     }
     <span class="hljs-keyword">return</span> localVal !== <span class="hljs-literal">null</span> ? <span class="hljs-built_in">JSON</span>.parse(localVal) : obj
   })

  <span class="hljs-keyword">const</span> update = <span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
    <span class="hljs-keyword">const</span> { name, value } = e.target
    setState(<span class="hljs-function"><span class="hljs-params">prevState</span> =&gt;</span> ({
      ...prevState,
      [name]: value,
    }))
  }

<span class="hljs-comment">// persisting state to localStorage</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">window</span>.localStorage.setItem(<span class="hljs-string">"theme"</span>, <span class="hljs-built_in">JSON</span>.stringify(state))
    <span class="hljs-keyword">let</span> root = <span class="hljs-built_in">document</span>.documentElement
    root.setAttribute(<span class="hljs-string">"data-theme"</span>, state.scheme)
    root.style.setProperty(<span class="hljs-string">"--font-size"</span>, <span class="hljs-string">`<span class="hljs-subst">${state.font}</span>px`</span>)
  }, [state])

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

  )
}
</code></pre>
<p>Congratulations! If you made it this far you now have a complete user theme-able website. The overall design of our <strong>switch theme UI</strong> now looks like this:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/cMboQU-qwyE" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<p>For a live preview of the site, visit <a target="_blank" href="https://www.iamspruce.dev/">https://www.iamspruce.dev/</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>There's really no limit with what you can do with <strong>theming</strong>. Although this tutorial uses Gatsby.js, you can easily apply these concepts to other React-based static site generators.</p>
<p>If you found this tutorial useful, kindly follow me on Twitter <a target="_blank" href="https://twitter.com/sprucekhalifa">@sprucekhalifa</a> .</p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn the CSS Box-Shadow Property by Coding a Beautiful Button ✨ ]]>
                </title>
                <description>
                    <![CDATA[ Today we're gonna learn how to use CSS's box-shadow property to make beautiful website components. Along the way, we'll create a button and get hands-on experience using this property. Let's get started. 🎖️ Table of Contents Why you should use the ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/css-box-shadow-property-with-examples/</link>
                <guid isPermaLink="false">66b2094ca5be9a107f4341c5</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ css properties ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Design ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joy Shaheb ]]>
                </dc:creator>
                <pubDate>Wed, 30 Jun 2021 18:49:49 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/06/FCC-Thumbnail.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Today we're gonna learn how to use CSS's <strong>box-shadow</strong> property to make beautiful website components. Along the way, we'll <strong>create a button</strong> and get hands-on experience using this property. Let's get started. 🎖️</p>
<h1 id="heading-table-of-contents">Table of Contents</h1>
<ul>
<li><a class="post-section-overview" href="#heading-why-should-you-use-the-css-box-shadow-property"><strong>Why</strong> you should use the CSS box-shadow property</a></li>
<li><a class="post-section-overview" href="#heading-the-syntax-of-the-box-shadow-property">The <strong>syntax</strong> of the box-shadow property</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-a-drop-shadow-to-a-button">How to make a <strong>button</strong> using the box-shadow property</a></li>
<li><a class="post-section-overview" href="#heading-additional-resources">Additional Resources</a> </li>
<li><a class="post-section-overview" href="#heading-what-is-inset-in-the-css-box-shadow-property">What is <strong>inset</strong> in</a> CSS <strong>Box shadow property</strong>?</li>
</ul>
<h2 id="heading-you-can-watch-this-tutorial-on-youtube-as-well-if-you-like"><strong>You can watch this tutorial on YouTube as well if you like:</strong></h2>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/4Clc-Bb5sY4" 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-why-should-you-use-the-css-box-shadow-property">Why Should You Use The CSS box-shadow Property?</h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Frame-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><strong>Attention to small details</strong> separates a good website from an excellent looking website. If you want to add those small details to your website, you should definitely use this property along with many other properties.</p>
<p>Let's took at some examples. 👇</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Page-1--1-.png" alt="Image" width="600" height="400" loading="lazy">
<em><strong>A Website Design</strong></em></p>
<p>Pay close attention to the button components in the image above. You'll see that we have some drop shadows. ☝</p>
<p>Let's examine these buttons even further: 👇</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Frame-27.png" alt="Image" width="600" height="400" loading="lazy">
<em><strong>Button with no box-shadow property</strong></em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Frame-28.png" alt="Image" width="600" height="400" loading="lazy">
<em><strong>Button using the box-shadow property</strong></em></p>
<p>You can tell that the latter one looks more dynamic and interesting, as it has more <strong>attention to detail.</strong> This is called a <strong>drop shadow effect</strong>. Let's see how we can implement it in our code.</p>
<h1 id="heading-project-setup"><strong>Project Setup</strong></h1>
<h3 id="heading-html">HTML</h3>
<p>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">"box-1"</span>&gt;</span> A Button <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h3 id="heading-css">CSS</h3>
<p>Clear your default browser settings like this:</p>
<pre><code class="lang-css">*{
   <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-attribute">font-family</span>: sans-serif;
}
</code></pre>
<p>Now, let's create a button with the following code:👇</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.box-1</span>{
   <span class="hljs-attribute">margin</span>: <span class="hljs-number">100px</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">100px</span>;
   <span class="hljs-attribute">height</span>: <span class="hljs-number">80px</span>;
   <span class="hljs-attribute">width</span>: <span class="hljs-number">200px</span>;
   <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid black;
   <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>;
   <span class="hljs-attribute">font-size</span>: <span class="hljs-number">40px</span>;

   <span class="hljs-attribute">display</span>: grid;
   <span class="hljs-attribute">place-content</span>: center;
}
</code></pre>
<p>We're all set, now let's start coding!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Frame-2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h1 id="heading-the-syntax-of-the-box-shadow-property">The Syntax of the box-shadow Property</h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Frame-3-1.png" alt="Image" width="600" height="400" loading="lazy">
<em><strong>All the inputs of box-shadow property</strong></em></p>
<p>Here's the syntax for the box-shadow property: 👇</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">box-shadow</span>: <span class="hljs-selector-tag">offset-x</span> | <span class="hljs-selector-tag">offset-y</span> | <span class="hljs-selector-tag">blur-radius</span> | <span class="hljs-selector-tag">spread-radius</span> | <span class="hljs-selector-tag">color</span> ;
</code></pre>
<p>Let's look at each part in more detail.</p>
<h2 id="heading-how-to-use-offset-x-in-the-box-shadow-property">How to Use Offset-x in the box-shadow Property</h2>
<p>You'll use the offset-x property to move the shadow left and right along the X-Axis. Here's a demo to show you how that looks:👇</p>
<p><img src="https://media.giphy.com/media/Mzxh8CdUTaxgzzj9ml/giphy.gif" alt="Image" width="480" height="226" loading="lazy">
<em><strong>We can move the shadow left &amp; right</strong></em></p>
<p>The recreate these results, write the following code in your CSS: 👇</p>
<pre><code class="lang-css"><span class="hljs-comment">/* offset-x | offset-y | color */</span>
<span class="hljs-selector-class">.box-1</span>{
   <span class="hljs-attribute">box-shadow</span>: -<span class="hljs-number">50px</span> <span class="hljs-number">0px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0.5</span>);
}

<span class="hljs-comment">/*Or, you can write*/</span>

<span class="hljs-selector-class">.box-1</span>{
   <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">50px</span> <span class="hljs-number">0px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0.5</span>);
}
</code></pre>
<h2 id="heading-how-to-use-offset-y-in-the-box-shadow-property">How to Use Offset-y in the box-shadow Property</h2>
<p>You'll use the offset-y property to move the shadow up and down along the Y-Axis. Here's a demo of how that looks:👇</p>
<p><img src="https://media.giphy.com/media/Ss9Qnrq9PFBpAfVLk8/giphy.gif" alt="Image" width="480" height="226" loading="lazy">
<em><strong>We can move the shadow top &amp; bottom</strong></em></p>
<p>To recreate these results write the following in your CSS: 👇</p>
<pre><code class="lang-css"><span class="hljs-comment">/* offset-x | offset-y | color */</span>
<span class="hljs-selector-class">.box-1</span>{
   <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0px</span> -<span class="hljs-number">50px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0.5</span>);
}

<span class="hljs-comment">/*Or, you can write*/</span>

<span class="hljs-selector-class">.box-1</span>{
   <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0px</span> -<span class="hljs-number">50px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0.5</span>);
}
</code></pre>
<h3 id="heading-how-to-combine-both-offset-x-and-offset-y">How to Combine Both offset-x and offset-y</h3>
<p>Write the following code in your CSS: 👇</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.box-1</span>{
   <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">10px</span> <span class="hljs-number">10px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0.5</span>);
}
</code></pre>
<p>Here's the result with the box shadow showing on the right and bottom of the button: 👇</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Frame-6-1.png" alt="Image" width="600" height="400" loading="lazy">
<em><strong>Our button with box shadow</strong></em></p>
<h2 id="heading-how-to-use-blur-radius-in-the-box-shadow-property">How to Use blur-radius in the box-shadow Property</h2>
<p>The blur-radius property will blur <strong>the color</strong> around our button, like this:👇</p>
<p><img src="https://media.giphy.com/media/5fRA7jzOwtmXnT57Ne/giphy.gif" alt="Image" width="480" height="216" loading="lazy">
<em><strong>Experimenting w/ blur radius</strong></em></p>
<p>To duplicate the results, write the following in your CSS: 👇</p>
<pre><code class="lang-css"><span class="hljs-comment">/* offset-x | offset-y | blur-radius | color */</span>

<span class="hljs-selector-class">.box-1</span>{
<span class="hljs-comment">/* play around with 👇 this */</span>
   <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">50px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0.8</span>);
}
</code></pre>
<h2 id="heading-how-to-use-spread-radius-in-the-box-shadow-property">How to Use spread-radius in the box-shadow Property</h2>
<p>This value spreads our shadow around our button, like this: 👇</p>
<p><img src="https://media.giphy.com/media/FfVw2vxOonQAjkFc7B/giphy.gif" alt="Image" width="480" height="216" loading="lazy">
<em><strong>Experimenting w/ spread radius</strong></em></p>
<p>Let's recreate the results with the following CSS code:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* offset-x | offset-y | blur-radius | spread-radius | color */</span>

<span class="hljs-selector-class">.box-1</span>{
<span class="hljs-comment">/*  play around with 👇 this */</span>
   <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">50px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0.5</span>);
}
</code></pre>
<h1 id="heading-how-to-add-a-drop-shadow-to-a-button">How to Add a Drop Shadow to a Button</h1>
<p>Let's put together what we've learned so far and add a drop shadow effect to our button: 👇</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.box-1</span>{
   <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">8px</span> <span class="hljs-number">10px</span> <span class="hljs-number">10px</span> <span class="hljs-number">1px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0.5</span>);
}
</code></pre>
<p>The result looks like this: 👇</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Frame-6--1--1.png" alt="Image" width="600" height="400" loading="lazy">
<em><strong>The result</strong></em></p>
<h1 id="heading-additional-resources">Additional Resources</h1>
<ul>
<li>[<a target="_blank" href="https://getcssscan.com/css-box-shadow-examples">GetCssScan</a>] - To get readymade box shadows</li>
<li>[<a target="_blank" href="https://keyframes.app/animate/">keyframes.app</a>] - to test and practice these properties in real time</li>
<li><a target="_blank" href="https://flatuicolors.com/">flatuicolors</a> - Beautiful color palettes</li>
</ul>
<h2 id="heading-bonus-tip">✨ Bonus Tip ✨</h2>
<h1 id="heading-what-is-inset-in-the-css-box-shadow-property">What is Inset in the CSS box-shadow Property?</h1>
<p>There's a keyword named <code>inset</code> that you can use with the box-shadow property. This puts the shadow inside our button instead of spreading it around the outside. Write this CSS code to experiment with it:👇</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.box-1</span>{
   <span class="hljs-attribute">box-shadow</span>: inset <span class="hljs-number">8px</span> <span class="hljs-number">10px</span> <span class="hljs-number">10px</span> <span class="hljs-number">1px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0.5</span>);
}
</code></pre>
<p>Here's the result: 👇</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Frame-6--2--4.png" alt="Image" width="600" height="400" loading="lazy">
<em><strong>Effect of the inset keyword</strong></em></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Now you can confidently use the box-shadow property to add not only <strong>drop shadows</strong> but also to add more <strong>attention to detail</strong> to your projects.</p>
<p>Here's your medal for reading till 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="usxsz1lstuwry3jlly4d" width="1000" height="245" loading="lazy"></p>
<ul>
<li><strong>YouTube<a target="_blank" href="https://youtube.com/c/joyshaheb"> / Joy Shaheb</a></strong></li>
<li><strong>LinkedIn<a target="_blank" href="https://www.linkedin.com/in/joyshaheb/"> / JoyShaheb</a></strong></li>
<li><strong>Twitter<a target="_blank" href="https://twitter.com/JoyShaheb"> / JoyShaheb</a></strong></li>
<li><strong>Instagram<a target="_blank" href="https://www.instagram.com/joyshaheb/"> / JoyShaheb</a></strong></li>
</ul>
<h1 id="heading-credits">Credits</h1>
<ul>
<li><a target="_blank" href="https://www.freepik.com/free-vector/young-girl-thinking-face-wondering-cartoon-illustration_11652601.htm#page=1&amp;query=worried%20illustration&amp;position=31">Young Girl</a></li>
<li><a target="_blank" href="https://www.freepik.com/free-vector/cute-cat-playing-with-box-cartoon_13747509.htm?query=happy%20illustration">Cute Kat</a>, <a target="_blank" href="https://www.freepik.com/free-vector/kawaii-cat-unicorn-character-collection_5481560.htm">Unicorn cat</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Box Shadow CSS Tutorial – How to Add a Drop Shadow to Any HTML Element ]]>
                </title>
                <description>
                    <![CDATA[ By Joe Liang We can add a drop shadow to any HTML element using the CSS property box-shadow. Here's how. ##Adding a Basic Drop Shadow Let's first set up some basic HTML elements to add our drop shadows to: ```html Box1 Box2 Box3 Then add some basic ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/css-tutorial-drop-shadow/</link>
                <guid isPermaLink="false">66d45f65706b9fb1c166b989</guid>
                
                    <category>
                        <![CDATA[ #box-shadow ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ css properties ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS3 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Pure CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 18 May 2020 13:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/05/feature.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Joe Liang</p>
<p>We can add a drop shadow to any HTML element using the CSS property <code>box-shadow</code>. Here's how.</p>
<p>##Adding a Basic Drop Shadow</p>
<p>Let's first set up some basic HTML elements to add our drop shadows to:</p>
<p>```html</p>
<div id="box1" class="box">Box1</div>
<div id="box2" class="box">Box2</div>
<div id="box3" class="box">Box3</div>

<p>Then add some basic CSS:</p>
<p>```css
p {
    padding: 10px;
}
.box {
    padding: 20px;
    width: 50%;
    margin: 30px auto;
    background: #000;
    color: #fff;
}</p>
<p>The result is just three black boxes that will be easy for us to add drop shadows to by calling their unique id's:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/html-elements-1.png" alt="HTML elements setup" width="600" height="400" loading="lazy">
<em>HTML elements setup</em></p>
<p>To add a basic drop shadow, let's use the <code>box-shadow</code> property on the Box 1:</p>
<p>```css
/<em> offset-x | offset-y | color </em>/</p>
<p>#box1 {
    box-shadow: 6px 12px yellow;
}</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/box1.png" alt="Adding a basic drop shadow to Box 1" width="600" height="400" loading="lazy">
<em>Adding a basic drop shadow to Box 1</em></p>
<p>We have 3 parameters here. The first 2 are, respectively, the x-offset and y-offset. They set the location of the drop shadow.</p>
<p>The offset is relative to the origin, which in HTML is always the top left corner of an element. A positive x-offset will move the shadow to the right, and a positive y-offset will move the shadow downwards.</p>
<p>The third parameter is the color of your drop shadow.</p>
<p>Keep in mind that although we used <code>&lt;div&gt;</code> elements here, the <code>box-shadow</code> property can be applied to any other HTML element as well.</p>
<p>##Adding a Blur Radius</p>
<p>If we want the shadow to look a little more realistic, we will want to experiment with the <code>blur-radius</code> parameter.</p>
<p>This parameter controls how much to blur the shadow such that it becomes bigger and lighter. Let's apply it to Box 2:</p>
<p>```css
/<em> offset-x | offset-y | blur-radius | color </em>/</p>
<p>#box2 {
    box-shadow: 6px 12px 4px red;
}</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/box2-blur.png" alt="Adding a blur radius to Box 2" width="600" height="400" loading="lazy">
<em>Adding a blur radius to Box 2</em></p>
<p>The value of 4px sets the radius of the blur to apply to our drop shadow.</p>
<p>##Adding a Spread Radius</p>
<p>If we want to control the size of the shadow, we can use the <code>spread-radius</code> parameter which controls how much a shadow grows or shrinks.</p>
<p>Let's add a spread radius of 8px to Box 2:</p>
<p>```css
/<em> offset-x | offset-y | blur-radius | spread-radius | color </em>/</p>
<p>#box2 {
    box-shadow: 6px 12px 4px 8px red;
}</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/box2-blur-and-spread.png" alt="Adding a spread radius in addition to a blur to Box 2" width="600" height="400" loading="lazy">
<em>Adding a spread radius in addition to a blur to Box 2</em></p>
<p>Remember the order of these parameters!</p>
<p>##Combining Multiple Shadows in a Single Property</p>
<p>If we want to get fancy, we can add multiple drop shadows to an element using a single <code>box-shadow</code> property.</p>
<p>Let's do that with Box 3 by simultaneously adding a blue and green drop shadow:</p>
<p>```css
/<em> Any number of shadows, separated by commas </em>/</p>
<p>#box3 {
    box-shadow: 6px 12px 2px 2px blue, -6px -12px 2px 2px green;
}</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/box3.png" alt="combine multiple drop shadows" width="600" height="400" loading="lazy">
<em>Adding multiple drop shadows to Box 3</em></p>
<p>##Bonus: Create an Inset Shadow</p>
<p>While it will not create a drop shadow, the <code>inset</code> parameter can also be used with the <code>box-shadow</code> property.</p>
<p>As the name suggests, this parameter creates an inset shadow (i.e. shadow inside a box).</p>
<p>The <code>inset</code> parameter can be placed either at the beginning or the end of the 
<code>box-shadow</code> property. Here we demonstrate its use with a <code>blockquote</code> element.</p>
<p>HTML:</p>
<p>```html</p>
<blockquote>
  <q>The key to success is to start before you're ready.</q>
  <p>— Marie Forleo</p>
</blockquote>

<p>CSS:</p>
<p>```css
blockquote {
  width: 50%;
  margin: 50px auto;
  padding: 20px;
  font-size: 24px;
  box-shadow: inset 10px 5px black;
}</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/blockquote.png" alt="Create an inset shadow" width="600" height="400" loading="lazy">
<em>Create an inset shadow</em></p>
<p>Of course you can add some blur and spread to enhance the shadow, or even multiple shadows:</p>
<p>```css
 box-shadow: inset 10px 5px 25px 5px black, 5px 5px 12px 2px black;</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/blockquote-enhanced.png" alt="Inset shadow combined with drop shadow" width="600" height="400" loading="lazy">
<em>Inset shadow combined with drop shadow</em></p>
<p>With the <code>box-shadow</code> property, we can easily make elements on a web page stand out to create a nice 3D lighting effect.</p>
<p>If you want to do some experimenting yourself, here's a <a target="_blank" href="https://codepen.io/1000mileworld/pen/dyYeggy">code pen</a> I created with the examples used in this tutorial.</p>
<p>Play around and see what you can come up with!</p>
<p>##Want to See More Web Development Tips and Knowledge?</p>
<ul>
<li><a target="_blank" href="https://1000mileworld.com/#post">Subscribe</a> to my weekly newsletter</li>
<li>Visit my blog at  <a target="_blank" href="https://1000mileworld.com/">1000 Mile World</a></li>
<li><a target="_blank" href="https://twitter.com/1000mileworld">Follow me</a> on Twitter</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ CSS Background Image – How to Add an Image URL to Your Div ]]>
                </title>
                <description>
                    <![CDATA[ By Amy Haddad Say you want to put an image or two on a webpage. One way is to use the background-image CSS property.  This property applies one or more background images to an element, like a <div>, as the documentation explains. Use it for aesthetic... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-add-an-image-url-to-your-div/</link>
                <guid isPermaLink="false">66d45d9dcc7f04d2549a3730</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ css properties ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                    <category>
                        <![CDATA[ programing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sun, 05 Apr 2020 11:22:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/06/w-qjCHPZbeXCQ-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Amy Haddad</p>
<p>Say you want to put an image or two on a webpage. One way is to use the <strong><code>background-image</code></strong> CSS property. </p>
<p>This property applies one or more background images to an element, like a <strong><code>&lt;div&gt;</code>,</strong> as the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/background-image">documentation</a> explains. Use it for aesthetic reasons, such as adding a textured background to your webpage.</p>
<h1 id="heading-add-an-image">Add an Image</h1>
<p>It’s easy to add an image using the <code>background-image</code> property. Just provide the path to the image in the <code>url()</code> value.</p>
<p>The image path can be a URL, as shown in the example below:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
   <span class="hljs-comment">/* Background pattern from Toptal Subtle Patterns */</span>
   <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">"https://amymhaddad.s3.amazonaws.com/morocco-blue.png"</span>);
   <span class="hljs-attribute">height</span>: <span class="hljs-number">400px</span>;
   <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}
</code></pre>
<p>Or it can be a local path. Here’s an example:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
   <span class="hljs-comment">/* Background pattern from Toptal Subtle Patterns */</span>
   <span class="hljs-attribute">height</span>: <span class="hljs-number">400px</span>;
   <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
   <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">"./images/oriental-tiles.png"</span>);
}
</code></pre>
<h1 id="heading-add-multiple-images">Add Multiple Images</h1>
<p>You can apply multiple images to the <code>background-image</code> property.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
<span class="hljs-comment">/* Background pattern from Toptal Subtle Patterns */</span>
   <span class="hljs-attribute">height</span>: <span class="hljs-number">400px</span>;
   <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
   <span class="hljs-attribute">background-image</span>: 
       <span class="hljs-built_in">url</span>(<span class="hljs-string">"https://amymhaddad.s3.amazonaws.com/morocco-blue.png"</span>),
       <span class="hljs-built_in">url</span>(<span class="hljs-string">"https://amymhaddad.s3.amazonaws.com/oriental-tiles.png"</span>);
   <span class="hljs-attribute">background-repeat</span>: no-repeat, no-repeat;
   <span class="hljs-attribute">background-position</span>: right, left; 
}
</code></pre>
<p>That’s a lot of code. Let’s break it down.</p>
<p>Separate each image <code>url()</code> value with a comma.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">background-image</span>: 
    <span class="hljs-selector-tag">url</span>("<span class="hljs-selector-tag">https</span>://<span class="hljs-selector-tag">amymhaddad</span><span class="hljs-selector-class">.s3</span><span class="hljs-selector-class">.amazonaws</span><span class="hljs-selector-class">.com</span>/<span class="hljs-selector-tag">morocco-blue</span><span class="hljs-selector-class">.png</span>"),
    <span class="hljs-selector-tag">url</span>("<span class="hljs-selector-tag">https</span>://<span class="hljs-selector-tag">amymhaddad</span><span class="hljs-selector-class">.s3</span><span class="hljs-selector-class">.amazonaws</span><span class="hljs-selector-class">.com</span>/<span class="hljs-selector-tag">oriental-tiles</span><span class="hljs-selector-class">.png</span>");
</code></pre>
<p>Now position and enhance your images by applying additional properties.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">background-repeat</span>: <span class="hljs-selector-tag">no-repeat</span>, <span class="hljs-selector-tag">no-repeat</span>;
<span class="hljs-selector-tag">background-position</span>: <span class="hljs-selector-tag">right</span>, <span class="hljs-selector-tag">left</span>;
</code></pre>
<p>There are several <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Backgrounds_and_Borders/Using_multiple_backgrounds">sub-properties</a> you can add to your background images, such as <strong><code>background-repeat</code></strong> and <strong><code>background-position</code></strong>, which we used in the above example. You can even add <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/gradient">gradients</a> to a background image.</p>
<p>See what it looks like when we put everything together.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/amymhaddad/embed/VwLqWbm" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<h1 id="heading-order-matters">Order Matters</h1>
<p>The order that you list your images in matters because of the stacking order. That means the first image listed is nearest to the user, according to the <a target="_blank" href="https://www.w3.org/TR/css-backgrounds-3/#layering">documentation</a>. Then, the next one, and the next, and so on. </p>
<p>Here’s an example.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
<span class="hljs-comment">/* Background pattern from Toptal Subtle Patterns */</span>
   <span class="hljs-attribute">height</span>: <span class="hljs-number">400px</span>;
   <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
   <span class="hljs-attribute">background-image</span>: 
       <span class="hljs-built_in">url</span>(<span class="hljs-string">"https://amymhaddad.s3.amazonaws.com/morocco-blue.png"</span>),
       <span class="hljs-built_in">url</span>(<span class="hljs-string">"https://amymhaddad.s3.amazonaws.com/oriental-tiles.png"</span>);
   <span class="hljs-attribute">background-repeat</span>: no-repeat, no-repeat;
}
</code></pre>
<p>We’ve listed two images in the code above. The first image (morocco-blue.png) will be in front of the second (oriental-tiles.png). Both images are the same size and lack opacity, so we only see the first image.</p>
<p>But if we move the second image (oriental-tiles.png) over to the right by 200 pixels, then you can see part of it (the rest remains hidden).</p>
<p>Here’s what it looks like when we put everything together.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/amymhaddad/embed/oNXrXMo" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<h2 id="heading-when-should-you-use-background-image">When Should You Use Background Image?</h2>
<p>There’s a lot to like about the <code>background-image</code> property. But there’s a drawback. </p>
<p>The image may not be accessible to all users, the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/background-image">documentation</a> points out, like those who use screen readers.</p>
<p>That’s because you can’t add textual information to the <code>background-image</code> property. As a result, the image will be missed by screen readers.</p>
<p>Use the <code>background-image</code> property only when you need to add some decoration to your page. Otherwise, use the HTML <strong><code>&lt;img&gt;</code></strong> element if an image has meaning or purpose, as the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/background-image">documentation</a> notes.</p>
<p>That way, you can add text to an image element, using the <strong><code>alt</code></strong> attribute, which <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img">describes the image</a>. The provided text will be picked up by screen readers.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"house"</span> 
       <span class="hljs-attr">src</span>=<span class="hljs-string">"./images/farnsworth_house.jpeg"</span>
       <span class="hljs-attr">alt</span>=<span class="hljs-string">"A glass house designed by Ludwig Mies van der Rohe located in Plano, Illinois."</span>&gt;</span>
</code></pre>
<p>Think of it this way: <code>background-image</code> is a CSS property, and CSS focuses on presentation or style; HTML focuses on semantics or meaning. </p>
<p>When it comes to images, you’ve got options. If an image is needed for decoration, then the <code>background-image</code> property may be a good choice for you.</p>
<p><em>I write about learning to program and the best ways to go about it (</em><a target="_blank" href="https://amymhaddad.com/">amymhaddad.com</a>).  </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to create responsive tables with pure CSS using Grid Layout Module ]]>
                </title>
                <description>
                    <![CDATA[ By Shingo Nakayama TL;DR The most popular way to display a collection of similar data is to use tables, but HTML tables have the drawback of being difficult to make responsive. In this article, I use CSS Grid Layout Module and CSS Properties (and no ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/https-medium-com-nakayama-shingo-creating-responsive-tables-with-pure-css-using-the-grid-layout-module-8e0ea8f03e83/</link>
                <guid isPermaLink="false">66d460ee57503cc72873ded6</guid>
                
                    <category>
                        <![CDATA[ css properties ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Datatables ]]>
                    </category>
                
                    <category>
                        <![CDATA[ flexbox ]]>
                    </category>
                
                    <category>
                        <![CDATA[ grid layout ]]>
                    </category>
                
                    <category>
                        <![CDATA[ responsive design ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 26 Feb 2019 06:17:06 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*CthvMCprY75MLB_q8BygXg.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Shingo Nakayama</p>
<h3 id="heading-tldr">TL;DR</h3>
<p>The most popular way to display a collection of similar data is to use tables, but HTML tables have the drawback of being difficult to make responsive.</p>
<p>In this article, I use CSS Grid Layout Module and CSS Properties (and no Javascript) to layout tables that wrap columns depending on screen width, which further changes to a card based on layout for small screens.</p>
<p>For the impatient, look at the following pen for a prototypical implementation.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/ShingoNakayama/embed/LMLeRZ" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<h3 id="heading-a-little-history-of-responsive-html-tables">A Little History of Responsive HTML Tables</h3>
<p>Responsive tables aren’t a new topic, and there are many solutions that have already been proposed. <a target="_blank" href="https://css-tricks.com/responsive-data-table-roundup/">“Responsive Table Data Roundup”</a> first published in 2012 by Chris Coyier, has things summarized very neatly (including a 2018 update).</p>
<p><a target="_blank" href="https://hashnode.com/post/really-responsive-tables-using-css3-flexbox-cijzbxd8n00pwvm53sl4l42cx">“Really Responsive Tables using CSS3 Flexbox”</a> by Vasan Subramanian shows an idea of wrapping columns, implemented with Flexbox.</p>
<p>Even though many interesting ideas have been proposed, libraries like <a target="_blank" href="https://getbootstrap.com/docs/4.0/content/tables/#responsive-tables">bootstrap</a> opt for horizontal scrolling for small screens.</p>
<p>As we now have CSS Grid, I think we could have a better common alternative to horizontal scrolling.</p>
<h3 id="heading-html-tables">HTML Tables</h3>
<p>Starting with the basics, a table in HTML is a layout format for displaying collections of items through a matrix of rows and columns. Items are laid out in rows, with the same data attributes in the same columns, with the rows often sorted with one or more sortable attributes. The format gives you a birds-eye view to quickly grasp and examine large quantities of data.</p>
<p>For example, here’s a hypothetical table of purchase order details, that you may see in a purchasing application.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*B78yFFUVc1X8uEp_gVLcNw.png" alt="Image" width="600" height="400" loading="lazy">
<em>Table of purchase order details</em></p>
<p>An item, in this case, is a purchase order detail, that has attributes such as part number, part description, etc.</p>
<p>When using HTML tables, the layout of the data is hardcoded as rows and columns (e.g. <code>&lt;tr&gt;</code> and <code>&lt;td&gt;</code>). This may be sufficient for usage by a screen that fits the whole table width, but in reality, this does not apply for the myriad of devices that exist today. In terms of hacks, you can alter the display property of tables and use any layout you can do with CSS in general, but that doesn’t seem semantically correct.</p>
<h3 id="heading-tables-redefined-collection-of-items">Tables Redefined (= Collection of Items)</h3>
<p>Let’s start by redefining how table data should be expressed in HTML.</p>
<p>As stated earlier, since table data is essentially an ordered collection of items, it seems natural to use ordered lists. Also, since tables are often used to supplement textual descriptions, it seems natural to enclose this in a section, but this would depend on the context of how the table data is being used.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
 <span class="hljs-tag">&lt;<span class="hljs-name">ol</span>&gt;</span>
  <span class="hljs-comment">&lt;!-- The first list item is the header of the table --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>#<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
   <span class="hljs-comment">&lt;!-- Enclose semantically similar attributes as a div hierarchy --&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>Part Number<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>Part Description<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">li</span>&gt;</span>
  <span class="hljs-comment">&lt;!-- The rest of the items in the list are the actual data --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>1<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
   <span class="hljs-comment">&lt;!-- Group part related information--&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>100-10001<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>Description of part<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">li</span>&gt;</span>
 ...
 <span class="hljs-tag">&lt;/<span class="hljs-name">ol</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
</code></pre>
<p>Vanilla <code>&lt;div&gt;</code>'s are used to express item attributes since HTML5 does not define an appropriate tag for this. The key here is to express semantically similar attributes as a hierarchy of <code>&lt;div&gt;</code>'s. This structure will be used when defining how the data should be laid out. I will come back to this in the next section on the topic of styling.</p>
<p>As for the actual data inside the <code>&lt;div&gt;</code> element, the first item in the list is the header, and the rest of the items are the actual data.</p>
<p>Now, it’s time to start talking about styling the items with CSS Grid.</p>
<h3 id="heading-styling-item-collections">Styling Item Collections</h3>
<p>The basic idea here is to display all attributes of the item as a normal table, display width permitting. This layout has the luxury of being able to see as many items (rows) as possible.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*6sZipUcqB3hru4Q5r0kORw.png" alt="Image" width="600" height="400" loading="lazy">
<em>Full Table</em></p>
<p>When the width of the display becomes narrower, some attributes are stacked vertically, in order to save horizontal space. The choice of stacking attributes should be based on:</p>
<ol>
<li>Do the attributes make sense when stacked vertically? and,</li>
<li>When stacked vertically, does it save horizontal space?</li>
</ol>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*llLsnXzdnBBfMRPqoKNBmw.png" alt="Image" width="600" height="400" loading="lazy">
<em>Wrapping Table 1. Start by wrapping columns that need little width, and give the other columns space</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*DdQ-n4VzeGU1EzhRKdHj8w.png" alt="Image" width="600" height="400" loading="lazy">
<em>Wrapping Table 2. Wrap “Part Description”, to be able to see the description</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*ys0ukWXXtbWhVyXTD9E0Zw.png" alt="Image" width="600" height="400" loading="lazy">
<em>Wrapping Table 3. Further wrap “Vendor Name”</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*-ik1zA0LDXzWib7Ux-4EpQ.png" alt="Image" width="600" height="400" loading="lazy">
<em>Wrapping Table 4. Wrap vendor related information under part related information</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*sEvQQjZoux7PEii3JQpCRg.png" alt="Image" width="600" height="400" loading="lazy">
<em>Wrapping Table 5. Fully wrapped</em></p>
<p>When the width further shrinks to the size of a mobile device, each item is displayed as a card. This layout has redundancy because the attribute names are repeatedly displayed on each card, and has the least glanceability, but does not compromise usability (e.g. horizontal scrolling, super small text, etc).</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*jI0hhzrpYpjbO3-fGh8IWA.png" alt="Image" width="600" height="400" loading="lazy">
<em>Two Column Card Layout</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*XCCcicUngRBcBaKyETC4vg.png" alt="Image" width="600" height="400" loading="lazy">
<em>One Column Card Layout</em></p>
<p>Now let’s dive into the details.</p>
<h4 id="heading-styling-step-1-full-table">Styling Step 1: Full Table</h4>
<p>Here’s a visual summary of how things will be implemented with CSS Grid.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*uA9PfcQ9JCzY54mH7p_v-A.png" alt="Image" width="600" height="400" loading="lazy">
<em>Grid containers</em></p>
<p>In order to make columns wrap, multiple grid containers are defined as a hierarchy. The red box is a grid container for each row, and the blue box is a container for each column group that wraps.</p>
<p>Let’ s start by setting the list as a grid container by defining a class called <code>.item-container</code> and applying it to the <code>&lt;li&gt;</code>(the red box).</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.item-container</span> {
    <span class="hljs-attribute">display</span>: grid;
    <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-number">2em</span> <span class="hljs-number">2em</span> <span class="hljs-number">10</span>fr <span class="hljs-number">2</span>fr <span class="hljs-number">2</span>fr <span class="hljs-number">2</span>fr <span class="hljs-number">2</span>fr <span class="hljs-number">5em</span> <span class="hljs-number">5em</span>;
}
</code></pre>
<p>The number of explicit columns specified with <code>grid-template-columns</code> is nine, which is the number of top-level <code>&lt;div&gt;</code>'s, directly  under <code>&lt;li&gt;</code>.</p>
<p>The column’s width is defined in relative length to make the columns wrap. The actual fraction has to be fine-tuned, based on the content.</p>
<p>The columns that don’t wrap are defined in absolute length to maximize width usage for the wrapping columns. In the purchase order details example, the second column is a two-digit Id, so I set the width to double that size of 2 m’s.</p>
<p>Next, we define another grid container called <code>.attribute-container</code> and apply it on all intermediate <code>&lt;div&gt;</code>’s under the list (the blue box).</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.attribute-container</span> {
    <span class="hljs-attribute">display</span>: grid;
    <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(auto-fit, minmax(var(--column-width-min), <span class="hljs-number">1</span>fr));
    }
</code></pre>
<p>The minimum column width for all grid items under <code>.attribute-container</code> is specified with a CSS variable called <code>--column-width-min</code>(more on this later) using the <code>minmax</code> function, with the maximum set to take the rest of the space (e.g. one fraction). Since <code>grid-template-columns</code> are <code>repeat</code>ed, available horizontal space will be split into the maximum number of columns that could take at least <code>--column-width-min</code>, and the rest of the columns would go to the next line. The column’s width will be stretched if there is excess horizontal space because the <code>repeat</code> is <code>auto-fit</code>ed.</p>
<h4 id="heading-styling-step-2-wrapping-table">Styling Step 2: Wrapping Table</h4>
<p>Next, <code>--column-width-min</code> needs to be specified independently for each column in order to wrap. Just to be clear, the variables need to be specified in order for the full table to render properly as well. To do this, a class is set for each <code>.attribute-container</code>, and a different <code>--column-width-min</code> is specified for each class scope.</p>
<p>Let’s take a look at the HTML where <code>.part-id</code> is applied,</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">"attribute-container part-id"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Part Number<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>Part Description<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>and the CSS:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.part-id</span> {
    <span class="hljs-attribute">--column-width-min</span>: <span class="hljs-number">10em</span>;
}
</code></pre>
<p>This specific grid container will have two columns, as long as the available width is wider than 10em for each grid item (e.g. the grid container is wider than 20em). Once the grid container’s width becomes narrower than 20em, the second grid item will go to the next row.</p>
<p>When we combine CSS properties like this, we need only one grid container <code>.attribute-container</code>, with the details changing where the class is applied.</p>
<p>We can further nest <code>.attribute-container</code>s, to have multiple levels of wrapping with different widths, as in the following exert.</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">"attribute-container part-information"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"attribute-container part-id"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"attribute"</span> <span class="hljs-attr">data-name</span>=<span class="hljs-string">"Part Number"</span>&gt;</span>Part Number<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">"attribute"</span> <span class="hljs-attr">data-name</span>=<span class="hljs-string">"Part Description"</span>&gt;</span>Part Description
    <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">"attribute-container vendor-information"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"attribute"</span>&gt;</span>Vendor Number<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">"attribute"</span>&gt;</span>Vendor Name<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>
.part-information {
    --column-width-min: 10em;
}
.part-id {
    --column-width-min: 10em;
}
.vendor-information {
    --column-width-min: 8em;
}
</code></pre>
<p>All of the above is enclosed in the following media query. The actual breakpoint should be selected based on the width necessary when your table is wrapped to the extreme.</p>
<pre><code>@media screen and (min-width: <span class="hljs-number">737</span>px) {
...
}
</code></pre><h4 id="heading-styling-step-three-card-layout">Styling Step Three: Card Layout</h4>
<p>The card layout will look like a typical form with attribute names in the first column and attribute values in the second column.</p>
<p>To do this, a class called <code>.attribute</code> is defined and applied to all leaf <code>&lt;div&gt;</code> tags under the <code>&lt;li&gt;</code>.</p>
<pre><code class="lang-js">.attribute {
    <span class="hljs-attr">display</span>: grid;
    grid-template-columns: minmax(<span class="hljs-number">9</span>em, <span class="hljs-number">30</span>%) <span class="hljs-number">1</span>fr;
}
</code></pre>
<p>The attribute names are taken from a custom attribute of the leaf  <code>&lt;div&gt;</code> called <code>data-name</code>, for example <code>&lt;div class=”attribute” data-name="Part Number"&gt;</code>, and a pseudo-element is created. The pseudo-element will be subject to the grid container’s layout.</p>
<pre><code class="lang-js">.attribute::before {
    <span class="hljs-attr">content</span>: attr(data-name);
}
</code></pre>
<p>The first item in the list is the header and does not need to be displayed.</p>
<pre><code class="lang-js"><span class="hljs-comment">/* Don't display the first item, since it is used to display the header for tabular layouts*/</span>
.collection-container&gt;li:first-child {
    <span class="hljs-attr">display</span>: none;
}
</code></pre>
<p>And finally, the cards are laid out in one column for mobile devices, but two for screens with a little bit more width, but not enough for displaying a table.</p>
<pre><code><span class="hljs-comment">/* 2 Column Card Layout */</span>
@media screen and (max-width: <span class="hljs-number">736</span>px) {
    .collection-container {
        <span class="hljs-attr">display</span>: grid;
        grid-template-columns: <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr;
        grid-gap: <span class="hljs-number">20</span>px;
    }
...
}
<span class="hljs-comment">/* 1 Column Card Layout */</span>
@media screen and (max-width:<span class="hljs-number">580</span>px) {
    .collection-container {
        <span class="hljs-attr">display</span>: grid;
        grid-template-columns: <span class="hljs-number">1</span>fr;
    }
}
</code></pre><h3 id="heading-finishing-notes">Finishing Notes</h3>
<p>Accessibility is an area that wasn’t considered at all and may have some space for improvement.</p>
<p>If you have any ideas or second thoughts, please feel free to comment!</p>
<p>And of course, thanks for reading.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
