<?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[ Ophy Boamah - 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[ Ophy Boamah - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 16:29:45 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/CodeHemaa/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Design Accessible Browser Extensions ]]>
                </title>
                <description>
                    <![CDATA[ Building a browser extension is easy, but ensuring that it’s accessible to everyone takes deliberate care and skill. Your extension might fetch data flawlessly and have a beautiful interface, but if screen reader users or keyboard navigators can’t us... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-design-accessible-browser-extensions/</link>
                <guid isPermaLink="false">68c169e7d950044818727fd6</guid>
                
                    <category>
                        <![CDATA[ browser ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Browser Extension ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Browsers ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Wed, 10 Sep 2025 12:07:03 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757460414092/f3a9f3ec-f520-4627-b839-a28f15574ba6.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Building a browser extension is easy, but ensuring that it’s accessible to everyone takes deliberate care and skill.</p>
<p>Your extension might fetch data flawlessly and have a beautiful interface, but if screen reader users or keyboard navigators can’t use it, you’ve unintentionally excluded many potential users.</p>
<p>In this article, we will audit a Chrome browser extension for accessibility issues and transform it into an inclusive experience that works for everyone.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-why-accessibility-matters-in-browser-extensions">Why Accessibility Matters in Browser Extensions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-perform-manual-browser-extension-accessibility-tests">How to Perform Manual Browser Extension Accessibility Tests</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-implement-browser-extension-accessibility-improvements">How to Implement Browser Extension Accessibility Improvements</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-perform-automated-browser-extension-accessibility-tests">How to Perform Automated Browser Extension Accessibility Tests</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-best-practices-for-accessible-browser-extensions">Best Practices for Accessible Browser Extensions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-why-accessibility-matters-in-browser-extensions">Why Accessibility Matters in Browser Extensions</h2>
<p>Every click in your browser extension is an opportunity to empower users or exclude them if accessibility isn’t part of your design.</p>
<p>Browser extensions face unique accessibility challenges, as they must inject functionality into existing web pages while maintaining their own accessible interfaces - a dual responsibility that can introduce potential barriers. For example, a popup that traps keyboard users or fails to communicate with screen readers can render an extension unusable.</p>
<p>With over one billion people living with disabilities, according to the World Health Organization, accessible design unlocks a vast user base and creates better experiences for everyone.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757242166628/da2f87e2-5903-4bae-a2f4-071b2a339c69.png" alt="An infographic showing browser extension common accessibility barriers" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>For browser extensions, accessibility barriers commonly emerge as:</p>
<ul>
<li><p><strong>Keyboard navigation dead-ends</strong>: Popups and interfaces that trap or exclude keyboard users.</p>
</li>
<li><p><strong>Silent interactions</strong>: Missing labels and descriptions, like a button with only an icon announced as “unlabelled button” by screen readers, leaving users guessing about its purpose.</p>
</li>
<li><p><strong>Unannounced dynamic content updates</strong>: Content changes that occur without assistive technology awareness, such as a quote updating without notifying screen readers of the change, including missing feedback for loading states or errors</p>
</li>
<li><p><strong>Context integration conflicts</strong>: Extensions modifying existing web pages can mistakenly break the page's accessibility features or introduce elements that clash with established navigation patterns</p>
</li>
</ul>
<p>By understanding these barriers, developers can take targeted steps to test and improve their extensions’ accessibility.</p>
<h2 id="heading-how-to-perform-manual-browser-extension-accessibility-tests">How to Perform Manual Browser Extension Accessibility Tests</h2>
<p>While automated tools catch obvious issues, manual testing reveals the real user experience. Here's how to systematically evaluate your extension's accessibility.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">You can use any unpublished browser extension to follow along. For this test, we’ll be using the <a target="_self" href="https://www.freecodecamp.org/news/how-to-build-an-advice-generator-chrome-extension-with-manifest-v3/">browser extension built in this article</a>, which uses <a target="_self" href="https://www.frontendmentor.io/challenges/advice-generator-app-QdUG-13db?via=ophyboamah">this Advice generator app design</a>.</div>
</div>

<h3 id="heading-keyboard-navigation-test">Keyboard Navigation Test</h3>
<p>Disconnect your mouse and try to use your extension completely with the keyboard only. Navigate using <code>Tab</code> to move between elements, <code>Enter</code> or <code>Space</code> to activate buttons, and arrow keys within components. </p>
<ul>
<li><p>Is it always clear which element has focus?</p>
</li>
<li><p>Can you activate buttons with <code>Enter</code> or <code>Space</code> as expected?</p>
</li>
<li><p>Can users exit modal dialogs or dropdown menus?</p>
</li>
</ul>
<p>If you encounter any dead-ends or confusion points, keyboard users will face the same barriers.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757242828152/b1555a79-a810-4d02-a995-6bf101ca2564.png" alt="An screenshot of an advice interface with a focused button " class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-screen-reader-evaluation">Screen Reader Evaluation</h3>
<p>Use your operating system's built-in screen reader to navigate your extension and listen to what is announced. On macOS, enable VoiceOver; on Windows, use Narrator; on Linux, try Orca. </p>
<ul>
<li><p>Does each element’s purpose come through clearly, such as a button announced as “Generate new advice” rather than just “button”?</p>
</li>
<li><p>Are headings, lists, and other structures properly conveyed?</p>
</li>
<li><p>Do users understand when content is loading, selected, or has changed?</p>
</li>
</ul>
<p>This testing phase often reveals the gap between what you intended to communicate and what actually reaches users.</p>
<h3 id="heading-visual-accessibility-review">Visual Accessibility Review</h3>
<p>Examine your extension in different visual contexts. Use developer tools, like WebAIM’s Contrast Checker, to verify that text meets WCAG’s 4.5:1 contrast ratio for readability. Test how your extension appears in system high-contrast settings. Ensure:</p>
<ul>
<li><p>Functionality remains usable at 200% zoom.</p>
</li>
<li><p>Information isn’t conveyed through colour alone, such as using text labels alongside colour-coded indicators.</p>
</li>
</ul>
<p>These manual tests will uncover critical accessibility issues, paving the way for targeted improvements to make your extension inclusive.</p>
<h2 id="heading-how-to-implement-browser-extension-accessibility-improvements">How to Implement Browser Extension Accessibility Improvements</h2>
<p>Imagine refreshing a page without knowing it happened or clicking a button with no clear purpose. The manual tests performed above revealed that's the experience for screen reader users of our extension among these three key accessibility issues:</p>
<ul>
<li><p><strong>Missing button label</strong>: The dice button only has an image with alt text “Dice icon,” which lacks the context screen readers need</p>
</li>
<li><p><strong>Silent dynamic updates</strong>: When new advice loads, screen readers don't know the content has changed</p>
</li>
<li><p><strong>No loading states</strong>: When fetching advice, users receive no feedback that something is happening</p>
</li>
</ul>
<p>Let's address the issues before conducting automated tests.</p>
<h3 id="heading-how-to-address-missing-button-label-and-alt-text">How to Address Missing Button Label and Alt text</h3>
<p>We’ll add <code>aria-label</code> to clearly explain the button's purpose and provide descriptive alt text for the icon. The <code>role="presentation"</code> attribute ensures the image is treated as decorative by screen readers.</p>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!--Before: Unclear Button Purpose and icon alt text--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"dice-button"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"generate-advice-btn"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/icons/icon-dice.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Dice icon"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

<span class="hljs-comment">&lt;!--After: Clear, Accessible Button and icon alt text--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"dice-button"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"generate-advice-btn"</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Generate new advice"</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/icons/icon-dice.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"A dice icon with green background"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"presentation"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<h3 id="heading-how-to-address-silent-dynamic-updates">How to Address Silent Dynamic Updates</h3>
<p>We’ll add <code>aria-live="polite"</code> for screen readers to announce new advice and <code>aria-atomic="true"</code> to ensure that the entire quote is read. That is:</p>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!--Before: Silent Dynamic Updates--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"advice-quote"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"advice-quote"</span>&gt;</span>
    "It is easy to sit up and take notice, what's difficult is getting up and taking action."
<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

<span class="hljs-comment">&lt;!--After: Announced Content Changes--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"advice-quote"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"advice-quote"</span> <span class="hljs-attr">aria-live</span>=<span class="hljs-string">"polite"</span> <span class="hljs-attr">aria-atomic</span>=<span class="hljs-string">"true"</span>&gt;</span>
    "It is easy to sit up and take notice, what's difficult is getting up and taking action."
<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<h3 id="heading-how-to-address-no-loading-states">How to Address No Loading States</h3>
<p>We’ll add a <code>setLoadingState</code> function to provide loading indicators, ensuring screen reader users are notified when content is being fetched:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Before: No Loading Feedback</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">requestNewAdvice</span>(<span class="hljs-params"></span>) </span>{
  chrome.runtime.sendMessage({ <span class="hljs-attr">action</span>: <span class="hljs-string">"fetchAdvice"</span> }, <span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
    <span class="hljs-comment">// No loading indicators...</span>
  });
}

<span class="hljs-comment">// After: Accessible Loading States</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">requestNewAdvice</span>(<span class="hljs-params"></span>) </span>{
  setLoadingState(<span class="hljs-literal">true</span>); 
  chrome.runtime.sendMessage({ <span class="hljs-attr">action</span>: <span class="hljs-string">"fetchAdvice"</span> }, <span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
    setLoadingState(<span class="hljs-literal">false</span>);
    <span class="hljs-comment">// Handle response with proper announcements...</span>
  });
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setLoadingState</span>(<span class="hljs-params">isLoading</span>) </span>{
  <span class="hljs-keyword">if</span> (isLoading) {
    <span class="hljs-comment">// Disable button and show loading text</span>
    generateAdviceBtn.disabled = <span class="hljs-literal">true</span>;
    generateAdviceBtn.setAttribute(<span class="hljs-string">'aria-label'</span>, <span class="hljs-string">'Loading new advice...'</span>);
    <span class="hljs-comment">// Show loading text in the advice quote element</span>
    adviceQuoteElement.textContent = <span class="hljs-string">"Loading new advice..."</span>;
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Re-enable button</span>
    generateAdviceBtn.disabled = <span class="hljs-literal">false</span>;
    generateAdviceBtn.setAttribute(<span class="hljs-string">'aria-label'</span>, <span class="hljs-string">'Generate new advice'</span>);
  }
}
</code></pre>
<p>With the manual testing issues addressed, we can now move on to performing an automated test of the same extension.</p>
<h2 id="heading-how-to-perform-automated-browser-extension-accessibility-tests">How to Perform Automated Browser Extension Accessibility Tests</h2>
<p>Manual testing provides crucial insights, but automated tools can efficiently catch common issues and provide ongoing monitoring. </p>
<p>This <a target="_blank" href="https://extensiona11ychecker.vercel.app/">Extension Accessibility Checker</a> simplifies testing by analyzing browser extension interfaces, such as popups and content scripts, for WCAG compliance, addressing unique challenges like popup constraints and content injection conflicts.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757239257443/42918662-1465-4c01-8f07-ada5d9adb174.gif" alt="A GIF showing how to test an extension zip file with the Extension accessibility checker tool" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>To use the Extension Accessibility Checker:</p>
<ol>
<li><p>Compress your browser extension folder into a .zip file</p>
</li>
<li><p>Upload the .zip file on <a target="_blank" href="https://extensiona11ychecker.vercel.app/">https://extensiona11ychecker.vercel.app/</a></p>
</li>
<li><p>Review the generated report for specific accessibility violations and implement suggested fixes </p>
</li>
</ol>
<p>As shown in the GIF above, this workflow helps establish accessibility as a routine part of your development process rather than an afterthought.</p>
<p>With automated testing in place, let’s explore best practices to ensure that your extension remains accessible throughout development.</p>
<h2 id="heading-best-practices-for-accessible-browser-extensions">Best Practices for Accessible Browser Extensions</h2>
<p>We've transformed our <a target="_blank" href="https://www.frontendmentor.io/challenges/advice-generator-app-QdUG-13db?via=ophyboamah">sample advice-generating browser extension</a> from a functional but inaccessible tool into an inclusive one that works for everyone. </p>
<p>Based on our improvements, here are four key principles for designing accessible browser extensions:</p>
<ol>
<li><h3 id="heading-semantic-html-and-clear-descriptive-labels">Semantic HTML and Clear, Descriptive Labels</h3>
</li>
</ol>
<p>Always start with proper HTML structure, using appropriate elements (for example, for a “Generate Advice” action, proper heading hierarchy) before adding ARIA attributes.</p>
<p>Ensure that every interactive element has a clear purpose via <code>aria-label</code>, <code>aria-labelledby</code>, or visible text that explains its action.</p>
<ol start="2">
<li><h3 id="heading-clear-communication-at-every-step">Clear Communication at Every Step</h3>
</li>
</ol>
<p>Every interactive element must convey its purpose effectively. Users need to understand:</p>
<ul>
<li><ul>
<li><p>What’s happening (for example, “Loading new advice…” for loading states)</p>
<ul>
<li><p>What went wrong (for example, “Failed to load advice” for errors)</p>
</li>
<li><p>What changed (for example, aria-live regions for updated content)</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ol start="3">
<li><h3 id="heading-complete-keyboard-accessibility">Complete Keyboard Accessibility</h3>
</li>
</ol>
<p>All functionality must be available through keyboard navigation. This requires testing with <code>Tab</code>, <code>Enter</code>, <code>Space</code>, and arrow keys as appropriate.</p>
<p>Provide clear and thoughtful focus indicators that move predictably through your interface with obvious ways to exit modals or complex interactions.</p>
<ol start="4">
<li><h3 id="heading-user-preferences-and-content-script-considerations">User Preferences and Content Script Considerations</h3>
</li>
</ol>
<p>Respect user choices by supporting system font size settings and not overriding user-defined colour schemes unnecessarily.</p>
<p>When your extension modifies existing web pages, make sure you don't break the page's established accessibility features, focus management and navigation patterns. Ensure any new elements you inject follow accessibility standards.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>As we’ve seen with our <a target="_blank" href="https://www.frontendmentor.io/challenges/advice-generator-app-QdUG-13db?via=ophyboamah">advice-generating extension</a>, addressing accessibility issues transforms a functional tool into an inclusive one.</p>
<p>However, while fixing issues in existing extensions is helpful, the most effective approach is letting accessibility guide your design and development decisions from the first line of code.</p>
<p>When starting your next browser extension project, ask:</p>
<ul>
<li><p>How would someone navigate this using only a keyboard?</p>
</li>
<li><p>Is the purpose of every interactive element immediately clear to screen readers?</p>
</li>
<li><p>How will users understand what's happening during loading states?</p>
</li>
</ul>
<p>Here are some helpful resources</p>
<ul>
<li><p><a target="_blank" href="https://developer.chrome.com/docs/extensions/mv3/a11y/">Chrome Extension Accessibility Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://extensiona11ychecker.vercel.app/">Extension Accessibility Checker</a></p>
</li>
<li><p><a target="_blank" href="https://www.w3.org/WAI/WCAG21/quickref/">Web Content Accessibility Guidelines (WCAG) 2.1</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build an Advice Generator Chrome Extension with Manifest V3 ]]>
                </title>
                <description>
                    <![CDATA[ In 2025, using Chrome without extensions is like using a smartphone without apps. It’s possible, but you’re missing out on a lot. And despite how essential extensions are, creating one is very simple – it’s just HTML, CSS, and JavaScript with browser... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-an-advice-generator-chrome-extension-with-manifest-v3/</link>
                <guid isPermaLink="false">68acc54701889f3eebbb5f25</guid>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ chrome extension ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Mon, 25 Aug 2025 20:19:19 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1756152220137/8717b809-1186-4a15-92f8-ea926177ef76.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In 2025, using Chrome without extensions is like using a smartphone without apps. It’s possible, but you’re missing out on a lot.</p>
<p>And despite how essential extensions are, creating one is very simple – it’s just HTML, CSS, and JavaScript with browser APIs.</p>
<p>In this tutorial, we are going to learn about Chrome extensions by building an Advice Generator extension with Manifest V3 (MV3), the latest and most secure architecture for Chrome Extensions. You can move along to see what we'll build <a class="post-section-overview" href="#heading-what-were-going-to-build">here</a>.</p>
<h3 id="heading-table-of-contents">Table of Contents</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-are-the-key-components-of-a-chrome-extension">What are the Key Components of a Chrome Extension?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-an-advice-generator-chrome-extension">How to Build an Advice Generator Chrome Extension</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-benefits-of-manifest-v3">The Benefits of Manifest V3</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-debug-your-chrome-extension">How to Debug Your Chrome Extension</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-are-the-key-components-of-a-chrome-extension">What are the Key Components of a Chrome Extension?</h2>
<p>Chrome extensions are incredibly powerful tools that can add custom functionality directly into your Browser experience to transform how you use the web.</p>
<p>Before we write any code, let's understand some key components:</p>
<ul>
<li><p>Every extension starts with a <strong>manifest</strong> file. This JSON file tells Chrome everything it needs to know about an extension: name, version, permissions, and files</p>
</li>
<li><p>The <strong>user interface</strong> is built with HTML, CSS, and JavaScript. It's essentially a mini webpage that lives inside your browser</p>
</li>
<li><p>Finally, there's the <strong>service worker</strong> which runs in the background and fetches data from external APIs. In Manifest V3, service workers have replaced background pages</p>
</li>
</ul>
<h2 id="heading-how-to-build-an-advice-generator-chrome-extension">How to Build an Advice Generator Chrome Extension</h2>
<p>Here’s a look at what we’re going to build:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755718930961/381f422d-f83c-49a9-a007-051ddea6e8da.png" alt="381f422d-f83c-49a9-a007-051ddea6e8da" class="image--center mx-auto" width="1600" height="825" loading="lazy"></p>
<p>This design is by <a target="_blank" href="https://www.frontendmentor.io/?via=ophyboamah">Frontend Mentor</a>.</p>
<p><strong>Prerequisites:</strong></p>
<p>To follow along with this tutorial, you need:</p>
<ul>
<li><p>Basic understanding of HTML, CSS and JavaScript</p>
</li>
<li><p>A Chrome browser</p>
</li>
<li><p>A text editor</p>
</li>
</ul>
<p>When structuring an extension project, the only prerequisite is to place the <code>manifest.json</code> file in the extension's root directory.</p>
<h3 id="heading-testing-your-chrome-extension-load-unpacked"><strong>Testing Your Chrome Extension (Load Unpacked)</strong></h3>
<p>Before we start building, you’ll want to see your progress after each file to catch any issues early. Here’s how to load your extension into Chrome for testing:</p>
<ol>
<li><p>Go to <code>chrome://extensions</code> to open the Chrome Extensions page.</p>
</li>
<li><p>In the top right corner of the Extensions page, toggle the <strong>Developer mode</strong> on.</p>
</li>
<li><p>Click the <strong>Load unpacked</strong> button that appears.</p>
</li>
<li><p>In the file dialog, go to the <strong>root folder of the extension</strong> and click <strong>Select Folder</strong>.</p>
</li>
</ol>
<p>Your extension should appear. If its icon does not appear in your browser's toolbar immediately, click the <strong>puzzle</strong> icon in your toolbar and pin it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755711497449/6c3f056c-322d-45a2-b1b3-15a62b7fad44.png" alt="A screenshot showing how to pin a Chrome extension from a browser's toolbar" class="image--center mx-auto" width="842" height="410" loading="lazy"></p>
<p>Now let's start by defining our extension's identity in the <code>manifest.json</code> file.</p>
<h3 id="heading-the-benefits-of-manifest-v3">The Benefits of Manifest V3</h3>
<p>The <code>manifest.json</code> is the heart of a Chrome Extension. Written in JSON (JavaScript Object Notation), it provides Chrome with everything it needs to know about your extension.</p>
<p>Think of it like a passport with visas and Chrome as the immigration officer verifying identity and access.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755715844005/b1742fbf-fafa-4c36-b08c-1637d00d625d.png" alt="An image depicting the analogy of the Manifest file as a passport and visa and Chrome as the immigration officer that ensures the right permissions." class="image--center mx-auto" width="2617" height="1236" loading="lazy"></p>
<p>Manifest V3 (MV3), brings better performance, security, and reliability to extensions. MV3 uses service workers that activate only when needed, improving battery life and preventing extensions from slowing down your browser.</p>
<p>Let's break down each important field:</p>
<ul>
<li><p><code>manifest_version</code> is the most critical line. Give it a value of 3 to tell Chrome you're using Manifest V3.</p>
</li>
<li><p><code>name</code><strong>,</strong> <code>version</code><strong>,</strong> <code>description</code> define your extension's basic identity.</p>
</li>
<li><p><code>action</code> is a Manifest V3 field that controls what happens when someone clicks your extension's <code>default_icon</code> in the toolbar. The <code>default_popup</code> points to your HTML file, so clicking the icon opens that page in a small popup window.</p>
</li>
<li><p><code>permissions</code> tells Chrome what your extension needs access to. We're using host permission <a target="_blank" href="https://api.adviceslip.com/">https://api.adviceslip.com/*</a> so our extension can fetch advice from that API. Without it, the extension would be blocked from making those requests. This might seem overly cautious, but it's a security measure that protects users.</p>
</li>
<li><p><code>background</code> points to your service worker script. The <code>service_worker</code> field tells Chrome that <code>service-worker.js</code> should run in the background.</p>
</li>
</ul>
<h3 id="heading-step-1-create-a-manifest-3-file">Step 1: Create a Manifest 3 File</h3>
<p>Going by the explanations of the various parts of the file above, here's what our <code>manifest.json</code> file would look like:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Advice Generator"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Get a fresh piece of advice whenever you need it!"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0"</span>,
  <span class="hljs-attr">"manifest_version"</span>: <span class="hljs-number">3</span>,
  <span class="hljs-attr">"action"</span>: {
    <span class="hljs-attr">"default_popup"</span>: <span class="hljs-string">"index.html"</span>,
    <span class="hljs-attr">"default_icon"</span>: <span class="hljs-string">"/icons/icon-dice.png"</span>
  },
  <span class="hljs-attr">"permissions"</span>: [
    <span class="hljs-string">"activeTab"</span>
  ],
  <span class="hljs-attr">"host_permissions"</span>: [
    <span class="hljs-string">"https://api.adviceslip.com/*"</span>
  ],
  <span class="hljs-attr">"background"</span>: {
    <span class="hljs-attr">"service_worker"</span>: <span class="hljs-string">"service-worker.js"</span>
  }
}
</code></pre>
<p>You might see <code>activeTab</code> in other extension examples. While we don't strictly need it for this, it's worth knowing about. It gives temporary access to whatever tab the user is on, but only when they click the extensions icon.</p>
<p>The image below will be the result of running our manifest code above:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755711701772/49fa40e5-1c5b-4cd3-a6f2-a9100db8efcb.png" alt="A screenshot showing the Advice Generator Chrome extension after running the Manifest.json" class="image--center mx-auto" width="917" height="531" loading="lazy"></p>
<h3 id="heading-step-2-create-the-html-and-css-pages">Step 2: Create the HTML and CSS Pages</h3>
<p>Now that our extension has its identity and permissions defined, let's move on to building the user interface starting with an <code>index.html</code> page.</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Advice Generator<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"style.css"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Manrope:wght@400;800&amp;display=swap"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"advice-card"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"advice-id"</span>&gt;</span>ADVICE #<span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"advice-id-number"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"advice-quote"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"advice-quote"</span>&gt;</span>
            “It is easy to sit up and take notice, what's difficult is getting up and taking action.”
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"divider"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"icons/pattern-divider.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Divider pattern"</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">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"dice-button"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"generate-advice-btn"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"icons/icon-dice.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Dice icon"</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">main</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"index.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Now, let's bring the design to life with a <code>style.css</code> file in your root directory. We'll set up the overall body styles, position the card, and style all the elements within it.</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
    <span class="hljs-comment">/* Define colors from the Frontend Mentor style guide */</span>
    <span class="hljs-attribute">--clr-light-cyan</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">193</span>, <span class="hljs-number">38%</span>, <span class="hljs-number">86%</span>);
    <span class="hljs-attribute">--clr-neon-green</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">150</span>, <span class="hljs-number">100%</span>, <span class="hljs-number">66%</span>);
    <span class="hljs-attribute">--clr-grayish-blue</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">217</span>, <span class="hljs-number">19%</span>, <span class="hljs-number">35%</span>);
    <span class="hljs-attribute">--clr-dark-grayish-blue</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">217</span>, <span class="hljs-number">19%</span>, <span class="hljs-number">25%</span>);
    <span class="hljs-attribute">--clr-dark-blue</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">218</span>, <span class="hljs-number">23%</span>, <span class="hljs-number">16%</span>); 
    <span class="hljs-comment">/* Typography */</span>
    <span class="hljs-attribute">--ff-manrope</span>: <span class="hljs-string">'Manrope'</span>, sans-serif;
    <span class="hljs-attribute">--fw-regular</span>: <span class="hljs-number">400</span>;
    <span class="hljs-attribute">--fw-bold</span>: <span class="hljs-number">700</span>;
}
<span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">font-family</span>: <span class="hljs-built_in">var</span>(--ff-manrope);
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--clr-dark-blue);
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">justify-content</span>: center;
    <span class="hljs-attribute">align-items</span>: center;
    <span class="hljs-attribute">min-height</span>: <span class="hljs-number">100vh</span>;
    <span class="hljs-attribute">min-width</span>: <span class="hljs-number">30rem</span>;
    <span class="hljs-attribute">box-sizing</span>: border-box;
}
<span class="hljs-selector-class">.advice-card</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--clr-dark-grayish-blue);
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.5rem</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">1.5rem</span> <span class="hljs-number">1.5rem</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">60%</span>; 
    <span class="hljs-attribute">text-align</span>: center;
    <span class="hljs-attribute">position</span>: relative;
    <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">5px</span> <span class="hljs-number">20px</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.2</span>);
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">70px</span>; 
}
<span class="hljs-selector-class">.advice-id</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--clr-neon-green);
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.8em</span>;
    <span class="hljs-attribute">letter-spacing</span>: <span class="hljs-number">4px</span>;
    <span class="hljs-attribute">text-transform</span>: uppercase;
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">20px</span>;
}
<span class="hljs-selector-class">.advice-quote</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--clr-light-cyan);
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.75em</span>; 
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-built_in">var</span>(--fw-bold);
    <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.4</span>;
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1.2rem</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span> <span class="hljs-number">15px</span>;
}
<span class="hljs-selector-class">.divider</span> {
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">35px</span>;
}
<span class="hljs-selector-class">.divider</span> <span class="hljs-selector-tag">img</span> {
    <span class="hljs-attribute">max-width</span>: <span class="hljs-number">90%</span>;
    <span class="hljs-attribute">height</span>: auto;
}
<span class="hljs-selector-class">.dice-button</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--clr-neon-green);
    <span class="hljs-attribute">border</span>: none;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">2rem</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">2rem</span>;
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">justify-content</span>: center;
    <span class="hljs-attribute">align-items</span>: center;
    <span class="hljs-attribute">cursor</span>: pointer;
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">bottom</span>: -<span class="hljs-number">1rem</span>; 
    <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(-<span class="hljs-number">50%</span>);
    <span class="hljs-attribute">transition</span>: box-shadow <span class="hljs-number">0.3s</span> ease-in-out;
}
<span class="hljs-selector-class">.dice-button</span><span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">40px</span> <span class="hljs-built_in">var</span>(--clr-neon-green);
}
<span class="hljs-selector-class">.dice-button</span> <span class="hljs-selector-tag">img</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">2rem</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">2rem</span>;
}
</code></pre>
<p>The image below will be the result of running our HTML and CSS code above plus the initial manifest:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755711748813/c641535b-5bdf-4adc-a11c-6115b1f1a284.png" alt="An image of the Advice Generator Chrome extension design" class="image--center mx-auto" width="944" height="560" loading="lazy"></p>
<p>With the HTML and CSS done, our extension's visual aspect is complete. Next, let’s give it life by writing the JavaScript that handles fetching new advice and updating the display.</p>
<h3 id="heading-step-3-add-a-service-worker">Step 3: Add a Service Worker</h3>
<p>In Manifest V3, the core background logic for an extension lives in its Service Worker. Unlike the persistent background pages of Manifest V2, in V3 Service Workers run only when needed, such as in response to a message from <code>index.js</code> or a browser event.</p>
<p>Our <code>service-worker.js</code> will have these roles:</p>
<ul>
<li><p>Listen for a request from <code>index.js</code> (when the user clicks the dice).</p>
</li>
<li><p>Fetch a new piece of advice from the Advice Slip API.</p>
</li>
<li><p>Send that advice back to <code>index.js</code> to be displayed.</p>
</li>
</ul>
<p>Create a file named <code>service-worker.js</code> in your extension's root directory.</p>
<pre><code class="lang-javascript">chrome.runtime.onMessage.addListener(<span class="hljs-function">(<span class="hljs-params">request, sender, sendResponse</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (request.action === <span class="hljs-string">"fetchAdvice"</span>) {
    fetchAdvice().then(<span class="hljs-function"><span class="hljs-params">adviceData</span> =&gt;</span> {
      sendResponse({ <span class="hljs-attr">advice</span>: adviceData });
    }).catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error fetching advice:"</span>, error);
      sendResponse({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Failed to fetch advice"</span> });
    });
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  }
});
<span class="hljs-comment">// Function to fetch advice from the Advice Slip API</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchAdvice</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://api.adviceslip.com/advice"</span>);
    <span class="hljs-keyword">if</span> (!response.ok) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`HTTP error! status: <span class="hljs-subst">${response.status}</span>`</span>);
    }
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
    <span class="hljs-keyword">return</span> data.slip; 
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Could not fetch advice:"</span>, error);
    <span class="hljs-keyword">throw</span> error; 
  }
}
</code></pre>
<h4 id="heading-message-handling-in-service-workers">Message Handling in Service Workers</h4>
<p>Since Service Workers don't have direct access to the DOM of your <code>index.html</code> page (and vice versa), they communicate using message passing. As you can see in the code above, the user clicks the dice in <code>index.html</code>, and <code>index.js</code> will send a message to <code>service-worker.js</code> asking for new advice. The Service Worker will then fetch the advice and send it back in another message.</p>
<p><code>chrome.runtime.onMessage.addListener</code> listens for incoming messages and <code>sendResponse</code> replies.</p>
<p>Our Service Worker is now ready to fetch advice. The next step is to make our <code>index.js</code> interact with it.</p>
<h3 id="heading-step-4-add-app-functionality">Step 4: Add App Functionality</h3>
<p>First, we'll create our <code>index.js</code> file. This script is responsible for all the user-facing logic. It will handle the user's interaction (clicking the dice), send a message to our <code>service-worker.js</code> to get new advice, and then update the <code>index.html</code> with the fetched advice.</p>
<p>Our <code>index.js</code> will perform the following steps:</p>
<ol>
<li><p>Reference the HTML elements where we'll display the advice ID, quote, and dice.</p>
</li>
<li><p>Set up an event listener for when the dice is clicked.</p>
</li>
<li><p>Send a message to the <code>service-worker.js</code> to request new advice.</p>
</li>
<li><p>Receive the advice back from <code>service-worker.js</code> and update the content on the <code>index.html</code> page.</p>
</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-comment">// Get references to our HTML elements</span>
<span class="hljs-keyword">const</span> adviceIdElement = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'advice-id-number'</span>);
<span class="hljs-keyword">const</span> adviceQuoteElement = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'advice-quote'</span>);
<span class="hljs-keyword">const</span> generateAdviceBtn = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'generate-advice-btn'</span>);
<span class="hljs-comment">// Function to request advice from the Service Worker</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">requestNewAdvice</span>(<span class="hljs-params"></span>) </span>{
  chrome.runtime.sendMessage({ <span class="hljs-attr">action</span>: <span class="hljs-string">"fetchAdvice"</span> }, <span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (chrome.runtime.lastError) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error sending message:"</span>, chrome.runtime.lastError);
      adviceQuoteElement.textContent = <span class="hljs-string">"Error: Could not get advice."</span>;
      adviceIdElement.textContent = <span class="hljs-string">"---"</span>;
      <span class="hljs-keyword">return</span>;
    }
    <span class="hljs-keyword">if</span> (response &amp;&amp; response.advice) {
      adviceIdElement.textContent = response.advice.id;
      adviceQuoteElement.textContent = <span class="hljs-string">`“<span class="hljs-subst">${response.advice.advice}</span>”`</span>;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (response &amp;&amp; response.error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Service Worker error:"</span>, response.error);
      adviceQuoteElement.textContent = <span class="hljs-string">`Error: <span class="hljs-subst">${response.error}</span>`</span>;
      adviceIdElement.textContent = <span class="hljs-string">"---"</span>;
    }
  });
}
<span class="hljs-keyword">if</span> (generateAdviceBtn) {
  generateAdviceBtn.addEventListener(<span class="hljs-string">'click'</span>, requestNewAdvice);
} <span class="hljs-keyword">else</span> {
  <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Generate advice button not found!"</span>);
}
<span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">'DOMContentLoaded'</span>, requestNewAdvice);
</code></pre>
<p>With <code>index.js</code> in place, our Advice Generator is now ready as you can see in the GIF below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755717163786/326dc332-bf3b-4a8a-ba3a-25bdc829cf68.gif" alt="A GIF showing the finished Advice Generator Chrome extension" class="image--center mx-auto" width="1124" height="720" loading="lazy"></p>
<p>The next crucial step is to know how to debug your extension, should anything go wrong.</p>
<h2 id="heading-how-to-debug-your-chrome-extension">How to Debug Your Chrome Extension</h2>
<p>Chrome provides excellent debugging tools to help troubleshoot extensions. Always follow these essential steps:</p>
<ul>
<li><p>Reload your extension after making changes (especially to <code>manifest.json</code> or <code>service-worker.js</code>) by clicking the refresh icon on <code>chrome://extensions</code>.</p>
</li>
<li><p>Check your <code>manifest.json</code> for typos – missing commas or brackets will break everything.</p>
</li>
<li><p>Verify your API URL and make sure you have the right permissions listed in <code>manifest.json</code>.</p>
</li>
</ul>
<h3 id="heading-debugging-the-main-html-and-js-pages">Debugging the Main HTML and JS Pages</h3>
<p>This is likely where you'll encounter most of your initial JavaScript or HTML/CSS issues.</p>
<ol>
<li><p>Open the extension and right-click anywhere in the popup to Inspect.</p>
</li>
<li><p>Check the Console tab for JavaScript errors from your <code>index.js</code> file.</p>
</li>
<li><p>Use the Elements tab to inspect your HTML and tweak CSS styles in real-time.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755714931805/f03dc46c-b78b-44b6-bc67-bb7fe02499a9.gif" alt="A GIF showing how to inspect the Elements and Console tabs of a Chrome extension" class="image--center mx-auto" width="1292" height="720" loading="lazy"></p>
<h3 id="heading-debugging-the-service-worker-crucial-for-mv3"><strong>Debugging the Service Worker – Crucial for MV3</strong></h3>
<p>The Service Worker runs in the background and has its own separate DevTools.</p>
<ol>
<li><p>Go to <code>chrome://extensions</code>.</p>
</li>
<li><p>Click the <strong>Service worker</strong> link underneath your extension or the Errors button.</p>
</li>
<li><p>Check the Console and Network tabs for service worker and API errors respectively.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755715410580/2c03c56c-affe-4a0a-939f-72ca866eecd3.png" alt="A screenshot showing a Chrome extension with the service worker link and errors button" class="image--center mx-auto" width="802" height="422" loading="lazy"></p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Congratulations, you've just built a Chrome extension using Manifest V3. You've created a user interface, implemented background processing with a service worker, and established communication between different parts of your extension. These skills are the building blocks for any Chrome extension, no matter how simple or complex.</p>
<p>Here are some helpful resources:</p>
<ul>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/What_are_WebExtensions">MDN on Browser Extensions</a></p>
</li>
<li><p><a target="_blank" href="https://developer.chrome.com/docs/extensions/get-started?hl=en">Chrome Devs on Chrome Extensions</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Simpler Accordion Menus with HTML <details> ]]>
                </title>
                <description>
                    <![CDATA[ Accordion menus are everywhere on the web because users want fast answers and smooth navigation. They help create clean, organized, and user-friendly interfaces. Many developers still reach for JavaScript to build accordions, which adds avoidable com... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-simpler-accordion-menus-with-html-details/</link>
                <guid isPermaLink="false">687e45310fc9d9c1bc2da5f7</guid>
                
                    <category>
                        <![CDATA[ HTML5 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS3 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Mon, 21 Jul 2025 13:48:33 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753119637759/0fb5302d-c21c-4c0d-affb-3f891261aabf.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Accordion menus are everywhere on the web because users want fast answers and smooth navigation.</p>
<p>They help create clean, organized, and user-friendly interfaces. Many developers still reach for JavaScript to build accordions, which adds avoidable complexities to their projects.</p>
<p>The HTML <code>&lt;details&gt;</code> element solves this problem with its built-in disclosure widget that toggles content visibility using just a few lines of HTML and optional CSS.</p>
<p>In this article, we’ll look at an FAQ accordion built using <code>&lt;details&gt;</code>. You can see the final project <a class="post-section-overview" href="#heading-our-example-project">here</a>.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-the-html-element">What is the HTML <code>&lt;details&gt;</code> Element?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-an-faq-accordion-built-with-the-element">An FAQ Accordion Built with the <code>&lt;details&gt;</code> Element</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-browser-support-and-accessibility-considerations">Browser Support and Accessibility Considerations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-the-html-element">What is the HTML <code>&lt;details&gt;</code> Element?</h2>
<p>The HTML <code>&lt;details&gt;</code> element is a disclosure widget that allows you to hide and show content with a single click. Think of it as a native accordion that comes built into HTML.</p>
<p>The most common use case for accordions is the Frequently Asked Questions (FAQ) section on many sites. If you’ve seen or interacted with an FAQ, that’s an opportunity to use <code>&lt;details&gt;</code>.</p>
<p>It has two main components:</p>
<ul>
<li><p><code>&lt;details&gt;</code> is the main container tag that opens and closes to display what’s in <code>&lt;summary&gt;</code>.</p>
</li>
<li><p><code>&lt;summary&gt;</code> is a container for the content that is displayed when <code>&lt;details&gt;</code> is clicked.</p>
</li>
</ul>
<p>💡 In addition to the <code>summary</code>, you can include any HTML text element within the <code>&lt;details&gt;</code> container.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752662432707/0d6ebbae-d68d-400f-9209-a83feec273b7.png" alt="0d6ebbae-d68d-400f-9209-a83feec273b7" class="image--center mx-auto" width="2714" height="1612" loading="lazy"></p>
<p>The image above shows a real-life use case of <code>&lt;details&gt;</code> on the Apple website. In a later section, we’ll learn about the browsers that support it.</p>
<h3 id="heading-when-to-use-over-javascript-alternatives">When to Use <code>&lt;details&gt;</code> over JavaScript alternatives</h3>
<p>Unlike JavaScript-based accordions that add weight to your project, <code>&lt;details&gt;</code> offers the same functionality with minimal load and better performance. It also offers built-in keyboard navigation and screen reader support.</p>
<p>Choose <code>&lt;details&gt;</code> over JavaScript-created accordions when:</p>
<ul>
<li><p>Building simple accordions or FAQ sections</p>
</li>
<li><p>Accessibility, performance, and SEO are a priority</p>
</li>
<li><p>You want to avoid JavaScript dependencies</p>
</li>
</ul>
<h2 id="heading-an-faq-accordion-built-with-the-element">An FAQ Accordion Built with the <code>&lt;details&gt;</code> Element</h2>
<p>Here’s what our example project looks like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752662715342/74db7ba5-f7a6-44be-974c-36c0418c4a81.png" alt="Example project using the  element" class="image--center mx-auto" width="2432" height="1894" loading="lazy"></p>
<p>This design is by <a target="_blank" href="https://www.frontendmentor.io/?via=ophyboamah">Frontend Mentor</a> (and you can check out the project on <a target="_blank" href="https://codepen.io/ophyboamah/full/ByaRqaN">Codepen</a>).</p>
<p>To follow along, you need basic knowledge of HTML and CSS. Since the focus of this article is &lt;details&gt;, we won't place a lot of emphasis on the starting HTML and CSS code (available on the Codepen above). Instead, we'll look at one FAQ question with its answer to learn how &lt;details&gt; works.</p>
<h3 id="heading-how-to-use">How to Use <code>&lt;details&gt;</code></h3>
<p>To create an accordion with the <code>&lt;details&gt;</code> element, you need both the <code>&lt;details&gt;</code> and <code>&lt;summary&gt;</code> elements, as shown in the starter code below.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">details</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">summary</span>&gt;</span>What is Frontend Mentor, and how will it help me?<span class="hljs-tag">&lt;/<span class="hljs-name">summary</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Frontend Mentor offers realistic coding challenges to help developers improve their frontend coding skills with projects in HTML, CSS, and JavaScript. It’s suitable for all levels and ideal for portfolio building.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">details</span>&gt;</span>
</code></pre>
<p>The GIF below will be the result after running the above code. With less than five lines of HTML code, we already have an accordion.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752662956079/25c66453-71ba-469c-8dd2-0f1b8e3b9d7f.gif" alt="25c66453-71ba-469c-8dd2-0f1b8e3b9d7f" class="image--center mx-auto" width="1384" height="480" loading="lazy"></p>
<h3 id="heading-styling">Styling <code>&lt;details&gt;</code></h3>
<p>Now, let's focus on transforming our basic accordion into something visually appealing (foundational styles can be found on the <a target="_blank" href="https://codepen.io/ophyboamah/full/ByaRqaN">Codepen</a>). First, we’ll add the icons as SVGs within <code>&lt;summary&gt;</code> with classes (closed-icon and open-icon) to make them easy to style.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">details</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">summary</span>&gt;</span>What is Frontend Mentor, and how will it help me?
  <span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"closed-icon"</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"&lt;http://www.w3.org/2000/svg&gt;"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"closed-icon"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"30"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"31"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 30 31"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M15 3.3125C12.5895 3.3125 10.2332 4.02728 8.22899 5.36646C6.22477 6.70564 4.66267 8.60907 3.74022 10.836C2.81778 13.063 2.57643 15.5135 3.04668 17.8777C3.51694 20.2418 4.67769 22.4134 6.38214 24.1179C8.08659 25.8223 10.2582 26.9831 12.6223 27.4533C14.9865 27.9236 17.437 27.6822 19.664 26.7598C21.8909 25.8373 23.7944 24.2752 25.1335 22.271C26.4727 20.2668 27.1875 17.9105 27.1875 15.5C27.1835 12.2689 25.8981 9.17131 23.6134 6.88659C21.3287 4.60186 18.2311 3.31653 15 3.3125ZM19.6875 16.4375H15.9375V20.1875C15.9375 20.4361 15.8387 20.6746 15.6629 20.8504C15.4871 21.0262 15.2486 21.125 15 21.125C14.7514 21.125 14.5129 21.0262 14.3371 20.8504C14.1613 20.6746 14.0625 20.4361 14.0625 20.1875V16.4375H10.3125C10.0639 16.4375 9.82541 16.3387 9.64959 16.1629C9.47378 15.9871 9.375 15.7486 9.375 15.5C9.375 15.2514 9.47378 15.0129 9.64959 14.8371C9.82541 14.6613 10.0639 14.5625 10.3125 14.5625H14.0625V10.8125C14.0625 10.5639 14.1613 10.3254 14.3371 10.1496C14.5129 9.97377 14.7514 9.875 15 9.875C15.2486 9.875 15.4871 9.97377 15.6629 10.1496C15.8387 10.3254 15.9375 10.5639 15.9375 10.8125V14.5625H19.6875C19.9361 14.5625 20.1746 14.6613 20.3504 14.8371C20.5262 15.0129 20.625 15.2514 20.625 15.5C20.625 15.7486 20.5262 15.9871 20.3504 16.1629C20.1746 16.3387 19.9361 16.4375 19.6875 16.4375Z"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#AD28EB"</span>/&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span> 
  <span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"open-icon"</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"&lt;http://www.w3.org/2000/svg&gt;"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"open-icon"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"30"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"31"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 30 31"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M15 3.3125C12.5895 3.3125 10.2332 4.02728 8.22899 5.36646C6.22477 6.70564 4.66267 8.60907 3.74022 10.836C2.81778 13.063 2.57643 15.5135 3.04668 17.8777C3.51694 20.2418 4.67769 22.4134 6.38214 24.1179C8.08659 25.8223 10.2582 26.9831 12.6223 27.4533C14.9865 27.9236 17.437 27.6822 19.664 26.7598C21.8909 25.8373 23.7944 24.2752 25.1335 22.271C26.4727 20.2668 27.1875 17.9105 27.1875 15.5C27.1841 12.2687 25.899 9.17076 23.6141 6.8859C21.3292 4.60104 18.2313 3.31591 15 3.3125ZM19.6875 16.4375H10.3125C10.0639 16.4375 9.82541 16.3387 9.64959 16.1629C9.47378 15.9871 9.37501 15.7486 9.37501 15.5C9.37501 15.2514 9.47378 15.0129 9.64959 14.8371C9.82541 14.6613 10.0639 14.5625 10.3125 14.5625H19.6875C19.9361 14.5625 20.1746 14.6613 20.3504 14.8371C20.5262 15.0129 20.625 15.2514 20.625 15.5C20.625 15.7486 20.5262 15.9871 20.3504 16.1629C20.1746 16.3387 19.9361 16.4375 19.6875 16.4375Z"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#301534"</span>/&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">summary</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Frontend Mentor offers realistic coding challenges to help developers improve their frontend coding skills with projects in HTML, CSS, and JavaScript. It’s suitable for all levels and ideal for portfolio building.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">details</span>&gt;</span>
</code></pre>
<p>In the code below, we customize the disclosure marker by hiding the default arrow and adding a custom icon to the right using the <code>::marker</code> pseudo-element on <code>&lt;summary&gt;</code>. We also set its content as empty, which removes the marker altogether.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Styles for the clickable summary element*/</span>
<span class="hljs-selector-tag">summary</span> {
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">700</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">transition</span>: color <span class="hljs-number">0.2s</span> ease;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1em</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1.5em</span>;
<span class="hljs-comment">/* Remove the default marker */</span>
  &amp;::marker {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">''</span>;
  }

  &amp;<span class="hljs-selector-pseudo">:last-child</span> { 
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">0</span>; 
  } 

  &amp;<span class="hljs-selector-pseudo">:hover</span> { 
    <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--text-accent);
    <span class="hljs-attribute">outline</span>: none;
  }
}

<span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">1em</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--text-light);
}
<span class="hljs-comment">/* Styles for the collapsible &lt;details&gt; container */</span>
<span class="hljs-selector-tag">details</span> {
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1em</span>;

  &amp;:last-child { 
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">0</span>; 
  }

  <span class="hljs-selector-class">.open-icon</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  &amp;<span class="hljs-selector-attr">[open]</span> {
    .open-icon {
      <span class="hljs-attribute">display</span>: inline;
    }

    <span class="hljs-selector-class">.closed-icon</span> {
      <span class="hljs-attribute">display</span>: none;
    }
  }

  <span class="hljs-selector-class">.open-icon</span>,
  <span class="hljs-selector-class">.closed-icon</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">1.8em</span>; 
    <span class="hljs-attribute">height</span>: <span class="hljs-number">1.8em</span>;
    <span class="hljs-attribute">flex-shrink</span>: <span class="hljs-number">0</span>;
  }
}
</code></pre>
<p>The GIF below shows the output of styling our accordion with the CSS code above.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752663406898/3d033ac2-e9d4-4836-8f3b-816513802353.gif" alt="3d033ac2-e9d4-4836-8f3b-816513802353" class="image--center mx-auto" width="1404" height="480" loading="lazy"></p>
<p>To have an FAQ question expanded when the page loads, add the <code>open</code> attribute to <code>&lt;details&gt;</code>. This is particularly useful for highlighting important information where the most crucial FAQ starts expanded.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">details</span> <span class="hljs-attr">open</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">summary</span>&gt;</span>What is Frontend Mentor, and how will it help me?<span class="hljs-tag">&lt;/<span class="hljs-name">summary</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">details</span>&gt;</span>
</code></pre>
<h2 id="heading-browser-support-and-accessibility-considerations">Browser Support and Accessibility Considerations</h2>
<p>According to <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/details">MDN</a>, <code>&lt;details&gt;</code> is a well established feature that works across many devices and the popular browsers (Chrome, Edge, Firefox, and Safari) since January 2020.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752663542331/33407311-a4db-47ab-bc9f-16baaed5d060.png" alt="33407311-a4db-47ab-bc9f-16baaed5d060" class="image--center mx-auto" width="1548" height="148" loading="lazy"></p>
<p><code>&lt;details&gt;</code> includes built-in accessibility features that requires additional JavaScript in custom solutions such as keyboard navigation, screen reader support, and semantic structure. You can also add attributes like role, aria-expanded, and aria-labelledby to ensure even more accessibility.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p><code>&lt;details&gt;</code> is a powerful yet under-utilized element for creating UI elements like accordions, FAQs, or navigation menus without JavaScript. It is easy to implement and lightweight, and yet improves user experience with interactive content.</p>
<p>So, the next time you need to create any collapsible content, with accessibility and performance in mind, consider reaching for <code>&lt;details&gt;</code> and it will surely make your development life easier.</p>
<p>Here are some helpful resources:</p>
<ul>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details">MDN Documentation for <code>&lt;details&gt;</code></a></p>
</li>
<li><p><a target="_blank" href="https://css-tricks.com/quick-reminder-that-details-summary-is-the-easiest-way-ever-to-make-an-accordion/">CSS-Tricks Guide to Styling Details</a></p>
</li>
<li><p><a target="_blank" href="https://web.dev/learn/html/details/">Web.dev Learn HTML: Details</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is CSS Subgrid? A Practical Tutorial ]]>
                </title>
                <description>
                    <![CDATA[ When designers create layouts in their mockups, everything including the content typically looks perfectly aligned and consistent. But in the real world, user-generated content varies wildly. For example, one testimonial card might have a brief sente... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-css-subgrid/</link>
                <guid isPermaLink="false">66c62f1ff3f170bad73e8630</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ webdev ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web layout ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Wed, 21 Aug 2024 18:17:03 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724227015705/f55ae862-c81f-4453-af92-cb96acf0d13d.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When designers create layouts in their mockups, everything including the content typically looks perfectly aligned and consistent.</p>
<p>But in the real world, user-generated content varies wildly. For example, one testimonial card might have a brief sentence, while another has an entire paragraph. This makes it challenging to maintain a perfect alignment.</p>
<p>CSS Subgrid can easily handle these web layout inconsistencies. It allows nested elements to align with their parent grid, ensuring a consistent look regardless of the content.</p>
<p>In this tutorial, we’ll explore how to use CSS Subgrid to create a products section that stays flexible and looks great. You can move along to see what we'll build <a class="post-section-overview" href="#heading-building-a-products-section-with-subgrid">here</a>.</p>
<h3 id="heading-table-of-contents">Table of Contents</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-limitations-of-css-grid">Limitations of CSS Grid</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-a-products-section-with-subgrid">How to Build a Products Section with Subgrid</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-does-subgrid-work">How Does Subgrid Work?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-subgrid">How to Use Subgrid</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-subgrid-in-browser-devtools">Subgrid in Browser DevTools</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-limitations-of-css-grid">Limitations of CSS Grid</h2>
<p>Adding a display of Grid to a container means that only the direct children become grids. If these direct children also have children, they are not a part of the main grid – so they display in their normal flow.</p>
<p>This is problematic because without a direct link to one another, each will take up the space it needs and not care about its siblings. This leads to misaligned content you can see on the left of the image below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724192748056/e6d99008-5a04-4a83-927d-0d46be2e17a5.png" alt="An image showing an example grid with and without subgrid" class="image--center mx-auto" width="1875" height="684" loading="lazy"></p>
<p>The project we'll build explores a Subgrid solution in a few lines of CSS code that will help us achieve the desired alignment seen on the right of the image above.</p>
<h2 id="heading-how-to-build-a-products-section-with-subgrid">How to Build a Products Section with Subgrid</h2>
<h3 id="heading-what-were-going-to-build">What We’re Going to Build</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724225971840/767e1b9e-bd54-4505-b3ad-2c39901b28c3.png" alt="An image of the final project to be built in this tutorial" class="image--center mx-auto" width="2074" height="1275" loading="lazy"></p>
<p>Check it out on <a target="_blank" href="https://codepen.io/ophyboamah/pen/OJevpQP">Codepen</a>.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li><p>Basic knowledge of HTML and CSS (For a refresher on how CSS Grid works, check out <a target="_blank" href="https://www.freecodecamp.org/news/web-layouts-use-css-grid-and-flex-to-create-responsive-webpages/">my previous article on Web Layouts</a>)</p>
</li>
<li><p>An IDE (text editor)</p>
</li>
<li><p>A web browser</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Since the focus of this article is Subgrid, we won't place a lot of emphasis on the starting HTML and CSS code. We'll just go through quickly first so you can set up. Then we'll dive into learning how to add Subgrid.</div>
</div>

<h3 id="heading-html-code">HTML Code:</h3>
<p>In our <code>index.html</code> file, we'll create the basic structure of the project which includes linking our CSS file and Google Fonts – all within the <code>&lt;head&gt;</code> tag. Within the <code>&lt;body&gt;</code> tag, we'll create a main container to house all the cards. Next, we'll create three individual cards as articles – each with an icon, title, text and button.</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"image/png"</span> <span class="hljs-attr">sizes</span>=<span class="hljs-string">"32x32"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./images/favicon-32x32.png"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"preconnect"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"preconnect"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.gstatic.com"</span> <span class="hljs-attr">crossorigin</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
    <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Inter:wght@100..900&amp;family=Lexend+Deca:wght@100..900&amp;display=swap"</span>
    <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
    <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Big+Shoulders+Display:wght@100..900&amp;family=Inter:wght@100..900&amp;family=Lexend+Deca:wght@100..900&amp;display=swap"</span>
    <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"style.css"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Ophy's Subgrid Products Cards<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"cards-container"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"sedans"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./assets/icon-sedans.svg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"an icon showing a sedan vehicle"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Sedans<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        Choose a sedan for its affordability and excellent fuel economy. Ideal for cruising in the city
        or on your next road trip in and out of town - let your imaginations run.
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>
        Learn more
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"suvs"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./assets/icon-suvs.svg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"an icon showing an suv vehicle"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>SUVs<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        Take an SUV for its spacious interior, power, and versatility.
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>
        Learn more
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"luxury"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./assets/icon-luxury.svg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"an icon showing a luxury vehicle"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>
        Extremely Luxurious
      <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        Cruise in the best car brands without the bloated prices. Enjoy the enhanced comfort of a luxury
        rental and arrive in style.
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>
        Learn more
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">article</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">footer</span>&gt;</span>
      Ophy's Subgrid Products Cards | <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://www.frontendmentor.io/"</span>&gt;</span>Design from Frontend Mentor <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h3 id="heading-css-code">CSS Code:</h3>
<p>In our <code>style.css</code> file, we'll first set our global and base styles:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Global Resets */</span>
* {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">box-sizing</span>: border-box;
}

<span class="hljs-comment">/* Root Variables */</span>
<span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">--primary-font</span>: <span class="hljs-string">"Lexend Deca"</span>, sans-serif;
  <span class="hljs-attribute">--secondary-font</span>: <span class="hljs-string">"Big Shoulders Display"</span>, sans-serif;
  <span class="hljs-attribute">--heading-color</span>: <span class="hljs-number">#F2F2F2</span>;
  <span class="hljs-attribute">--font-color</span>: <span class="hljs-number">#FFF</span>;
  <span class="hljs-attribute">--sedans-background</span>: <span class="hljs-number">#E28625</span>;
  <span class="hljs-attribute">--suv-background</span>: <span class="hljs-number">#006971</span>;
  <span class="hljs-attribute">--luxury-background</span>: <span class="hljs-number">#004140</span>;
  <span class="hljs-attribute">--heading-font-size</span>: <span class="hljs-number">2.5rem</span>;
  <span class="hljs-attribute">--button-font-size</span>: <span class="hljs-number">0.9rem</span>;
  <span class="hljs-attribute">--default-padding</span>: <span class="hljs-number">1rem</span> <span class="hljs-number">0</span>;
}

<span class="hljs-comment">/* Base Styles */</span>
<span class="hljs-selector-tag">html</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
}

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-built_in">var</span>(--primary-font);
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">920px</span>;
}

<span class="hljs-comment">/* Heading Styles */</span>
<span class="hljs-selector-tag">h3</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-built_in">var</span>(--secondary-font);
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--heading-color);
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">var</span>(--heading-font-size);
}
<span class="hljs-comment">/* Paragraph Styles */</span>
<span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-built_in">var</span>(--primary-font);
  <span class="hljs-attribute">font-optical-sizing</span>: auto;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">200</span>; 
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--font-color);
  <span class="hljs-attribute">padding</span>: <span class="hljs-built_in">var</span>(--default-padding);
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.5</span>;
}
<span class="hljs-comment">/*  Footer  */</span>
  <span class="hljs-selector-tag">footer</span> {
    <span class="hljs-attribute">text-align</span>: center;
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">1.5rem</span>;
    a {
      <span class="hljs-attribute">text-decoration</span>: none;
    }
  }
</code></pre>
<p>Next, we'll style the main cards container and button. Note that we've specified columns and rows for the cards container using <code>grid-template-columns</code> and <code>grid-template-rows</code>, respectively.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Container */</span>
<span class="hljs-selector-class">.cards-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(<span class="hljs-number">300px</span>, <span class="hljs-number">1</span>fr));
  <span class="hljs-attribute">grid-template-rows</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">4</span>, auto);
  <span class="hljs-attribute">min-height</span>: <span class="hljs-number">31.25rem</span>;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">10.688rem</span>;
  button {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">var</span>(--button-font-size);
    <span class="hljs-attribute">background</span>: <span class="hljs-built_in">var</span>(--font-color);
    <span class="hljs-attribute">border</span>: none;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span> <span class="hljs-number">1.5rem</span>;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">25px</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">70%</span>;
    &amp;:hover {
      <span class="hljs-attribute">cursor</span>: pointer;
      <span class="hljs-attribute">background</span>: none;
      <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--font-color);
      <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-built_in">var</span>(--font-color);
    }
}
</code></pre>
<p>Then we'll create general card styles as well as individual card styles.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* All */</span>
<span class="hljs-selector-class">.suvs</span>,
<span class="hljs-selector-class">.sedans</span>,
<span class="hljs-selector-class">.luxury</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">3rem</span>;
  h3 {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">var</span>(--heading-font-size);
    <span class="hljs-attribute">text-transform</span>: uppercase;
  }
}
<span class="hljs-comment">/* Sedans */</span>
<span class="hljs-selector-class">.sedans</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--sedans-background);
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">10px</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">10px</span>;
  button {
    <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--sedans-background);
  }
}
<span class="hljs-comment">/* SUV */</span>
<span class="hljs-selector-class">.suvs</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--suv-background);
  button {
    <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--suv-background);
  }
}
<span class="hljs-comment">/* Luxury */</span>
<span class="hljs-selector-class">.luxury</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--luxury-background);
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0</span> <span class="hljs-number">10px</span> <span class="hljs-number">10px</span> <span class="hljs-number">0</span>;
  button {
    <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--luxury-background);
  }
}
</code></pre>
<p>The image below will be the result after running the above starter code. The cards have been created as grid columns but the rows within the individual cards are not aligning properly due to the difference in content length.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724176252090/b3540574-6779-4486-8622-fbf8fe8e9a09.png" alt="An image of the products cards without Subgrid" class="image--center mx-auto" width="2136" height="1340" loading="lazy"></p>
<h2 id="heading-how-does-subgrid-work">How Does Subgrid Work?</h2>
<p>The display above will be a nightmare for designers and stakeholders until it's fixed. In the past, to fix this, developers needed to make these cards into nested grids. But that code will eventually become messy and difficult to maintain.</p>
<p>CSS Subgrid allows a grid item to inherit the grid tracks (rows or columns) of its parent grid, rather than defining its own. This is particularly useful for maintaining consistent alignment between nested grids and their parent grids.</p>
<p>In our project, instead of defining a row for the icons, titles, text and buttons, we can make them inherit the same from their parent grid (the cards container).</p>
<h2 id="heading-how-to-use-subgrid">How to Use Subgrid</h2>
<p>To create a <code>subgrid</code>, assign the keyword as a value to either a <code>grid-template-columns</code> or a <code>grid-template-rows</code> of a nested grid.</p>
<p>To implement this in our project, we'll first turn the article element into a grid container in order to place its children in a structured grid. Next, <code>grid-template-rows</code> is given a value of <code>subgrid</code>. This inherits the row structure from the cards container grid.</p>
<p>Setting <code>grid-row</code> to <code>span 4</code> basically means the element should occupy a space that covers 4 rows of the parent grid.</p>
<pre><code class="lang-css">  <span class="hljs-selector-tag">article</span> {
    <span class="hljs-attribute">display</span>: grid;
    <span class="hljs-attribute">grid-template-rows</span>: subgrid;
    <span class="hljs-attribute">grid-row</span>: span <span class="hljs-number">4</span>;
}
</code></pre>
<h3 id="heading-optional-code">Optional Code</h3>
<p>The code below for positioning elements with <code>grid-row</code> is not necessary in this project since we're using Subgrid correctly. But it may come in handy for more complex layouts when you want explicit control over the placement of each element within the grid.</p>
<pre><code class="lang-css">    <span class="hljs-selector-tag">img</span> {
      <span class="hljs-attribute">grid-row</span>: <span class="hljs-number">1</span>/<span class="hljs-number">2</span>;
    }

    <span class="hljs-selector-tag">h3</span> {
      <span class="hljs-attribute">grid-row</span>: <span class="hljs-number">2</span>/<span class="hljs-number">3</span>;
    }

    <span class="hljs-selector-tag">p</span> {
      <span class="hljs-attribute">grid-row</span>: <span class="hljs-number">3</span>/<span class="hljs-number">4</span>;
    }

    <span class="hljs-selector-tag">button</span> {
      <span class="hljs-attribute">grid-row</span>: <span class="hljs-number">4</span>/<span class="hljs-number">5</span>;
    }
</code></pre>
<p>Once <code>subgrid</code> is applied, our cards should be perfectly aligned as shown in the image below. This alignment occurs because the child elements within each card (like titles, paragraphs, and buttons) now share the same grid structure, inherited from the parent. They are "aware" of each other and automatically adjust their positions to stay in sync.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724182833885/5d985d19-d203-4bd3-a5b2-afbf0f060fa9.png" alt="An image of the products cards aligned using subgrid" class="image--center mx-auto" width="2161" height="1272" loading="lazy"></p>
<p>For example, even if the titles for Sedans and SUVs are shorter, the grid ensures that their paragraphs and buttons start in the same rows, maintaining consistency across all cards. This leads to a cleaner, more organized layout, where each element is aligned regardless of varying content lengths.</p>
<h2 id="heading-subgrid-in-browser-devtools">Subgrid in Browser DevTools</h2>
<p>In any modern browser, right-click on the project webpage and select inspect from the list of options. Or use the shortcut (command + option + I on Mac or control + shift + I on Windows) to open the Elements tab of DevTools.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724164230096/01861ffd-27a3-4394-bf96-fefcedd890f2.png" alt="An image of an inspected subgrid in Chrome DevTools" class="image--center mx-auto" width="2257" height="1371" loading="lazy"></p>
<p>As you can see in the image above, just like we have for grid, Subgrid also has a badge. Toggle it to inspect or debug a Subgrid. It toggles an overlay that shows columns, rows, and their numbers on top of the element in the viewport.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Subgrid is a helpful tool for aligning layouts – something you had to do manually in the past. Now, nested grids can inherit properties such as rows and columns from their parent grids. This extends the abilities of CSS Grid to create consistent and perfectly aligned designs.</p>
<p>If you're ever tempted to create an unending loop of CSS grids just to get a design with differently sized content to align perfectly – instead, reach for CSS Subgrid to make your code cleaner and easier to manage.</p>
<p>Here are some helpful resources:</p>
<ul>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout/Subgrid">MDN on CSS Subgrid</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=Yl8hg2FG20Q">Learn CSS Subgrid</a></p>
</li>
<li><p><a target="_blank" href="https://web.dev/articles/css-subgrid">Web Dev on CSS Subgrid</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Media Queries vs Container Queries – Which Should You Use and When? ]]>
                </title>
                <description>
                    <![CDATA[ As the web evolves, new tools and ideas are released with the goal of making our lives as web developers easier. This means we have to choose whether to stick with the old ways or discard them entirely for the shiny new stuff. But does this always de... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/media-queries-vs-container-queries/</link>
                <guid isPermaLink="false">66c5a3401078112e60c1e703</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ responsive design ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Fri, 28 Jun 2024 20:21:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/06/titleimage.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As the web evolves, new tools and ideas are released with the goal of making our lives as web developers easier. This means we have to choose whether to stick with the old ways or discard them entirely for the shiny new stuff. But does this always demand an either-or solution?</p>
<p>When in situations like these, the ideal approach is to understand both concepts – compare and contrast their strengths and weaknesses and then decide their most appropriate applications. This is exactly what this article will do with CSS media queries and container queries.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-responsive-and-intrinsic-web-design">Responsive and Intrinsic Web Design</a></li>
<li><a class="post-section-overview" href="#heading-what-are-media-queries">What are media queries?</a></li>
<li><a class="post-section-overview" href="#heading-what-are-container-queries">What are container queries?</a></li>
<li><a class="post-section-overview" href="#heading-how-do-media-queries-and-container-queries-compare">Real-life comparison and key differences</a></li>
<li><a class="post-section-overview" href="#heading-which-should-you-use-and-when">Which should you use and when?</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-responsive-and-intrinsic-web-design">Responsive and Intrinsic Web Design</h2>
<p>Before 2010, web developers could get away with creating websites that worked mainly on desktop. This was until Ethan Marcotte introduced the concept of Responsive Web Design (RWD). It's <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Responsive_Design">defined by MDN</a> as <em>a way to design for a multi-device web</em>. This lead to the adoption of media queries as a component of RWD. </p>
<p>But lately there's been a shift towards what Jen Simmons defined as Intrinsic Web Design – the need for creating context-aware components. And container queries are making this possible.</p>
<h2 id="heading-what-are-media-queries">What Are Media Queries?</h2>
<p>Media queries are rules for applying specified styles to an element if certain conditions are met. They’re popularly used to ensure that websites are responsive on various devices by querying the viewport width. </p>
<p>Media queries are characterized by an @media rule followed by a condition in parentheses and an expression within brackets that will be applied if the indicated condition is met. So, if we wanted to change the background color of a div based on the viewport width of a device, this is how we might do that:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Mobile */</span>
<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">480px</span>) {
  <span class="hljs-selector-class">.mysite</span> {
    <span class="hljs-attribute">background-color</span>: red;
  }
}
</code></pre>
<p>In the sample code above, we’re asking for the </p><div> with class of mysite to be given a background-color of red if the viewport reaches a maximum width of 480px.<p></p>
<p><strong>Tip</strong>: Max-width is used to assume a desktop-first design and targeting smaller as we go down. If it were a mobile-first design, we'd use min-width to target bigger screens as we go up.</p>
<h2 id="heading-what-are-container-queries">What Are Container Queries?</h2>
<p>Container queries are rules for applying specified styles to an element based on the size of that element’s parent container. They're an answer to a long-standing question by web developers who wanted the ability to respond to changes within an individual container on the page rather than the whole viewport.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.header</span> {
   <span class="hljs-attribute">container</span>: mysite / inline-size;
}

<span class="hljs-keyword">@container</span> mysite (<span class="hljs-attribute">min-width:</span> <span class="hljs-number">600px</span>) {
   <span class="hljs-selector-class">.maincard</span> {
       <span class="hljs-attribute">grid-template-column</span>: <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr;
    }
   <span class="hljs-selector-class">.item</span> {
       <span class="hljs-attribute">background-color</span>: green;
    }
}
</code></pre>
<p>As you can see in the code above, we first define a container whose children we want to make changes to. In our case, we’d like to make changes to the element with class of item, within the header container. You can do this by giving the container a name (optional) and type. </p>
<p>Next, using the @container rule, we check for condition(s) and apply some styles if met. For a minimum width of 600px, we want green as the background-color and two grid columns.</p>
<p><strong>Tip</strong>: You don't define a container to make changes directly to that container – but to it's children. This means that if we wanted to make changes to the header container itself, we would have to nest it within another container: for instance container A and query A to affect it's child – header.</p>
<h2 id="heading-how-do-media-queries-and-container-queries-compare">How Do Media Queries and Container Queries Compare?</h2>
<p>Now, with an understanding of how both work, let's see them in real-life. The CodePen below shows four elements in a layout. The first two are styled with container queries while the bottom two are styled with media queries. You can resize the viewport to see how the elements respond.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/mqvscq-demo.png" alt="Image" width="600" height="400" loading="lazy">
<em>Media and container queries CodePen demo: project inspired by Miriam Suzanne.</em></p>
<p></p><p>
  <span>See the Pen <a href="https://codepen.io/ophyboamah/pen/YzbaROw">
  MQ vs CQ (from MS)</a> by Ophy Boamah (<a href="https://codepen.io/ophyboamah">@ophyboamah</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p><p></p>


<h3 id="heading-key-differences-between-media-queries-and-container-queries">Key Differences Between Media Queries and Container Queries</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/comparetable.png" alt="Image" width="600" height="400" loading="lazy">
<em>Summary of main differences, explained in detail below</em></p>
<h3 id="heading-viewport-based-vs-container-based">Viewport-based vs. Container-based</h3>
<p>Media queries apply styles based on the size of the viewport (the entire browser window). This means that the layout changes according to the overall screen size, making it suitable for adjusting designs for different devices like mobile phones, tablets, and desktops. </p>
<p>Container queries, on the other hand, apply styles based on the size of the container element in which they are placed. This allows individual components to adapt their appearance based on their own size rather than the viewport size, making them highly flexible and reusable across different parts of a web page.</p>
<h3 id="heading-modularity-and-flexibility">Modularity and Flexibility</h3>
<p>Since media queries depend on the viewport size, they can be less effective for creating truly modular components. Adjusting styles for one part of a page may unintentionally affect others, especially in complex layouts. Plus, they may fall short in scenarios where components need to adapt independently within a larger layout. This can lead to less maintainable CSS. </p>
<p>In contrast, container queries promote modularity and flexibility by allowing styles to be defined based on the container's size. This means you can create components that are self-contained, adaptable, and that can be reused in various parts of a website without unexpected changes, enhancing their reusability. </p>
<p>This results in more adaptive designs where components can adjust their own layout and appearance, which is useful in modern, component-based design systems.</p>
<h3 id="heading-complexity-and-maintenance">Complexity and Maintenance</h3>
<p>In large projects, managing numerous media queries can become cumbersome. As the number of breakpoints and special cases grows, the CSS can become complex and harder to maintain. Over time, this can lead to a bloated and difficult-to-manage codebase. </p>
<p>Container queries can simplify the maintenance of CSS in large projects. By keeping styles component-specific and context-aware, the CSS remains more organized and modular. This reduces the complexity of managing global breakpoints and makes it easier to maintain, leading to a more organized codebase.</p>
<h2 id="heading-which-should-you-use-and-when">Which Should You Use and When?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/finalsection.png" alt="Image" width="600" height="400" loading="lazy">
<em>Media query vs container query (image credit: <i><a target="_blank" href="http://web.dev/">web.dev</a></i>)</em></p>
<p>Everything we discussed in the previous sections is meant to help you make an informed decision. Having seen how these two concepts compare and contrast, now consider the following factors:</p>
<h3 id="heading-understanding-and-comfort">Understanding and Comfort</h3>
<p>How well do you understand each concept? Container queries are relatively new but if you spend time studying and experimenting with them, just like media queries, the learning curve isn’t intimidating. So use in production the one you understand and are more comfortable with, to make your life easier.</p>
<h3 id="heading-project-requirements-and-complexity">Project Requirements and Complexity</h3>
<p>What’s the design approach you’re using and how complex is your project? Because sometimes the design approach for your project will determine which of these will best suit your needs. Also, the more complex, the harder it’ll get to maintain your code and you want to use something you can manage.</p>
<h3 id="heading-future-trends-and-collaboration">Future Trends and Collaboration</h3>
<p>The future of responsive design is looking more and more intrinsic. We’re gradually making a shift towards component responsiveness based on changes to their individual content, and container queries shine best here. </p>
<p>But media queries don't seem to be going anywhere anytime soon, so you can use them together to achieve perfect responsiveness across many different devices.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The potential for container queries to allow creating reusable components in CSS is exciting – but it may not be ready to fully replace media queries for making web pages responsive just yet. </p>
<p>For now, our best bet is using them together, and where each makes the most sense. And you can be sure to make the right call by experimenting further to internalize the pros and cons of each.</p>
<p>Here are some helpful resources:</p>
<ul>
<li><a target="_blank" href="https://www.freecodecamp.org/news/learn-css-media-queries-by-building-projects/">freeCodeCamp on Media Queries</a></li>
<li><a target="_blank" href="https://ishadeed.com/article/css-container-query-guide/">Ahmad Shadeed on Container Queries</a></li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=2rlWBZ17Wes">How to Use Media Queries and Container Queries</a></li>
</ul>
</div> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is Cross-Browser Compatibility? How to Build Websites that Work Everywhere ]]>
                </title>
                <description>
                    <![CDATA[ When building for the web, it's easy to develop tunnel vision and only build for yourself. You may overlook the diverse needs of your audience and focus solely on your preferences and how things look on your preferred browser. This can cause you to m... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-cross-browser-compatibility/</link>
                <guid isPermaLink="false">66c5a34fdd1f1e4092a3256c</guid>
                
                    <category>
                        <![CDATA[ Browsers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Compatibility ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Wed, 06 Mar 2024 18:26:43 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/03/Cross-Browser.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When building for the web, it's easy to develop tunnel vision and only build for yourself. You may overlook the diverse needs of your audience and focus solely on your preferences and how things look on your preferred browser. This can cause you to miss out on crucial functionality aspects and lead to future compatibility issues on other browsers. </p>
<p>In this article, we'll dive into practical strategies for achieving cross-browser compatibility, focusing on specific UI components like form elements, scrollbars, and fonts. Then we'll discuss some general best practices that every web developer should adopt.</p>
<blockquote>
<p>“Remember that you are not your users — just because your site works on your MacBook Pro or high-end Galaxy Nexus, doesn't mean it will work for all your users!” – <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Introduction">MDN Web Docs</a></p>
</blockquote>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-cross-browser-compatibility">What is Cross-Browser Compatibility?</a></li>
<li><a class="post-section-overview" href="#heading-common-cross-browser-issues-and-solutions">Common Cross-Browser Issues and Solutions</a></li>
<li><a class="post-section-overview" href="#heading-best-practices-for-cross-browser-compatibility">Best Practices for Cross-Browser Compatibility</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-what-is-cross-browser-compatibility">What is Cross-Browser Compatibility?</h2>
<p>In simple terms, cross-browser compatibility is about ensuring that your website delivers a consistent, top-notch experience for all users, regardless of their browser choice. </p>
<p>Browsers use different engines, so by default they render websites differently. In order to get your websites to look and work the same regardless of the user's browser requires an understanding of unique browser capabilities.</p>
<p>Cross-browser compatibility says that ideally, a website should look and function the same whether someone is viewing it on Chrome, Microsoft Edge and Opera (powered by Blink engine), Firefox (powered by Gecko engine) or even Safari (powered by WebKit engine). </p>
<h3 id="heading-benefits-of-cross-browser-compatibility">Benefits of Cross-Browser Compatibility:</h3>
<ol>
<li>Wider reach – your websites are accessible to more users, regardless of the browser they use.</li>
<li>Consistent User Experience – your websites have a uniform look and functionality across platforms.</li>
<li>Better Search Engine Optimization (SEO) – your websites get higher rankings from being more user-friendly.</li>
</ol>
<h2 id="heading-common-cross-browser-issues-and-solutions">Common Cross-Browser Issues and Solutions</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/browserstack.png" alt="Image" width="600" height="400" loading="lazy">
<em>Infographic showing test results of a web page on different browsers. Image credit Browserstack</em></p>
<h3 id="heading-form-elements">Form Elements</h3>
<p>The appearance and behavior of form elements like <code>&lt;input&gt;</code>, <code>&lt;select&gt;</code>, <code>&lt;textarea&gt;</code>, and <code>&lt;button&gt;</code> can vary significantly across browsers. This affects both the visual aspect and usability of forms, including how users interact with them (for example, clicking, focusing, and typing).</p>
<p>For instance, placeholder text in <code>&lt;input&gt;</code> fields may appear fainter in one browser and more pronounced in another, leading to readability issues. </p>
<p>To resolve this:</p>
<ul>
<li>Use CSS to standardize the appearance of form elements as much as possible.</li>
<li>For placeholders, ensure contrast and legibility across browsers:</li>
</ul>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">::placeholder</span> { <span class="hljs-comment">/* Chrome, Firefox, Opera, Safari 10.1+ */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#909090</span>;
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>; <span class="hljs-comment">/* Firefox */</span>
}

<span class="hljs-selector-tag">input</span><span class="hljs-selector-class">.studentid</span><span class="hljs-selector-pseudo">:-ms-input-placeholder</span> { <span class="hljs-comment">/* Microsoft Edge */</span>
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#909090</span>;
}
</code></pre>
<p>The CSS code above targets placeholder text in input fields across browsers, sets their color to #909090, and ensures full opacity for consistent visibility (with specific rules for Microsoft Edge).</p>
<h3 id="heading-fonts">Fonts</h3>
<p>Fonts and typography face several cross-browser compatibility issues, from varying default font sizes to differences in font rendering engines. This can affect the weight, spacing, and overall appearance of text.</p>
<p>A font might appear thinner and more spaced out in Chrome compared to Edge, affecting readability and design consistency. </p>
<p>To resolve this:</p>
<ul>
<li>Define a base font size in your CSS and use relative units (like <code>em</code> or <code>rem</code>) for text sizing as shown in the code below. This helps maintain scalability and consistency.</li>
</ul>
<pre><code class="lang-css"><span class="hljs-selector-tag">html</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>; <span class="hljs-comment">/* Define a base font size */</span>
}

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Open Sans'</span>, sans-serif;
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.6</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>;
}

<span class="hljs-selector-tag">h1</span>, <span class="hljs-selector-tag">h2</span>, <span class="hljs-selector-tag">h3</span>, <span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">2rem</span>;;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1.5rem</span>;
}
</code></pre>
<ul>
<li>When using web fonts, ensure they are loaded properly across all browsers by using services like Google Fonts, which provide cross-browser compatible font loading:</li>
</ul>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"&lt;https://fonts.googleapis.com/css?family=Open+Sans&amp;display=swap&gt;"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>&gt;</span>
</code></pre>
<ul>
<li>The code below makes sure that the 'Open Sans' font looks the same on our website, no matter the browser. It does this first by using a version of the font that might already be on our computer to load things faster. Otherwise, it grabs it from the internet but swaps in a default font while waiting for the latter to load. </li>
</ul>
<pre><code class="lang-css"><span class="hljs-keyword">@font-face</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Open Sans'</span>;
  <span class="hljs-attribute">font-style</span>: normal;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">400</span>;
  <span class="hljs-attribute">font-display</span>: swap;
  <span class="hljs-attribute">src</span>: <span class="hljs-built_in">local</span>(<span class="hljs-string">'Open Sans Regular'</span>), <span class="hljs-built_in">local</span>(<span class="hljs-string">'OpenSans-Regular'</span>), <span class="hljs-built_in">url</span>(&lt;https://fonts.gstatic.com/s/opensans/v15/mem8YaGs126MiZpBA-UFVZ0b.woff2&gt;) <span class="hljs-built_in">format</span>(<span class="hljs-string">'woff2'</span>);
}
</code></pre>
<h3 id="heading-scrollbars">Scrollbars</h3>
<p>Scrollbar styling has long been a challenge for web developers due to inconsistent support across different browsers. While browsers like Chrome, Safari, and Edge have provided ways to customize scrollbars using CSS, the level of support and ways of implementing them vary.</p>
<p>Recent updates have seen improvements in standardizing scrollbar customization, with most modern browsers adopting similar capabilities. But there are still some differences in the approach:</p>
<p>For <strong>Chrome, Edge, and Firefox</strong>, you can use the CSS <code>scrollbar-width</code> and <code>scrollbar-color</code> properties to customize the scrollbar's appearance. These are part of a newer standard aimed at providing a more consistent way of styling scrollbars across browsers that support it.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* For Chrome, Firefox, and Edge */</span>
<span class="hljs-selector-tag">scrollbar-width</span>: <span class="hljs-selector-tag">thin</span>;
<span class="hljs-selector-tag">scrollbar-color</span>: <span class="hljs-selector-id">#c0c0c0</span> <span class="hljs-selector-id">#f0f0f0</span>;
</code></pre>
<p><strong>For Safari</strong>, which uses the WebKit rendering engine, you'll need to use the <code>::-webkit-scrollbar</code> pseudo-element to achieve similar styling. This method is specific to WebKit-based browsers.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* For Safari */</span>
<span class="hljs-selector-class">.mostly-customized-scrollbar</span><span class="hljs-selector-pseudo">::-webkit-scrollbar</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#aaa</span>; <span class="hljs-comment">/* or add it to the track */</span>
}
</code></pre>
<p>The CSS code above customizes the appearance of scrollbars across those browsers by adjusting their size and colours.</p>
<p>But for consistency across all browsers, you'll need to design your web pages in a way that the default scrollbar appearance does not negatively impact your design.</p>
<h2 id="heading-best-practices-for-cross-browser-compatibility">Best Practices for Cross-Browser Compatibility</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/best-practices.jpeg" alt="Image" width="600" height="400" loading="lazy">
<em>Infographic showing measuring tools. Image credit Creative Bloq</em></p>
<h3 id="heading-define-a-doctype">Define a Doctype</h3>
<p>Start your HTML document with a <code>&lt;!DOCTYPE&gt;</code> declaration to ensure standards mode is activated. </p>
<p>This is important because it tells the web browser which version of HTML the page is written in. Without it, browsers might render the page in "quirks mode," – where the browser assumes you've written old, non-standard code. This ultimately leads to unpredictable styling and layout issues because modern web standards are not fully applied.</p>
<p>A <code>&lt;!DOCTYPE&gt;</code> declaration in HTML5 looks like this at the very beginning of your HTML file:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
</code></pre>
<h3 id="heading-use-a-css-reset">Use a CSS Reset</h3>
<p>A CSS reset is basically adding a set of rules that target common elements to remove their default styling, reducing browser-default discrepancies. </p>
<p>Various browsers have different inherent styles for HTML elements – margins, paddings, font sizes, and so on. So implementing a CSS reset makes sure that only the styles you write in your code will take effect. This leads to a consistent baseline for styling your webpage across various browsers. </p>
<p>There are developers that like to write theirs from scratch. And there are others like me, who use <a target="_blank" href="https://meyerweb.com/eric/tools/css/reset/">Eric Meyer's popular and free CSS reset</a> as you can see in the code below:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* http://meyerweb.com/eric/tools/css/reset/ 
   v2.0 | 20110126
   License: none (public domain)
*/</span>

<span class="hljs-selector-tag">html</span>, <span class="hljs-selector-tag">body</span>, <span class="hljs-selector-tag">div</span>, <span class="hljs-selector-tag">span</span>, <span class="hljs-selector-tag">applet</span>, <span class="hljs-selector-tag">object</span>, <span class="hljs-selector-tag">iframe</span>,
<span class="hljs-selector-tag">h1</span>, <span class="hljs-selector-tag">h2</span>, <span class="hljs-selector-tag">h3</span>, <span class="hljs-selector-tag">h4</span>, <span class="hljs-selector-tag">h5</span>, <span class="hljs-selector-tag">h6</span>, <span class="hljs-selector-tag">p</span>, <span class="hljs-selector-tag">blockquote</span>, <span class="hljs-selector-tag">pre</span>,
<span class="hljs-selector-tag">a</span>, <span class="hljs-selector-tag">abbr</span>, <span class="hljs-selector-tag">acronym</span>, <span class="hljs-selector-tag">address</span>, <span class="hljs-selector-tag">big</span>, <span class="hljs-selector-tag">cite</span>, <span class="hljs-selector-tag">code</span>,
<span class="hljs-selector-tag">del</span>, <span class="hljs-selector-tag">dfn</span>, <span class="hljs-selector-tag">em</span>, <span class="hljs-selector-tag">img</span>, <span class="hljs-selector-tag">ins</span>, <span class="hljs-selector-tag">kbd</span>, <span class="hljs-selector-tag">q</span>, <span class="hljs-selector-tag">s</span>, <span class="hljs-selector-tag">samp</span>,
<span class="hljs-selector-tag">small</span>, <span class="hljs-selector-tag">strike</span>, <span class="hljs-selector-tag">strong</span>, <span class="hljs-selector-tag">sub</span>, <span class="hljs-selector-tag">sup</span>, <span class="hljs-selector-tag">tt</span>, <span class="hljs-selector-tag">var</span>,
<span class="hljs-selector-tag">b</span>, <span class="hljs-selector-tag">u</span>, <span class="hljs-selector-tag">i</span>, <span class="hljs-selector-tag">center</span>,
<span class="hljs-selector-tag">dl</span>, <span class="hljs-selector-tag">dt</span>, <span class="hljs-selector-tag">dd</span>, <span class="hljs-selector-tag">ol</span>, <span class="hljs-selector-tag">ul</span>, <span class="hljs-selector-tag">li</span>,
<span class="hljs-selector-tag">fieldset</span>, <span class="hljs-selector-tag">form</span>, <span class="hljs-selector-tag">label</span>, <span class="hljs-selector-tag">legend</span>,
<span class="hljs-selector-tag">table</span>, <span class="hljs-selector-tag">caption</span>, <span class="hljs-selector-tag">tbody</span>, <span class="hljs-selector-tag">tfoot</span>, <span class="hljs-selector-tag">thead</span>, <span class="hljs-selector-tag">tr</span>, <span class="hljs-selector-tag">th</span>, <span class="hljs-selector-tag">td</span>,
<span class="hljs-selector-tag">article</span>, <span class="hljs-selector-tag">aside</span>, <span class="hljs-selector-tag">canvas</span>, <span class="hljs-selector-tag">details</span>, <span class="hljs-selector-tag">embed</span>, 
<span class="hljs-selector-tag">figure</span>, <span class="hljs-selector-tag">figcaption</span>, <span class="hljs-selector-tag">footer</span>, <span class="hljs-selector-tag">header</span>, <span class="hljs-selector-tag">hgroup</span>, 
<span class="hljs-selector-tag">menu</span>, <span class="hljs-selector-tag">nav</span>, <span class="hljs-selector-tag">output</span>, <span class="hljs-selector-tag">ruby</span>, <span class="hljs-selector-tag">section</span>, <span class="hljs-selector-tag">summary</span>,
<span class="hljs-selector-tag">time</span>, <span class="hljs-selector-tag">mark</span>, <span class="hljs-selector-tag">audio</span>, <span class="hljs-selector-tag">video</span> {
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">border</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">font</span>: inherit;
    <span class="hljs-attribute">vertical-align</span>: baseline;
}
<span class="hljs-comment">/* HTML5 display-role reset for older browsers */</span>
<span class="hljs-selector-tag">article</span>, <span class="hljs-selector-tag">aside</span>, <span class="hljs-selector-tag">details</span>, <span class="hljs-selector-tag">figcaption</span>, <span class="hljs-selector-tag">figure</span>, 
<span class="hljs-selector-tag">footer</span>, <span class="hljs-selector-tag">header</span>, <span class="hljs-selector-tag">hgroup</span>, <span class="hljs-selector-tag">menu</span>, <span class="hljs-selector-tag">nav</span>, <span class="hljs-selector-tag">section</span> {
    <span class="hljs-attribute">display</span>: block;
}
<span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1</span>;
}
<span class="hljs-selector-tag">ol</span>, <span class="hljs-selector-tag">ul</span> {
    <span class="hljs-attribute">list-style</span>: none;
}
<span class="hljs-selector-tag">blockquote</span>, <span class="hljs-selector-tag">q</span> {
    <span class="hljs-attribute">quotes</span>: none;
}
<span class="hljs-selector-tag">blockquote</span><span class="hljs-selector-pseudo">:before</span>, <span class="hljs-selector-tag">blockquote</span><span class="hljs-selector-pseudo">:after</span>,
<span class="hljs-selector-tag">q</span><span class="hljs-selector-pseudo">:before</span>, <span class="hljs-selector-tag">q</span><span class="hljs-selector-pseudo">:after</span> {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">''</span>;
    <span class="hljs-attribute">content</span>: none;
}
<span class="hljs-selector-tag">table</span> {
    <span class="hljs-attribute">border-collapse</span>: collapse;
    <span class="hljs-attribute">border-spacing</span>: <span class="hljs-number">0</span>;
}
</code></pre>
<p>There's another group of developers that use <a target="_blank" href="https://necolas.github.io/normalize.css/">Normalize.css</a>, which you can install using a package manager like npm and then importing it in your CSS.</p>
<pre><code class="lang-bash">npm install normalize.css
</code></pre>
<h3 id="heading-review-css-property-support">Review CSS Property Support</h3>
<p>Before using advanced CSS features, check their compatibility on websites like <a target="_blank" href="https://caniuse.com/">Can I Use</a>. There, you can find detailed compatibility tables for HTML, CSS, and JavaScript features across different browsers and versions. This should help you make informed decisions about which technologies to use and when to implement fallbacks.</p>
<p>In the screenshot below, I searched for CSS Grid and immediately got to see the various browsers and their versions that support it. So before implementing CSS Grid on my web page, I have an idea of the browsers that it works with.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-05-at-9.06.17-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Browser compatibility for CSS Grid.</em></p>
<h3 id="heading-create-responsive-websites">Create Responsive Websites</h3>
<p>The multi-device world we currently live in demands that, as web developers, we make responsiveness a priority. </p>
<p>We can use fluid layouts, flexible images, and media queries to ensure our websites adapt to any screen size. The ripple effects of getting responsiveness right is cross-browser compatibility, accessibility and enhanced user experience.</p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/responsive-design-best-practices/">Here's an article</a> discussing some best practices for responsive design and how to implement them.</p>
<h3 id="heading-do-cross-browser-testing">Do Cross-Browser Testing</h3>
<p>Testing has become such a buzzword in programming lately, but this is because it's very important to make sure the code you write works as expected. </p>
<p>It's not just about checking if your TypeScript code runs smoothly, though. Even simpler web projects need thorough testing. </p>
<p>Cross-browser testing means trying your web pages on various browsers and devices to make sure they look and work consistently across board.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Cross-browser compatibility may be a mouthful to pronounce. But as we’ve seen, it's essential to consider when building websites. And you can gradually make your websites compatible by testing and tweaking your code and implementing some of the five best practices we’ve discussed above. </p>
<p>So, before you draw the curtains on your next website or web app, remember to check if your users on Chrome, Firefox, Safari, and other browsers are seeing and experiencing the same things.</p>
<p>Here are some helpful resources:</p>
<ul>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Introduction">MDN Web Docs on Cross-browser compatibility</a></li>
<li><a target="_blank" href="https://medium.com/@codepaper_/the-significance-of-cross-browser-compatibility-in-website-development-8ea2cca480dc">Codepaper on Significance of Cross-browser compatibility</a></li>
<li><a target="_blank" href="https://meyerweb.com/eric/tools/css/reset/">Eric Meyer on CSS Reset</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Advanced CSS Selectors – How and When to Use Them ]]>
                </title>
                <description>
                    <![CDATA[ Writing CSS is often painful for a lot of developers, because many of us lose our curiosity very early in the learning journey. For instance, as soon as we learn basic CSS selectors, we settle into a pattern of using only those, thinking they're all ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/advanced-css-selectors/</link>
                <guid isPermaLink="false">66c5a3313d77fae9eb82a472</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Mon, 26 Feb 2024 17:12:11 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/Advanced-CSS.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Writing CSS is often painful for a lot of developers, because many of us lose our curiosity very early in the learning journey. For instance, as soon as we learn basic CSS selectors, we settle into a pattern of using only those, thinking they're all we need. But what if there’s more? </p>
<p>In this article, you'll learn about some essential advanced CSS selectors and combinators like <code>child and sibling combinators</code> , <code>pseudo-classes</code>, <code>structural pseudo-classes</code>, <code>pseudo-elements</code> and <code>attribute selectors</code> by building an Interactive FAQ section. If you'd like to move ahead to see what we'll build, <a class="post-section-overview" href="#building-an-interactive-faq-section">check it out</a>.</p>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-are-advanced-css-selectors">What are Advanced CSS selectors?</a></li>
<li><a class="post-section-overview" href="#heading-why-you-should-use-advanced-css-selectors">Why You Should Use Advanced CSS selectors</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-an-interactive-faq-section">How to Build an Interactive FAQ section</a></li>
<li><a class="post-section-overview" href="#heading-full-project-code">Full Project Code</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h1 id="heading-what-are-advanced-css-selectors"><strong>What are Advanced CSS Selectors?</strong></h1>
<p>At its core, CSS is about selecting elements from the DOM (Document Object Model) to apply styles to them. </p>
<p>While basic selectors like class, ID, and element selectors get much of the day-to-day work done, advanced CSS selectors offer a deeper level of specificity and control. They enable you to target exactly the elements you wish to style, based on attributes, states, and their relationships to each other.</p>
<p>For instance, you can dress up links that have been visited (<code>:visited</code>), style the first paragraph within an article (<code>article p:first-of-type</code>), or target empty elements (<code>:empty</code>), all of which save you from littering your HTML code with extra classes or IDs ultimately leading to cleaner and more efficient code.</p>
<h1 id="heading-why-you-should-use-advanced-css-selectors">Why You Should Use Advanced CSS Selectors</h1>
<p>Here are three of many reasons to consider giving advanced CSS selectors a chance:</p>
<ol>
<li><strong>Interactive Styling</strong>: With pseudo-classes like <code>:hover</code> and <code>:focus</code>, you can create interactive elements that respond to user actions, directly within CSS. This is a win-win, because it minimizes the need for JavaScript for visual effects and so keeps your scripts lean and still boosts user experience and interactivity.</li>
<li><strong>Accessibility and SEO</strong>: Using advanced selectors can help keep HTML semantic, as styles are applied based on the natural structure of your document and attributes of elements. This makes your code easier to read and maintain but most importantly improves accessibility and SEO.</li>
<li><strong>Future Relevance</strong>: As web standards evolve, so does CSS. This means by adopting advanced selectors today, you're aligning your stylesheets with the future of web development. This ensures that your designs remain resilient and adaptable, no matter what changes come to the web .</li>
</ol>
<h1 id="heading-how-to-build-an-interactive-faq-section">How to Build an Interactive FAQ Section</h1>
<p>To learn advanced CSS selectors, we’ll build an interactive FAQ section to reveal answers to questions when clicked. We'll also implement different styles for the FAQs based on their state or content. </p>
<p>This practical approach will solidify your understanding as you see their application in real-world scenarios.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/finalproject.gif" alt="Image" width="600" height="400" loading="lazy">
<em>A GIF showing the FAQ section we'll build in this article</em></p>
<p>Check it out on CodePen <a target="_blank" href="https://codepen.io/ophyboamah/full/WNmWRvd">here</a>.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>Basic knowledge of HTML and CSS</li>
<li>An IDE</li>
<li>A web browser</li>
</ul>
<h2 id="heading-html-code">HTML Code</h2>
<p>The HTML structure for our project consists of a series of FAQ items, each contained within a <code>div</code> and featuring a clickable question (<code>label</code> or <code>button</code>) that controls the visibility of the answer (<code>div</code>). Each FAQ item has a checkbox input to manage its open/close state, using CSS to visually toggle the answer visibility without JavaScript.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-section"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-heading"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Frequently Asked Questions<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Here are a few general CSS questions and their answers, hope they serve as a refresher.<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">class</span>=<span class="hljs-string">"faq-container"</span>&gt;</span>
      <span class="hljs-comment">&lt;!-- FAQ Item 1 --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-item"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"faq1"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-toggle"</span> <span class="hljs-attr">hidden</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"faq1"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-question"</span>&gt;</span>What's the difference between px, em, and rem?<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-answer"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>px is a fixed size, em changes size based on the parent element's font size, and rem is always relative to the document's root font size, making layouts more flexible.<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>&gt;</span>
      <span class="hljs-comment">&lt;!-- FAQ Item 2 --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-item"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"faq2"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-toggle"</span> <span class="hljs-attr">hidden</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"faq2"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-question"</span>&gt;</span>Why use :hover and :focus pseudo-classes?<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-answer"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>They let you style elements when users interact with them, like changing a button's color when hovered over, making websites more interactive.<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>&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">section</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<h2 id="heading-starting-basic-css-code">Starting Basic CSS Code</h2>
<p>The code below applies basic styling to our HTML code above. This is provided so that you can focus on learning how advanced CSS selectors work.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#00ad8f</span>;
}

<span class="hljs-selector-class">.faq-section</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">5em</span>; 
}

<span class="hljs-selector-class">.faq-section</span> <span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2.5em</span>; 
}

<span class="hljs-selector-class">.faq-heading</span> {
  <span class="hljs-attribute">text-align</span>: center; 
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">2em</span>; 
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}

<span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">800px</span>;
  <span class="hljs-attribute">margin</span>: auto;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1em</span>;
}

<span class="hljs-selector-class">.faq-item</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.3em</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#333</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">0.5em</span>;
}

<span class="hljs-selector-class">.faq-toggle</span> {
  <span class="hljs-attribute">display</span>: none; <span class="hljs-comment">/* Hide checkbox */</span>
}

<span class="hljs-selector-class">.faq-question</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#efefef</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1em</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">position</span>: relative; <span class="hljs-comment">/* Necessary for positioning ::before content */</span>
}

<span class="hljs-selector-class">.faq-answer</span> {
  <span class="hljs-attribute">max-height</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">overflow</span>: hidden;
  <span class="hljs-attribute">border-top</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#333</span>;
  <span class="hljs-attribute">transition</span>: transform <span class="hljs-number">0.3s</span> ease, padding <span class="hljs-number">0.3s</span> ease;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span> <span class="hljs-number">1em</span>;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/beforeadvCSS.png" alt="Image" width="600" height="400" loading="lazy">
<em>A screenshot of our FAQ section before adding advanced CSS selectors</em></p>
<h2 id="heading-child-and-sibling-combinators-gt">Child and Sibling Combinators (<code>+</code> , <code>~</code>, <code>&gt;</code>):</h2>
<p>The child and sibling combinators, though not as popular as id and class selectors, are powerful for styling elements in relation to each other. </p>
<p>The child combinator (<strong><code>&gt;</code></strong>) is essential for targeting direct children of an element, such as styling menu items in a navigation bar without affecting nested drop-downs. </p>
<p>Meanwhile, the adjacent sibling selector (<strong><code>+</code></strong>) targets only the sibling that immediately follows an element for tasks like making the first paragraph after a heading stand out </p>
<p>And the general sibling selector (<strong><code>~</code></strong>) targets any sibling that follows an element, like highlighting list items following a checked checkbox.</p>
<p>In our project, as seen in the code below, when a question is clicked (that is, its associated checkbox is checked), the adjacent sibling selector (<code>+</code>) shows a "-" symbol to indicate an open state, meaning an FAQ is opened. Also, it controls the max-height of the answer to reveal it smoothly.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.faq-toggle</span><span class="hljs-selector-pseudo">:checked</span> + <span class="hljs-selector-class">.faq-question</span><span class="hljs-selector-pseudo">::after</span> {
  <span class="hljs-attribute">content</span>: <span class="hljs-string">'-'</span>; <span class="hljs-comment">/* Changes the plus to a minus on the FAQ question when the toggle is checked */</span>
}

<span class="hljs-selector-class">.faq-toggle</span><span class="hljs-selector-pseudo">:checked</span> + <span class="hljs-selector-class">.faq-question</span> + <span class="hljs-selector-class">.faq-answer</span> {
  <span class="hljs-attribute">max-height</span>: <span class="hljs-number">1000px</span>; <span class="hljs-comment">/* Reveals the answer when the toggle is checked */</span>
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/childandsib.png" alt="Image" width="600" height="400" loading="lazy">
<em>A screenshot of our FAQ section adding the - symbol on open questions</em></p>
<h2 id="heading-pseudo-classes-nth-child-nth-of-type-not-focus-hover">Pseudo-Classes (<code>:nth-child()</code>, <code>:nth-of-type()</code>, <code>:not()</code>, <code>:focus</code>, <code>:hover</code>):</h2>
<p>Pseudo-classes allow styling of elements based on their state or characteristics without changing the HTML structure. </p>
<p>They're great for interactive elements, like changing the background color of buttons on hover using <code>:hover</code> and <code>:nth-of-type()</code> to highlight every third image in a gallery for a patterned effect. Or styling every other row in a table to improve readability with <code>:nth-child()</code>and<code>:not()</code>to apply styles to all buttons except the disabled ones.</p>
<p>In our project, as seen in the code below, we use the <code>:nth-of-type()</code> pseudo-class to differentiate between odd and even questions by assigning them different background colors, and <code>:hover</code> to improve interactivity, making the FAQ section easier to navigate visually.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.faq-item</span><span class="hljs-selector-pseudo">:nth-of-type(odd)</span> <span class="hljs-selector-class">.faq-question</span>{
 <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>; <span class="hljs-comment">/* For odd items */</span>
} 

<span class="hljs-selector-class">.faq-item</span><span class="hljs-selector-pseudo">:nth-of-type(even)</span> <span class="hljs-selector-class">.faq-question</span>{
 <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#caffee</span>; <span class="hljs-comment">/* For even items */</span>
}

<span class="hljs-selector-class">.faq-item</span><span class="hljs-selector-pseudo">:nth-of-type(odd)</span> <span class="hljs-selector-class">.faq-question</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#dfdfdf</span>; 
}

<span class="hljs-selector-class">.faq-item</span><span class="hljs-selector-pseudo">:nth-of-type(even)</span> <span class="hljs-selector-class">.faq-question</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#9debd2</span>; 
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/candsibselectors-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>A GIF showing different hover colors for odd and even FAQ questions</em></p>
<h2 id="heading-structural-pseudo-classes-first-child-last-child-empty-only-child">Structural Pseudo-Classes (<code>:first-child</code>, <code>:last-child</code>, <code>:empty</code>, <code>:only-child</code>):</h2>
<p>Structural pseudo-classes shine when it comes to styling elements based on their position within their parent container. This is why they help with tasks like highlighting the first or last item in a list with <code>:first-child</code> to draw attention or <code>:last-child</code> for adding a special border for emphasis. </p>
<p>They also excel in scenarios where the document structure influences style, such as using <code>:empty</code> to hide or differently style empty divs for layout consistency, or <code>:only-child</code> to center content within a div for a clean look.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.faq-item</span><span class="hljs-selector-pseudo">:first-of-type</span> <span class="hljs-selector-class">.faq-question</span> {
  <span class="hljs-attribute">border-top</span>: <span class="hljs-number">2px</span> solid <span class="hljs-number">#007BFF</span>; 
}

<span class="hljs-selector-class">.faq-item</span><span class="hljs-selector-pseudo">:last-of-type</span> <span class="hljs-selector-class">.faq-question</span> {
  <span class="hljs-attribute">border-bottom</span>: <span class="hljs-number">2px</span> solid <span class="hljs-number">#007BFF</span>; 
}
</code></pre>
<p>In our project and in the code above, the <code>:first-of-type</code> and <code>:last-of-type</code> selectors are used to visually distinguish the first and last FAQ items by adding a top and bottom border, respectively.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/structural.png" alt="Image" width="600" height="400" loading="lazy">
<em>A screenshot of our FAQ section with blue borders</em></p>
<h2 id="heading-pseudo-elements-before-after-first-letter-first-line">Pseudo-Elements (<code>::before</code>, <code>::after</code>, :<code>:first-letter</code>, <code>::first-line</code>):</h2>
<p>Pseudo-elements have the ability to create virtual elements that can be styled separately. They allow us to style specific parts of an element, such as adding content before or after an element's content, or styling the first letter or line of text. </p>
<p>You can also use <code>::before</code> and <code>::after</code> to add decorative quotes around block quotes without altering the HTML, or <code>::first-letter</code> to enlarge the first letter of each article similar to what’s done in magazines. Finally, <code>::first-line</code> changes the color of the first line of a paragraph to grab attention.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* ::after used to display "+" symbol */</span>
<span class="hljs-selector-class">.faq-question</span><span class="hljs-selector-pseudo">::after</span> {
  <span class="hljs-attribute">content</span>: <span class="hljs-string">'+'</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#00ad8f</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.4em</span>;
}
</code></pre>
<p>In our project and in the code above, the <code>::after</code> pseudo-element adds a "+" sign to each question in their default states. This complements the "-" symbol we added above on opened questions. Together, these provide visual cues to the user about the state of the FAQ item.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/aftersymbol.png" alt="Image" width="600" height="400" loading="lazy">
<em>A screenshot of our FAQ section adding the + symbol on closed questions</em></p>
<h2 id="heading-attribute-selectors-attrvalue-attrvalue-attrvalue">Attribute Selectors ( <code>[attr^="value"]</code>, <code>[attr$="value"]</code>, <code>[attr*="value"]</code>):</h2>
<p>Attribute selectors provide a way to style elements based on the presence, absence, or value of attributes. They're the go-to for styling elements with specific data attributes, like differentiating external links with <code>[attr^="value"]</code> by targeting URLs that begin with "http" or using <code>[attr$="value"]</code> to apply icons to download links. </p>
<p>All these emphasize the role of attribute selectors in crafting precise and condition-based styles, offering a high level of specificity and flexibility.</p>
<pre><code class="lang-css">
<span class="hljs-selector-class">.faq-item</span><span class="hljs-selector-attr">[data-category^=<span class="hljs-string">"important"</span>]</span> <span class="hljs-selector-class">.faq-question</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#E91E63</span>; 
}
</code></pre>
<p>In our project and in the code above, we use an attribute selector <code>[attr^="value"]</code> to apply a distinct style (red) to questions marked with a <code>data-category</code> as important. This makes them stand out in the FAQ section.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/dataattribute.png" alt="Image" width="600" height="400" loading="lazy">
<em>A screenshot of our FAQ section with the important question differently colored</em></p>
<h1 id="heading-full-project-code">Full Project Code</h1>
<p>Here's the HTML Code:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-section"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-heading"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Frequently Asked Questions<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Here are a few general CSS questions and their answers, hope they serve as a refresher.<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">class</span>=<span class="hljs-string">"faq-container"</span>&gt;</span>
      <span class="hljs-comment">&lt;!-- FAQ Item 1 --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-item"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"faq1"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-toggle"</span> <span class="hljs-attr">hidden</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"faq1"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-question"</span>&gt;</span>What's the difference between px, em, and rem?<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-answer"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>px is a fixed size, em changes size based on the parent element's font size, and rem is always relative to the document's root font size, making layouts more flexible.<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>&gt;</span>
      <span class="hljs-comment">&lt;!-- FAQ Item 2 --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-item"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"faq2"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-toggle"</span> <span class="hljs-attr">hidden</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"faq2"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-question"</span>&gt;</span>Why use :hover and :focus pseudo-classes?<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-answer"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>They let you style elements when users interact with them, like changing a button's color when hovered over, making websites more interactive.<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>&gt;</span>
      <span class="hljs-comment">&lt;!-- FAQ Item 3 --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-item"</span> <span class="hljs-attr">data-category</span>=<span class="hljs-string">"important"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"faq3"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-toggle"</span> <span class="hljs-attr">hidden</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"faq3"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-question"</span>&gt;</span>What is the CSS Box Model?<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-answer"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>It's a concept that includes margins, borders, padding, and the actual content area, helping you control spacing and layout around elements.<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>&gt;</span>
      <span class="hljs-comment">&lt;!-- FAQ Item 4 --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-item"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"faq4"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-toggle"</span> <span class="hljs-attr">hidden</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"faq4"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-question"</span>&gt;</span>How does z-index work?<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-answer"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>z-index decides which elements appear on top of others on the page. Higher values are closer to the front, useful for overlays or dropdown menus.<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>&gt;</span>
      <span class="hljs-comment">&lt;!-- FAQ Item 5 --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-item"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"faq5"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-toggle"</span> <span class="hljs-attr">hidden</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"faq5"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-question"</span>&gt;</span>Why use CSS variables?<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"faq-answer"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>They make it easy to update values like colors or fonts across your site by changing them in one place, keeping your styles consistent and easier to manage.<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>&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">section</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<p>Here's the CSS code:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#00ad8f</span>;
}

<span class="hljs-selector-class">.faq-section</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">5em</span>; 
}

<span class="hljs-selector-class">.faq-section</span> <span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2.5em</span>; 
}

<span class="hljs-selector-class">.faq-heading</span> {
  <span class="hljs-attribute">text-align</span>: center; 
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">2em</span>; 
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}

<span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">800px</span>;
  <span class="hljs-attribute">margin</span>: auto;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1em</span>;
}

<span class="hljs-selector-class">.faq-item</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.3em</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#333</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">0.5em</span>;
}

<span class="hljs-selector-class">.faq-toggle</span> {
  <span class="hljs-attribute">display</span>: none; <span class="hljs-comment">/* Hide checkbox */</span>
}

<span class="hljs-selector-class">.faq-question</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#efefef</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1em</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">position</span>: relative; <span class="hljs-comment">/* Necessary for positioning ::before content */</span>
}

<span class="hljs-selector-class">.faq-answer</span> {
  <span class="hljs-attribute">max-height</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">overflow</span>: hidden;
  <span class="hljs-attribute">border-top</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#333</span>;
  <span class="hljs-attribute">transition</span>: transform <span class="hljs-number">0.3s</span> ease, padding <span class="hljs-number">0.3s</span> ease;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span> <span class="hljs-number">1em</span>;
}

<span class="hljs-selector-class">.faq-toggle</span><span class="hljs-selector-pseudo">:checked</span> + <span class="hljs-selector-class">.faq-question</span><span class="hljs-selector-pseudo">::after</span> {
  <span class="hljs-attribute">content</span>: <span class="hljs-string">'-'</span>; <span class="hljs-comment">/* Changes the plus to a minus on the FAQ question when the toggle is checked */</span>
}

<span class="hljs-selector-class">.faq-toggle</span><span class="hljs-selector-pseudo">:checked</span> + <span class="hljs-selector-class">.faq-question</span> + <span class="hljs-selector-class">.faq-answer</span> {
  <span class="hljs-attribute">max-height</span>: <span class="hljs-number">1000px</span>; <span class="hljs-comment">/* Reveals the answer when the toggle is checked */</span>
}

 <span class="hljs-comment">/* nth-of-type for styling odd and even .faq-question differently */</span>
<span class="hljs-selector-class">.faq-item</span><span class="hljs-selector-pseudo">:nth-of-type(odd)</span> <span class="hljs-selector-class">.faq-question</span>{
 <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>; <span class="hljs-comment">/* For odd items */</span>
} 

<span class="hljs-selector-class">.faq-item</span><span class="hljs-selector-pseudo">:nth-of-type(even)</span> <span class="hljs-selector-class">.faq-question</span>{
 <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#caffee</span>; <span class="hljs-comment">/* For even items */</span>
}

<span class="hljs-selector-class">.faq-item</span><span class="hljs-selector-pseudo">:nth-of-type(odd)</span> <span class="hljs-selector-class">.faq-question</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#dfdfdf</span>; <span class="hljs-comment">/* Lightens the question's background on hover for visual feedback */</span> 
}

<span class="hljs-selector-class">.faq-item</span><span class="hljs-selector-pseudo">:nth-of-type(even)</span> <span class="hljs-selector-class">.faq-question</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#9debd2</span>; <span class="hljs-comment">/* Lightens the question's background on hover for visual feedback */</span> 
}

<span class="hljs-comment">/* First-of-type and last-of-type to style the first and last item uniquely */</span>
<span class="hljs-selector-class">.faq-item</span><span class="hljs-selector-pseudo">:first-of-type</span> <span class="hljs-selector-class">.faq-question</span> {
  <span class="hljs-attribute">border-top</span>: <span class="hljs-number">2px</span> solid <span class="hljs-number">#007BFF</span>;
}

<span class="hljs-selector-class">.faq-item</span><span class="hljs-selector-pseudo">:last-of-type</span> <span class="hljs-selector-class">.faq-question</span> {
  <span class="hljs-attribute">border-bottom</span>: <span class="hljs-number">2px</span> solid <span class="hljs-number">#007BFF</span>;
}

<span class="hljs-comment">/* ::after used to display "+" symbol */</span>
<span class="hljs-selector-class">.faq-question</span><span class="hljs-selector-pseudo">::after</span> {
  <span class="hljs-attribute">content</span>: <span class="hljs-string">'+'</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#00ad8f</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.4em</span>;
}

<span class="hljs-selector-class">.faq-item</span><span class="hljs-selector-attr">[data-category^=<span class="hljs-string">"important"</span>]</span> <span class="hljs-selector-class">.faq-question</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#E91E63</span>; <span class="hljs-comment">/* Styles important questions differently */</span>
}
</code></pre>
<h1 id="heading-conclusion">Conclusion</h1>
<p>We've just taken a dive into the world of advanced CSS selectors by building an interactive FAQ section. These advanced selectors allow you to write less code while doing more, keeping your HTML clean and your styles sharp. </p>
<p>As we wrap up, I hope the next time you're faced with a decision on how to approach styling a complex layout or interactive element, you'll remember the power and flexibility that these advanced CSS selectors offer and choose to try them out.</p>
<ul>
<li><a target="_blank" href="https://web.dev/learn/css/selectors">Google Web Dev on CSS Selectors</a></li>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_selectors">MDN Web Docs on CSS Selectors</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Chrome DevTools – Simple Strategies for Smarter Web Development ]]>
                </title>
                <description>
                    <![CDATA[ As a web developer, there are many tools out there – in addition to your code editor – that can make you more efficient.  It doesn't matter if you're just starting out or have been coding for years. Knowing how to effectively use Developer Tools (Dev... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/chrome-devtools/</link>
                <guid isPermaLink="false">66c5a334215f782a032b1cb7</guid>
                
                    <category>
                        <![CDATA[ Google Chrome ]]>
                    </category>
                
                    <category>
                        <![CDATA[ clean code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ debugging ]]>
                    </category>
                
                    <category>
                        <![CDATA[ devtools ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Problem Solving ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Thu, 15 Feb 2024 16:12:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/ChromeDevTools-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As a web developer, there are many tools out there – in addition to your code editor – that can make you more efficient. </p>
<p>It doesn't matter if you're just starting out or have been coding for years. Knowing how to effectively use Developer Tools (DevTools for short) can significantly boost your development process. You can edit pages on the fly, quickly spot issues, and deeply understand your site's performance. </p>
<p>All major browsers have their own DevTools that let you examine the code of a webpage, evaluate its metrics, and run some tests alongside. This article will discuss Chrome's DevTools, as it's the industry standard.</p>
<h2 id="heading-table-of-contents">Table of contents:</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-chrome-devtools">What is Chrome DevTools?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-open-chrome-devtools">How to Open Chrome DevTools</a></li>
<li><a class="post-section-overview" href="#heading-keyboard-shortcuts-for-easy-navigation">Keyboard shortcuts for Easy Navigation</a></li>
<li><a class="post-section-overview" href="#heading-key-chrome-devtools-features">Key Chrome DevTools Features</a></li>
<li><a class="post-section-overview" href="#heading-practical-devtools-use-cases">Practical DevTools Use Cases</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h1 id="heading-what-is-chrome-devtools">What is Chrome DevTools?</h1>
<p>Chrome DevTools is a set of tools that are essential for diagnosing and solving web development challenges, directly within the Google Chrome browser. </p>
<p>It gives you direct access to a website's inner workings - to inspect HTML and CSS, debug JavaScript, analyze performance, and see the immediate impact of your code, all in realtime. </p>
<p>This direct access to a website's inner workings is crucial for diagnosing issues quickly and efficiently, ensuring your web applications are both performant and bug-free.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/DevToolsScreenshots-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>A grid of elements, console, performance and network panels screenshots</em></p>
<h1 id="heading-how-to-open-chrome-devtools">How to Open Chrome DevTools</h1>
<p>To open DevTools in your Chrome browser, you can either:</p>
<ol>
<li>Right-click on any webpage and select inspect from the list of options.</li>
<li>Use the shortcut (command + option + I on Mac or control + shift + I on Windows). </li>
<li>Click the three dot icon next to your profile picture on your Chrome browser, choose 'More Tools' and 'Developer Tools' from the second option box.</li>
</ol>
<p>It usually opens in a split screen interface, either below your current webpage or beside it. Once open, its features line up as tabs at the top of the DevTools window. These tabs include: Elements, Console, Source, Network, Application, Security, Memory, Performance, Audits.</p>
<h2 id="heading-keyboard-shortcuts-for-easy-navigation">Keyboard Shortcuts for Easy Navigation</h2>
<ol>
<li>Use Cmd or Ctrl + Shift + C to open the Elements panel</li>
<li>Use Cmd or Ctrl + Shift + J to open the Console panel</li>
<li>Use Cmd or Ctrl + ] to move forward to the next panel </li>
<li>Use Cmd or Ctrl + [ to move back to the previous panel </li>
</ol>
<h1 id="heading-key-chrome-devtools-features">Key Chrome DevTools Features</h1>
<p>DevTools is packed with features essential for web developers to streamline various aspects of their workflow. Let's look at a few of them in some detail now.</p>
<h2 id="heading-elements-panel">Elements Panel</h2>
<p>This panel is used for inspecting and modifying the HTML and CSS of a webpage in real-time, which is great for debugging layout issues or experimenting with new styles before applying them in your actual code. You also get to see how the DOM (Document Object Model) is structured. </p>
<p>Imagine fine-tuning your website's footer appearance (background color, font size) directly in your browser and seeing the results instantly. </p>
<p>With DevTools open, click on the Elements tab to access it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/elpanel-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>A screenshot of Chrome DevTools' Elements panel</em></p>
<h2 id="heading-console-panel">Console Panel</h2>
<p>This panel serves as your interactive playground for JavaScript within the browser. Whether you're tracking down an elusive bug with a quick <code>console.log()</code> or experimenting with DOM elements, in the Console panel you can test snippets of JavaScript and view any logs or errors in the currently loaded webpage. </p>
<p>To use it, simply open DevTools and select the "Console" tab or use the shortcut (option + command + J on Mac or contrl + shift + J on Windows).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/clpanel-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>A screenshot of Chrome DevTools' Console panel</em></p>
<h2 id="heading-network-panel">Network Panel</h2>
<p>This panel gives you an overview of all network activity on your webpage – from tracking every resource that is loaded to how your site communicates with servers. </p>
<p>If you've wondered why your website takes forever to load or why some API requests seem to vanish into thin air, the Network panel is your go-to as it provides insights into the success or failure of API calls. </p>
<p>To access it, open DevTools and navigate to the "Network" tab.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/netpanel-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>A screenshot of Chrome DevTools' Network panel</em></p>
<h2 id="heading-performance-panel">Performance Panel</h2>
<p>This panel is used for capturing and analyzing a website's performance metrics. It shows all the activities happening when interacting with a page. </p>
<p>When your web app starts to crawl under heavy usage, the Performance panel can pinpoint where the performance bottlenecks lie so that you can resolve these issues, ensuring your app runs smoothly. </p>
<p>With DevTools open, click on the "Performance" tab to use it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/perfpanel-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>A screenshot of Chrome DevTools' Performance panel</em></p>
<p>The above are only a handful of the panels available, but they're by far the most popular and must-knows. Using them properly will make your development processes more intuitive and rewarding.</p>
<h1 id="heading-practical-devtools-use-cases">Practical DevTools Use Cases</h1>
<p>In the following interactive examples, I intentionally created the mini project in Codepen <strong>with issues</strong> to simulate real-world debugging scenarios using Chrome DevTools. </p>
<p>I figured it'd be a great way to highlight the practical uses of certain DevTools panels and features in identifying bugs and troubleshooting right in the browser. </p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li>Chrome browser (<a target="_blank" href="https://support.google.com/chrome/answer/95346?hl=en&amp;co=GENIE.Platform%3DDesktop">Click this link to download</a>)</li>
<li>A basic understanding of HTML, CSS, and JavaScript</li>
<li><a target="_blank" href="https://codepen.io/ophyboamah/full/rNpZZwo">Codepen</a></li>
</ul>
<p></p><p>
  <span>See the Pen <a href="https://codepen.io/ophyboamah/pen/rNpZZwo">
  Modal Window</a> by Ophy Boamah (<a href="https://codepen.io/ophyboamah">@ophyboamah</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p><p></p>


<h2 id="heading-how-to-debug-html-and-css-with-the-elements-panel">How to Debug HTML and CSS with the Elements Panel</h2>
<p>Our mini project contains a modal that, upon clicking, should display a modal window with some important information. But there's a bug preventing this from happening. </p>
<p>This situation sets the stage for a practical demonstration of how you can use the Elements Panel to troubleshoot and resolve styling and structural issues.</p>
<pre><code>&lt;body&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"show-modal"</span>&gt;</span>Click me to learn a secret 🤫<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>

  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal hidden"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"close-modal"</span>&gt;</span><span class="hljs-symbol">&amp;times;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hey Ophy here 👋🏾<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
      I lead Women Who Code Frontend, a global remote community of 3,000+ women frontend devs and enthusiasts. Find us on beacons.ai/wwcodefrontend
    <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>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"overlay hidden"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>

  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"script.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
&lt;/body&gt;
</code></pre><pre><code class="lang-css"><span class="hljs-selector-class">.hidden</span> {
  <span class="hljs-attribute">display</span>: none;
}

<span class="hljs-selector-class">.modal</span> {
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>);
  <span class="hljs-attribute">width</span>: <span class="hljs-number">70%</span>;

  <span class="hljs-attribute">background-color</span>: white;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">6rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">3rem</span> <span class="hljs-number">5rem</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.3</span>);
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">10</span>;
}
</code></pre>
<p>In our modal's HTML code above, we've added the class name 'modal hidden' which has a corresponding styling with the CSS property of <code>display:none</code> that is set to hide the modal when the page is loaded initially and only display it when the button is clicked.</p>
<h3 id="heading-step-1-initial-inspection">✅ Step 1 - Initial inspection:</h3>
<p>Attempt to trigger the modal by clicking on the 'Click me to learn a secret' button. Since we've set that up not to work, right-click on the area where the modal should appear and choose "Inspect" to open DevTools' Elements Panel.</p>
<h3 id="heading-step-2-diagnose-visibility-issues">✅ Step 2 - Diagnose visibility issues:</h3>
<p>In the Elements Panel, locate the modal in the DOM to see that the modal is present but not visible. This confirms that the bug is caused within our CSS code <code>display: hidden</code>. </p>
<p>As soon as you click on the modal in the DOM, any corresponding CSS classes will be pulled up within Styles at the bottom section of the Elements panel. You can toggle some properties on and off or type others to see the effects in real-time.</p>
<p>Manually change the class name from <code>modal hidden</code> to <code>modal block</code> to trigger the right properties that'll cause the modal to show.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/modalblock.png" alt="Image" width="600" height="400" loading="lazy">
<em>A screenshot of debugging the modal's HTML, CSS in Elements panel</em></p>
<h3 id="heading-step-3-center-the-modal">✅ Step 3 - Center the modal:</h3>
<p>Now the modal is visible, but it's displayed at the top – which is different from where we'd like it to be (that is, in the center of the page).</p>
<p>To change this, modify the <code>transform</code> property to <code>translate(-50%, -50%)</code> by adding the second <code>-50%</code> and ensure that <code>top: 50%</code>, and <code>left: 50%</code> are correctly set to center the modal on the screen.</p>
<h3 id="heading-step-4-enhance-the-appearance">✅ Step 4 - Enhance the appearance:</h3>
<p>You can go further to refine the modal's appearance by tweaking its <code>background-color</code>, <code>padding</code>, or other stylistic properties directly within the Styles to achieve the desired look and feel.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/ChromeDevTools.gif" alt="Image" width="600" height="400" loading="lazy">
<em>A GIF fixing the modal in Chrome DevTools' Elements panel</em></p>
<h2 id="heading-debug-javascript-with-the-sources-panel">Debug JavaScript with the Sources Panel</h2>
<p>I added a bug in the JavaScript code of our modal mini project to prevent it from opening when the button is clicked. </p>
<p>In the real world, this would cause neither the open nor close commands to trigger any action, which would leave users unable to interact with the content and frustrated as a result. Let's troubleshoot and debug this issue in the Sources Panel.</p>
<p>In the code below, the openModal function is set to remove the indicated classes. However, this doesn't work because we deliberately misspelled <code>hidden</code>. </p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Introducing a bug: Incorrectly spelling 'hidden' as 'hiddn'</span>
<span class="hljs-keyword">const</span> openModal = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  modal.classList.remove(<span class="hljs-string">"hiddn"</span>); <span class="hljs-comment">// Intentional bug</span>
  overlay.classList.remove(<span class="hljs-string">"hidden"</span>);

  <span class="hljs-comment">// Fetch data from a real API and display in the modal</span>
};
</code></pre>
<h3 id="heading-step-1-set-up-breakpoints">✅ Step 1 - Set up breakpoints:</h3>
<p>Open Chrome DevTools and navigate to the Sources Panel. Here, find the JavaScript file that includes the modal functionality (in our example its pen.js). </p>
<p>The openModal function contains the logic for displaying the modal on the screen. This function will include a line where the modal element's class is manipulated to remove a "hidden" class. </p>
<p>Click on the number next to this code line in DevTools. A blue (or sometimes red, depending on the theme) icon appears next to the line number, indicating that a breakpoint has been set. This breakpoint will pause the execution of our JavaScript code as soon as it reaches this line.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/soscreenshot.png" alt="Image" width="600" height="400" loading="lazy">
<em>A screenshot of setting breakpoints the modal's JS in Sources panel</em></p>
<p>Breakpoints pause code execution at critical points, allowing you to inspect the current state of variables and understand the flow of execution. This step is crucial for identifying where the code deviates from expected behaviour.</p>
<h3 id="heading-step-2-examine-the-code-execution-flow">✅ Step 2 - Examine the code execution flow:</h3>
<p>With our breakpoint in place, try to open the modal by clicking on its button. Execution of our JavaScript code now pauses at our breakpoint, which enables us to step through the code line by line. </p>
<p>This is an opportunity to observe variables, function calls, look for anomalies such as misnamed functions, incorrect logic, or uncaught exceptions that could explain why the modal isn't working. </p>
<p>In our case it's because we intentionally misspelled the class name <code>hidden</code> as <code>hiddn</code>. Fix that in the code to get the modal working again.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/ChromeDevTools--2-.gif" alt="Image" width="600" height="400" loading="lazy">
<em>A GIF troubleshooting the modal bug in Chrome DevTools' Elements panel</em></p>
<h2 id="heading-optimize-performance-with-the-network-panel">Optimize Performance with the Network Panel</h2>
<p>Here I've added a fetch function that makes an API call to a live endpoint (<a target="_blank" href="https://jsonplaceholder.typicode.com/posts/1"><code>https://jsonplaceholder.typicode.com/posts/1</code></a>). This is an excellent opportunity to explore the Network Panel's capabilities in diagnosing and understanding network-related problems.</p>
<p>From the code below, you can see that the openModal function doesn't only open the modal but also makes an API call to the <code>jsonplaceholder</code> endpoint to fetch some data. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> openModal = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts/1'</span>)
    .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
    .then(<span class="hljs-function"><span class="hljs-params">json</span> =&gt;</span> <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'modal-content'</span>).innerText = json.title)
    .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error loading the content:'</span>, error));
};
</code></pre>
<h3 id="heading-step-1-initiate-the-api-call">✅ Step 1 - Initiate the API call:</h3>
<p> On the modal project UI, click on the 'Click me to learn a secret' button. Though the modal does not visibly activate, because of the fetch logic within the openModal function, an API call will be made.</p>
<h3 id="heading-step-2-network-panel-inspection">✅ Step 2 - Network Panel Inspection:</h3>
<p>Ideally, your Network Panel should be open before clicking the button, but you can also reverse the steps. Detailed insights on your API request such as the request's method, status code, response and the time it took to complete, will be available under headers, preview, response, initiator and timing tabs respectively. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/netscreenshot.png" alt="Image" width="600" height="400" loading="lazy">
<em>A screenshot overview of API request in Network panel</em></p>
<h3 id="heading-step-3-simulating-network-conditions">✅ Step 3 - Simulating Network Conditions:</h3>
<p>Use the Network Panel's throttling feature to mimic various network speeds like offline or slow 3G to see how the API request behaves under constrained conditions. </p>
<p>From this you can compare how different network speeds can affect application performance. This will teach you the importance of optimizing data loading strategies to enhance user experience, especially on slower connections.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/ChromeDevTools--1-.gif" alt="Image" width="600" height="400" loading="lazy">
<em>A GIF observing API requests and responses in Chrome DevTools' Network panel</em></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Bringing Chrome DevTools into your web development routine is not just about fixing bugs. It's about streamlining your workflow, making your sites more accessible, and boosting their performance. </p>
<p>Through our modal window mini-project, we've seen firsthand how DevTools can address a wide array of development challenges, but that’s merely scratching the surface of what it can do. </p>
<p>As you continue to explore its capabilities and familiarize yourself with its features, you'll find it's an invaluable companion on your web development journey – designed to make your development process not just faster, but also more rewarding.</p>
<ul>
<li><a target="_blank" href="https://developer.chrome.com/docs/devtools">The Official Chrome DevTools documentation</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/learn-how-to-use-the-chrome-devtools-to-troubleshoot-websites/">How to use the Chrome DevTools to troubleshoot websites</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Optimize Your CSS Code for Faster Web Pages ]]>
                </title>
                <description>
                    <![CDATA[ CSS is more than just a tool for styling. It also determines how web pages render in a browser. Well-optimized CSS means faster loading times and a smoother user experience. In today's digital landscape, the performance of a website is a key factor i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-optimize-your-css-code-for-faster-web-pages/</link>
                <guid isPermaLink="false">66c5a33d5e24e23ff2251593</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Fri, 26 Jan 2024 13:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/csstitle.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>CSS is more than just a tool for styling. It also determines how web pages render in a browser. Well-optimized CSS means faster loading times and a smoother user experience.</p>
<p>In today's digital landscape, the performance of a website is a key factor in its success. Writing efficient CSS code can greatly influence how quickly your web pages load, impacting everything from user experience to search engine rankings. </p>
<p>This guide delves into effective strategies to help you refine your CSS, ensuring that your website not only looks great but also loads swiftly and runs smoothly.</p>
<h2 id="heading-how-css-affects-web-performance">How CSS affects Web Performance</h2>
<p>When a user visits a webpage, the browser retrieves the site's structural HTML and its stylistic CSS. This is a set of detailed instructions on how each part of the webpage should look. </p>
<p>If the CSS is packed with too much information or is too complex, it's like giving the browser a puzzle that takes longer to solve. This can lead to longer waiting times for users, which can be annoying.</p>
<p>That's where the art of streamlining CSS comes into play. It's not just about tidying up the code, but also making sure the browser can get the webpage ready faster. </p>
<p>When CSS is made leaner and simpler, it's like giving the browser a clear, easy-to-follow map. This makes webpages load faster, making everything feel more responsive. </p>
<h2 id="heading-1-write-shorter-css">1. Write Shorter CSS</h2>
<p>When writing CSS, use the popular software development principle Don’t Repeat Yourself (DRY). This advocates for conciseness and clarity in your code. </p>
<p>This is important here, because in practice, CSS involves repeating properties across various selectors. The goal should be to identify and consolidate these repetitive properties. By doing so you eliminate redundancies, leading to cleaner and more manageable CSS.</p>
<p>For instance, in the code below, multiple elements (<code>h1</code>and <code>h2</code>) share the same font-size and color. </p>
<pre><code class="lang-css"><span class="hljs-selector-tag">h1</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}
<span class="hljs-selector-tag">h2</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}
</code></pre>
<p>So instead of declaring these properties separately for each selector, you can group them under a common class. This not only streamlines your stylesheet but also makes future updates easier and less error-prone.</p>
<p>You can rewrite the above code to look like this:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">h1</span>, <span class="hljs-selector-tag">h2</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}
</code></pre>
<p>Using shorthand properties is another effective strategy for minimizing the size of your CSS, making your code more efficient. It also allows you to set multiple related CSS properties with a single declaration. Here's how you can write effective shorthand CSS:</p>
<p>When all sides of an element have the same value, use that one value.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Before shorthand */</span>
<span class="hljs-selector-class">.same-sides</span> {
    <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">15px</span>;
    <span class="hljs-attribute">padding-right</span>: <span class="hljs-number">15px</span>;
    <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">15px</span>;
    <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">15px</span>;
}

<span class="hljs-comment">/* After shorthand */</span>
<span class="hljs-selector-class">.same-sides</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">15px</span>;
}
</code></pre>
<p>When all sides of an element have different values, use all four.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Before shorthand */</span>
<span class="hljs-selector-class">.different-sides</span> {
    <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">padding-right</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">15px</span>;
    <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">25px</span>;
}

<span class="hljs-comment">/* After shorthand */</span>
<span class="hljs-selector-class">.different-sides</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">20px</span> <span class="hljs-number">15px</span> <span class="hljs-number">25px</span>;
}
</code></pre>
<p>When top/bottom and right/left have the same value, use two values.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Before shorthand */</span>
<span class="hljs-selector-class">.two-sides</span> {
    <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">padding-right</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-comment">/* After shorthand */</span>
<span class="hljs-selector-class">.two-sides</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">20px</span>;
}
</code></pre>
<p>When only the right/left values are the same but the top and bottom aren't, use three values.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Before shorthand */</span>
<span class="hljs-selector-class">.three-sides</span> {
    <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">padding-right</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">15px</span>;
    <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-comment">/* After shorthand */</span>
<span class="hljs-selector-class">.three-sides</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">20px</span> <span class="hljs-number">15px</span>;
}
</code></pre>
<h2 id="heading-2-use-shallow-css-selectors">2. Use Shallow CSS Selectors</h2>
<p>Shallow CSS selectors are direct and concise selectors with fewer levels of nested elements that don't dig too deep into the HTML structure. </p>
<p>Simplifying your selectors can significantly speed up your webpage rendering because deeply nested selectors take longer for browsers to evaluate, which results in a slower page render.</p>
<p>Consider the example in the code below: to assign property values to a deeply nested selector like <code>header nav ul li a</code> is cumbersome and will cause rendering delays because the browser needs time to check each level (header, then nav, then ul, and so on) to find the right <strong><code>&lt;a&gt;</code></strong> tag to style). </p>
<p>Alternatively, giving it a direct class <code>.nav-link</code> is straightforward and quicker for browsers to interpret. Class selectors are generally more efficient than nested tags because the browser simply looks for elements with a class and applies the styles, without worrying about their position in the DOM tree.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Less efficient: Deeply nested selector */</span>
<span class="hljs-selector-tag">header</span> <span class="hljs-selector-tag">nav</span> <span class="hljs-selector-tag">ul</span> <span class="hljs-selector-tag">li</span> <span class="hljs-selector-tag">a</span> { 
   <span class="hljs-attribute">color</span>: <span class="hljs-number">#000</span>;
   <span class="hljs-attribute">font-size</span>: <span class="hljs-number">10px</span>;
 }

<span class="hljs-comment">/* More efficient: Class selector */</span>
<span class="hljs-selector-class">.nav-link</span> {
   <span class="hljs-attribute">color</span>: <span class="hljs-number">#000</span>;
   <span class="hljs-attribute">font-size</span>: <span class="hljs-number">10px</span>;
}
</code></pre>
<h2 id="heading-3-segment-css-code">3. Segment CSS Code</h2>
<p>Segmenting your CSS code into smaller, more focused segments like separate files for different website components and creating page-specific styles can greatly improve your website's performance. This approach not only makes it easier to find and edit specific styles but also ensures that webpages load only the CSS they need, avoiding unnecessary bulk.</p>
<p>Enhanced maintainability and faster page loading are the most obvious key benefits. Smaller CSS files are easier to manage, much like a well-organized toolbox where everything is easy to find. But also, by loading only the essential CSS for each page, the browser has less work to do hence improving the user experience.</p>
<h3 id="heading-original-css">Original CSS</h3>
<p>Suppose you have a CSS file that contains styles for various parts of your website:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Styles for the home page */</span>
<span class="hljs-selector-class">.homepage</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f0f0f0</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
}

<span class="hljs-comment">/* Styles for the services page */</span>
<span class="hljs-selector-class">.services</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#333</span>;
    <span class="hljs-attribute">color</span>: white;
}

<span class="hljs-comment">/* Styles for the contact page */</span>
<span class="hljs-selector-class">.contact</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#222</span>;
    <span class="hljs-attribute">color</span>: white;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
}
</code></pre>
<h3 id="heading-segmented-css">Segmented CSS</h3>
<p>Now, let's segment this CSS into different files based on their purpose:</p>
<ol>
<li><strong>Home page Styles (homepage.css):</strong></li>
</ol>
<pre><code class="lang-css"><span class="hljs-selector-class">.homepage</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f0f0f0</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
}
</code></pre>
<ol start="2">
<li><strong>Services page Styles (services.css):</strong></li>
</ol>
<pre><code class="lang-css"><span class="hljs-selector-class">.services</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#333</span>;
    <span class="hljs-attribute">color</span>: white;
}
</code></pre>
<ol start="3">
<li><strong>Contact page Styles (contact.css):</strong></li>
</ol>
<pre><code class="lang-css"><span class="hljs-selector-class">.contact</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#222</span>;
    <span class="hljs-attribute">color</span>: white;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
}
</code></pre>
<p>Each CSS file is focused on a specific part of the website. Now, when a user visits your website, each page loads only the CSS it requires hence enhancing the website's performance.</p>
<h2 id="heading-4-optimize-css-delivery">4. Optimize CSS Delivery</h2>
<p>You can make your CSS files lighter and faster to load by shrinking your CSS – that is, you can remove extra spaces and lines (this is called minifying). Then you can compress these files so they're smaller and quicker for users to download. </p>
<p>Also, make sure the most important styles of your website load first, so people see your page faster. The other styles can load in the background without slowing things down.</p>
<p>You can also make your website faster for people who visit more than once, by saving some of your CSS in their browser (this is known as caching). This means it doesn’t have to load again every time they visit. </p>
<p>Also, if you use a CDN or a network of servers, your CSS files can be stored in many places around the world to load faster no matter where your users are. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/minifycss.png" alt="Image" width="600" height="400" loading="lazy">
<em>Graphic comparing file size between an unminified CSS file at 167KB and a minified CSS file at 92KB</em></p>
<h3 id="heading-original-css-1">Original CSS</h3>
<pre><code class="lang-css"><span class="hljs-comment">/* Main Stylesheet */</span>
<span class="hljs-comment">/* Header Style */</span>
<span class="hljs-selector-tag">header</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#333</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
}

<span class="hljs-comment">/* Navigation Style */</span>
<span class="hljs-selector-tag">nav</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#444</span>;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">10px</span>;
}
</code></pre>
<p>The above CSS code is readable and well-commented, but it contains extra spaces and comments that increase the file size.</p>
<h3 id="heading-minified-css">Minified CSS</h3>
<pre><code class="lang-css"><span class="hljs-selector-tag">header</span>{<span class="hljs-attribute">background-color</span>:<span class="hljs-number">#333</span>;<span class="hljs-attribute">color</span>:white;<span class="hljs-attribute">padding</span>:<span class="hljs-number">10px</span>}<span class="hljs-selector-tag">nav</span>{<span class="hljs-attribute">background-color</span>:<span class="hljs-number">#444</span>;<span class="hljs-attribute">margin-top</span>:<span class="hljs-number">10px</span>;}
</code></pre>
<p>The minified version combines all the rules into a single line, removing unnecessary spaces and comments, which reduces the file size for quicker loading.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Optimizing your CSS speeds up your website and consequently improves the overall user experience. </p>
<p>By implementing the practices outlined in this article, you can achieve more performant, efficient and maintainable CSS. The performance savings may not be significant from tweaking a few lines but over hundreds more across different stylesheets, the impact will begin to show. </p>
<p>Remember, web performance is an ongoing process. Regularly review and refine your CSS to keep up with best practices and emerging trends.</p>
<h3 id="heading-additional-resources">Additional Resources</h3>
<ul>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS">MDN Web Docs on CSS</a></li>
<li><a target="_blank" href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency">Google Web Fundamentals</a></li>
<li><a target="_blank" href="https://www.oreilly.com/library/view/web-performance-in/9781617293771/">Web Performance In Action</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What are Progressive Web Apps? PWA Guide for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ Progressive Web Apps (PWAs) are simply installable web applications – websites that you can install on your device, much like you would install an app from an app store.  They bring together the best parts of using a website (easy to access, no need ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-are-progressive-web-apps-pwa-guide/</link>
                <guid isPermaLink="false">66c5a34c3d77fae9eb82a477</guid>
                
                    <category>
                        <![CDATA[ progressive web app ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PWA ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Thu, 18 Jan 2024 15:56:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/Essentials.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Progressive Web Apps (PWAs) are simply installable web applications – websites that you can install on your device, much like you would install an app from an app store. </p>
<p>They bring together the best parts of using a website (easy to access, no need to install anything) with the great features of mobile apps (fast, can work offline), offering a high-quality user experience. </p>
<p>The core of a PWA's usefulness lies in the offline-first approach, where applications are designed to function seamlessly without a constant internet connection. This means you can still use these apps even when your internet is slow or not available, and makes PWAs very user-friendly and accessible, even where an internet connection is not always reliable.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/pwaa.png" alt="Image" width="600" height="400" loading="lazy">
<em>Graphic showing a native app vs a web application vs a PWA</em></p>
<h2 id="heading-5-reasons-to-use-a-pwa-instead-of-a-native-app">5 Reasons to Use a PWA Instead of a Native app</h2>
<p>Progressive Web Apps (PWAs) are reshaping the landscape of digital interaction. They offer a hybrid experience that combines the best features of web and mobile apps. </p>
<p>Let's delve deeper into why PWAs are often a superior choice compared to native apps:</p>
<h3 id="heading-1-speed-and-ease-of-installation">1. Speed and Ease of Installation</h3>
<p>PWAs eliminate the lengthy download and installation process typical of native apps. You can access a PWA as swiftly as you'd load a web page, making it as straightforward as bookmarking your favorite site – no waiting for downloads or navigating through app stores. </p>
<p>Consider Twitter Lite, a PWA version of the popular social media platform, which offers the full Twitter experience without the need to wait for a separate app download. </p>
<h3 id="heading-2-minimal-storage-requirements">2. Minimal Storage Requirements</h3>
<p>One of the most significant advantages of PWAs is their minimal storage requirements. Since they primarily store data online, much like cloud services, they occupy significantly less space on a user’s device. </p>
<p>This feature is particularly beneficial for users with limited device storage or expensive data plans. For example, Pinterest’s PWA takes up less space than its native counterpart but still provides a rich, engaging user experience. </p>
<h3 id="heading-3-reliable-offline-performance">3. Reliable Offline Performance</h3>
<p>A PWA's ability to function offline is like having a good book downloaded to your e-reader, ready to enjoy even when you're out of range of a good signal. </p>
<p>PWAs can function effectively even in areas with poor or no internet connectivity, using cached data from previous online activities. This ensures that users have uninterrupted access to essential features. </p>
<p>A notable example is the Starbucks PWA, which allows customers to browse the menu and customize orders, regardless of their internet connection for a consistent user experience.</p>
<h3 id="heading-4-cost-effective-development-and-cross-device-compatibility">4. Cost-Effective Development and Cross-Device Compatibility</h3>
<p>Developing a PWA can be more cost-effective than building native apps for various platforms. This unified approach not only saves significant development time and resources but also simplifies maintenance and updates. </p>
<p>Businesses like Uber have leveraged PWAs to provide a seamless user experience across all devices without the need for multiple native apps. </p>
<h3 id="heading-5-automatic-updates-and-push-notifications">5. Automatic Updates and Push Notifications</h3>
<p>PWAs update themselves seamlessly, much like a web page loading the latest content each time it’s visited. Users always have access to the most current version of the app without going through the process of manual updates. This feature ensures that users are not hindered by outdated versions, a common issue with native apps. </p>
<p>For instance, Google Maps’ PWA automatically incorporates the latest features and improvements without user intervention. In addition to staying current, PWAs can engage users with push notifications, just like native apps, keeping them informed and involved without the need for a visit to the app store. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/pwass.png" alt="Image" width="600" height="400" loading="lazy">
<em>Infographic of a Progressive Web App (PWA) showcasing its features: adaptability across devices, security, offline functionality, fast performance, updates, and push notifications.</em></p>
<h2 id="heading-pwa-core-concepts">PWA Core Concepts</h2>
<p>To fully grasp the potential and functionality of Progressive Web Apps, it's essential to understand their foundational components. These core concepts not only define the structure and behavior of PWAs but also distinguish them from traditional web applications.</p>
<h3 id="heading-service-workers-the-backbone-of-pwas">Service Workers: The Backbone of PWAs</h3>
<p>Service workers are scripts that run in the background, separate from your web page. They act as a proxy between the web application and the network. </p>
<p>Think of service workers as behind-the-scenes helpers for your web app. Their main job is to manage how your app talks to the internet. </p>
<p>They can save important parts of your app on the user's device, which means your app can work even when there's no internet. They're also in charge of quietly updating app content and can send notifications, just like a native app on your phone.</p>
<h3 id="heading-the-app-manifest-your-pwas-identity">The App Manifest: Your PWA's Identity</h3>
<p>The web app manifest is a JSON file which is essential because it tells the user's device how your app should look and behave. </p>
<p>It's like your app's ID card – it includes the app's name, the icons it uses, the first page it should open, and how it should display (like in full screen). This file makes your web app feel more like a regular app, allowing users to 'install' it on their home screen.</p>
<h3 id="heading-caching-the-key-to-offline-functionality">Caching: The Key to Offline Functionality</h3>
<p>Effective caching is vital for a robust offline experience. Caching is like your app's memory. It stores important parts of your app so they can be quickly loaded later, even if there's no internet. It's crucial for making your app work offline. </p>
<p>There are different ways to handle caching, such as cache-first (where the app checks the cache before the internet), network-first (the opposite), and stale-while-revalidate (a mix of both). The choice depends on what your app does and what kind of information it handles, affecting how your app stores and retrieves its data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/pwa-components.png" alt="Image" width="600" height="400" loading="lazy">
<em>Icons representing key components of a PWA: Service worker, Manifest and HTTPS</em></p>
<h2 id="heading-overview-of-building-a-pwa">Overview of Building a PWA</h2>
<p>Building a Progressive Web App (PWA) might sound complex, but it's quite manageable when you break it down into steps. In this article, I'll give you an overview of the process – and in my next tutorial, I'll go into the process in more detail.</p>
<h3 id="heading-1-start-with-a-basic-webpage">1. Start with a Basic Webpage:</h3>
<p>Create a simple website using HTML for structure, CSS for style, and JavaScript for functionality.</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Ophy's To-Do List PWA<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Ophy's To-Do List<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"todo-input"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Add a new task..."</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"addTask()"</span>&gt;</span>Add<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"todo-list"</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- Tasks will go here --&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"app.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Arial'</span>, sans-serif;
}

<span class="hljs-selector-id">#todo-list</span> {
    <span class="hljs-attribute">list-style-type</span>: none;
}

<span class="hljs-selector-id">#todo-list</span> <span class="hljs-selector-tag">li</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">5px</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">5px</span>;
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f2f2f2</span>;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">3px</span>;
}
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addTask</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">var</span> input = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'todo-input'</span>);
    <span class="hljs-keyword">var</span> newTask = input.value;
    <span class="hljs-keyword">if</span> (newTask) {
        <span class="hljs-keyword">var</span> listItem = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'li'</span>);
        listItem.textContent = newTask;
        <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'todo-list'</span>).appendChild(listItem);
        input.value = <span class="hljs-string">''</span>; <span class="hljs-comment">// Clear the input</span>
    }
}
</code></pre>
<h3 id="heading-2-create-a-manifest-file">2. Create a Manifest File:</h3>
<p>In the manifest file, write down your app's name, the icons it uses, and the first page it should open. This makes your website act more like an app you can install.</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Ophy's To-Do List"</span>,
    <span class="hljs-attr">"short_name"</span>: <span class="hljs-string">"OphyToDo"</span>,
    <span class="hljs-attr">"icons"</span>: [
        {
            <span class="hljs-attr">"src"</span>: <span class="hljs-string">"favicon.ico"</span>,
            <span class="hljs-attr">"sizes"</span>: <span class="hljs-string">"64x64 32x32 24x24 16x16"</span>,
            <span class="hljs-attr">"type"</span>: <span class="hljs-string">"image/x-icon"</span>
        }
    ],
    <span class="hljs-attr">"start_url"</span>: <span class="hljs-string">"/"</span>,
    <span class="hljs-attr">"display"</span>: <span class="hljs-string">"standalone"</span>,
    <span class="hljs-attr">"theme_color"</span>: <span class="hljs-string">"#000000"</span>,
    <span class="hljs-attr">"background_color"</span>: <span class="hljs-string">"#ffffff"</span>
}
</code></pre>
<h3 id="heading-3-set-up-a-service-worker">3. Set Up a Service Worker:</h3>
<p>In your main JavaScript file, add a service worker. This is a special script that works separately from your website.</p>
<p>The service worker's job is to handle how your app stores and retrieves data, especially for offline use.</p>
<pre><code class="lang-javascript">self.addEventListener(<span class="hljs-string">'install'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">event</span>) </span>{
    <span class="hljs-comment">// Perform install steps</span>
    <span class="hljs-keyword">var</span> CACHE_NAME = <span class="hljs-string">'ophy-todo-cache-v1'</span>;
    <span class="hljs-keyword">var</span> urlsToCache = [
        <span class="hljs-string">'/'</span>,
        <span class="hljs-string">'/styles.css'</span>,
        <span class="hljs-string">'/app.js'</span>
    ];

    event.waitUntil(
        caches.open(CACHE_NAME)
            .then(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">cache</span>) </span>{
                <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Opened cache'</span>);
                <span class="hljs-keyword">return</span> cache.addAll(urlsToCache);
            })
    );
});
</code></pre>
<p>Following these steps will help you build a simple PWA that users can install and use, even when they're offline.</p>
<h2 id="heading-real-world-use-cases-for-pwas">Real World Use Cases for PWAs</h2>
<p>These real-world examples demonstrate the practical benefits and impact of offline-first strategies:</p>
<ol>
<li><strong>Starbucks</strong>: Starbucks has a PWA that lets customers look at the menu and order drinks and food even when they're offline. This not only makes the experience better for customers but also helps increase sales and customer interaction with the brand, as they can order anytime, anywhere.</li>
<li><strong>Khan academy</strong>: Khan Academy, a well-known educational site, has a PWA allowing students to download and access lessons and courses without an internet connection. This feature is particularly helpful for those in areas with unreliable internet, ensuring uninterrupted learning. Just like the Starbucks PWA, Khan Academy's use of this technology improves the user experience, making education more accessible and flexible.</li>
<li><strong>Trivago</strong>: Trivago, a popular hotel search engine, developed a PWA to enhance user experience, especially for travelers with unstable internet connections. The PWA allows users to browse hotel deals and information offline, making trip planning more flexible and accessible. This has led to increased user engagement and higher conversion rates, as travelers can continue interacting with the app even in areas with poor connectivity.</li>
<li><strong>Forbes</strong>: Forbes, a leading global media company, launched a PWA to improve the mobile experience for its readers. The PWA significantly reduced loading times and allowed offline reading of articles. This innovation not only enhanced user engagement but also resulted in a noticeable increase in readership and time spent on the site. The Forbes PWA demonstrates how media outlets can leverage offline-first strategies to reach and retain a wider audience, regardless of their internet connectivity.</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>PWAs are changing the game in web development, bringing features we usually see in native apps to the web. </p>
<p>They offer a blend of the accessibility of web applications with the engaging user experience of native apps. They represent a forward-thinking solution for businesses and developers looking to maximize reach and functionality while minimizing costs and complexity. </p>
<p>PWAs aren't just a passing trend – they're the next big thing in how we make and use web apps. By focusing on working offline, PWAs provide a more reliable and user-friendly experience. </p>
<p>Whether you're just curious or ready to start building, the following resources remain great places to begin exploring the possibilities of offline-first web applications.</p>
<ul>
<li><a target="_blank" href="https://developers.google.com/web/progressive-web-apps/checklist">Google's PWA Checklist</a></li>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">MDN Web Docs on Service Workers</a></li>
<li><a target="_blank" href="https://web.dev/progressive-web-apps/">Web.dev for PWA tutorials</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Web Accessibility – Best Practices and a Checklist for Developers ]]>
                </title>
                <description>
                    <![CDATA[ The World Health Organization reports that about 15% (1.2 billion) of the world's population lives with some form of disability.  This means that as developers, our focus on making websites and applications accessible helps more people use these reso... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/web-accessibility-best-practices-and-checklist/</link>
                <guid isPermaLink="false">66c5a346362cdd3f13c75135</guid>
                
                    <category>
                        <![CDATA[ a11y ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Wed, 30 Nov 2022 18:40:47 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/11/WebAccessibility.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The World Health Organization <a target="_blank" href="https://www.who.int/teams/noncommunicable-diseases/sensory-functions-disability-and-rehabilitation/world-report-on-disability">reports</a> that about <strong>15% (1.2 billion)</strong> of the world's population lives with some form of disability. </p>
<p>This means that as developers, our focus on making websites and applications accessible helps more people use these resources. </p>
<p>In this article, I'll point out barriers to web accessibility, discuss the Web Content Accessibility Guidelines (WCAG), and share a basic checklist that all developers can use when building their websites and applications.</p>
<blockquote>
<p>“<em>The power of the Web is in its universality. Access by everyone regardless of disability is an essential aspect</em>.” – Tim Berners-Lee, W3C Director and inventor of the World Wide Web.</p>
</blockquote>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/a11y.png" alt="Image" width="600" height="400" loading="lazy">
<em>Image credit: <a target="_blank" href="https://blog.interactiveschools.com/">Interactive Schools</a></em></p>
<h2 id="heading-what-is-web-accessibility">What is Web Accessibility?</h2>
<p>A person is said to be disabled when they’re faced with a condition – permanent or temporary – that makes it difficult or impossible for them to achieve a desired task. </p>
<p>In effect, web accessibility involves removing all barriers that prevent any users from accessing the web equally.</p>
<h2 id="heading-what-are-the-barriers-to-accessibility">What are the Barriers to Accessibility?</h2>
<p>The barriers to accessibility include <strong>visual, auditory, cognitive</strong> and <strong>motor</strong>. </p>
<p>Visual barriers constitute conditions which make it difficult for people to view images, videos, and gifs. These conditions can include low vision, colour blindness, or even total vision loss. </p>
<p>Auditory barriers constitute conditions which make it difficult or impossible for people to consume audio content. </p>
<p>Those who have difficulty concentrating, learning or remembering new things are faced with cognitive barriers. </p>
<p>And people who have partial or total loss of function in a body part and find it difficult to navigate websites using devices such as a mouse experience motor barriers.</p>
<p>To resolve these barriers of web or digital accessibility, the Web Accessibility Initiative (WAI) of World Wide Consortium (W3C) created the <strong>Web Content Accessibility Guidelines</strong> (WCAG). </p>
<h2 id="heading-what-are-web-content-accessibility-guidelines">What are Web Content Accessibility Guidelines?</h2>
<p>They are globally accepted standards that guide developers and organisations in building an accessible web.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/pour-accessibility.png" alt="Image" width="600" height="400" loading="lazy">
<em>Image credit: <a target="_blank" href="https://www.siteimprove.com/">Site Improve</a></em></p>
<p>Most of the barriers to web accessibility faced by people with disabilities can be put into four categories. The WCAG addresses each category to ensure accessibility is achieved.</p>
<p><strong>Perceivable:</strong> It requires that users can identify content and interface elements using their senses. Most users rely primarily on visual senses, while others rely on sound.</p>
<p><strong>Operable:</strong> It requires that users can use controls, buttons, navigation, and other interactive elements by themselves. It takes into consideration that disabled users will use assistive technology like voice recognition, keyboards, screen readers, and so on.</p>
<p><strong>Understandable:</strong> It requires that users can comprehend the content and learn and remember how to use your site. The site should have a consistent format, predictable design and usage patterns, as well as an appropriate tone.</p>
<p><strong>Robust:</strong> It requires that users of varying abilities and conditions can reliably interpret and interact with content using a technology or device of their choice.</p>
<h2 id="heading-web-accessibility-checklist">Web Accessibility Checklist</h2>
<p>As developers, these are a few of the things to look out for when building websites or application in order to ensure that people of varying abilities can access them equally.  </p>
<h3 id="heading-how-to-make-images-accessible">How to make images accessible</h3>
<p>All images should have descriptive sentence-like alt texts instead of just a word or clause. For example, the image below should have an alt text as shown in the code beneath it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/pizza.jpg" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@hybridstorytellers?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText"&gt;Hybrid Storytellers on &lt;a href="https://unsplash.com/t/food-drink?utm_source=unsplash&amp;utm_medium=referral&amp;utm<em>content=creditCopyText)</em></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"a right hand removing a slice from a whole pizza"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unsplash.com/photos/XYyUxXw_oQw"</span>/&gt;</span>
</code></pre>
<p>The code above shows a sentence-like, descriptive alternative text for the image. The goal of the alt text should be to describe the image in such a way that people using screen readers feel like they can visualize or imagine exactly what image is being described.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/ImageAlt-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Image Alt text output</em></p>
<p>The next level of accessibility as seen in the above image, is to write alt texts so that users who may be encountering connectivity issues have an idea of the image before they see it.</p>
<h3 id="heading-how-to-make-links-accessible">How to make links accessible</h3>
<p>Links should be descriptive and suggestive, and you should label all links with exactly what they do. </p>
<p>Avoid embedding your links in vague texts such as ‘here’. For instance, if we wanted to refer to my most recent article, for the sake of users who rely on screen readers, this is how to do it.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
Check out my most recent article on <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://www.freecodecamp.org/news/web-layouts-use-css-grid-and-flex-to-create-responsive-webpages/"</span>&gt;</span>Web Layouts – How to Use CSS Grid and Flex to Create a Responsive Web Page<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>In the code above, the link tag is wrapped around the whole title of the article instead of simply making the link text a vague 'here'. This way, everyone who sees, reads, or hears it knows exactly what resource will be found when the link is clicked.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/AccessibilityLink.png" alt="Image" width="600" height="400" loading="lazy">
<em>Link output image</em></p>
<p>When screen readers get to a link that is as descriptive as what we have in the image above, it makes it very easy for visually impaired users to know what the link does and, in effect, decide whether or not to visit it. </p>
<h3 id="heading-how-to-make-forms-accessible"><strong>How to make forms accessible</strong></h3>
<p>When creating web forms, you should consider users with visual or motor limitations. Make it easy for users who can't use the mouse to navigate your form with the keyboard and users relying on screen readers to know the exact information needed for each input.</p>
<p>Ensure that your forms are accessible by using <code>&lt;label&gt;</code> or <code>aria-label</code> to communicate the purpose of an input or what information it requires to screen readers. </p>
<p><code>&lt;fieldset&gt;</code> tags tell the form that groups of inputs belong together and <code>&lt;legend&gt;</code> tags act as labels for groups of inputs. These become especially necessary when dealing with questions that involve checkboxes or radio buttons.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">fieldset</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"first-section"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">legend</span>&gt;</span>Contact Details<span class="hljs-tag">&lt;/<span class="hljs-name">legend</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"name"</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">autofocus</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Ophy Boamah"</span> <span class="hljs-attr">autocomplete</span>=<span class="hljs-string">"on"</span> <span class="hljs-attr">required</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"ob2@hotmail.com"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"tel"</span>&gt;</span>Phone<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"tel"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tel"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"+233 200001212"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">fieldset</span>&gt;</span>
</code></pre>
<p>In the code above, I implement all the form best practices I mentioned. The fieldset tag creates an initial "first-section" group. The legend tag contains text that provides a description for the group of elements. Finally, the label tag identifies each of the inputs and their purpose.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/Fieldset.png" alt="Image" width="600" height="400" loading="lazy">
<em>Accessible form output</em></p>
<p>The image above is the output of the code. To learn more about creating modern and accessible forms, check out my previous article on <a target="_blank" href="https://www.freecodecamp.org/news/create-and-validate-modern-web-forms-html5/">How To Create and Validate Modern Web Forms With HTML5</a>. </p>
<h3 id="heading-video-and-audio-accessibility">Video and audio accessibility</h3>
<p>All videos should have subtitles and captions. Similarly, all audio should have transcripts, so that people with hearing challenges can still follow along and understand.</p>
<pre><code class="lang-html"> <span class="hljs-tag">&lt;<span class="hljs-name">video</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"video"</span> <span class="hljs-attr">controls</span> <span class="hljs-attr">preload</span>=<span class="hljs-string">"metadata"</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"assets/samplevideo.mp4"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"video/mp4"</span> /&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">track</span>
     <span class="hljs-attr">label</span>=<span class="hljs-string">"English"</span>
     <span class="hljs-attr">kind</span>=<span class="hljs-string">"subtitles"</span>
     <span class="hljs-attr">srclang</span>=<span class="hljs-string">"en"</span>
     <span class="hljs-attr">src</span>=<span class="hljs-string">"assets/samplevideo-en.srt"</span>
     <span class="hljs-attr">default</span> /&gt;</span>
 <span class="hljs-tag">&lt;/<span class="hljs-name">video</span>&gt;</span>
</code></pre>
<p>The code above shows a video element that introduces the track tag for adding subtitles so that users who are not able to hear the accompanying audio can read to follow along.</p>
<div class="embed-wrapper">
        <iframe width="640" height="360" src="https://player.vimeo.com/video/776769878" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="Vimeo embed" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen="" loading="lazy"></iframe></div>
<h3 id="heading-how-to-select-colours-for-accessibility">How to select colours for accessibility</h3>
<p>When selecting colours for your websites, consider people who are colour-blind and those who have issues with sight. </p>
<p>When we use colours with poor contrast, it makes it difficult for users to read or navigate content on a web page. This means that we must always ensure that even in bad lighting conditions, our foreground and background colours have enough contrast between them for button, links, images, icons, texts and so on. </p>
<p>If you're unsure whether two colours complement each other in an accessible way, check using this <a target="_blank" href="https://accessibleweb.com/color-contrast-checker/">online colour checker tool</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/wcagcolorcheceker.png" alt="Image" width="600" height="400" loading="lazy">
<em>Use a color checker tool to check color contrast</em></p>
<p>You can also add this <a target="_blank" href="https://chrome.google.com/webstore/detail/accessible-web-helper/gdnpkbipbholkoaggmlblpbmgemddbgb">Web Accessibility Checker Chrome Extension</a> to your browser for onsite accessibility checks.</p>
<h3 id="heading-how-to-make-transitions-and-animations-accessible">How to make transitions and animations accessible</h3>
<p>Use transitions and animations sparingly and only when extremely necessary in order not to trigger some users. </p>
<p>There are those who get dizzy or experience seizures when they encounter elements that move rapidly. Provide a way for such users to pause, hide, or stop the animation by making those controls available. </p>
<h3 id="heading-how-to-create-accessible-page-structure-and-navigation">How to create accessible page structure and navigation</h3>
<p>Use the appropriate HTML tags to semantically structure websites. Your site should be easy to navigate especially with assistive technology. </p>
<p>Page titles should be descriptive so users can easily differentiate between tabs.</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Web Accessibility Site | Checklist for Developers<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</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">nav</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">li</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Contact<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">nav</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>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">section</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">h1</span>&gt;</span>
          Welcome to Web Accessibility
        <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
          This is semantic structuring with HTML tag
        <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">section</span>&gt;</span>
  <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;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://codehemaa.com"</span>&gt;</span>My website<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The code above shows a web page with a descriptive title. I've used the right semantic tags to properly structure the page by distinguishing the header from the main body and footer. </p>
<p>I've also properly labelled sections, divs, and headings. This helps screen recorders to properly spell out exactly what element and content is present on the page.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>If the inventor of the web stated emphatically “<em>access by everyone regardless of disability is an essential aspect</em>” of the web, then as developers we must strive to achieve just that. Plus, it's just the right thing to do.</p>
<p>You should consider accessibility even before you start to build your sites – not done after as damage control. Going forward, we ought to strive for inclusion by contributing to build a more a11y-conscious and a11y-friendly web. </p>
<p>Thanks for reading 👋🏾. I hope you found it helpful.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Web Layouts – How to Use CSS Grid and Flex to Create a Responsive Web Page ]]>
                </title>
                <description>
                    <![CDATA[ Your web layout is to your website what a floor plan is to a building. Without them, you’re just building castles in the air.  The first thing to do when you have a website or application to build or design is to decide on the layout. This is importa... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/web-layouts-use-css-grid-and-flex-to-create-responsive-webpages/</link>
                <guid isPermaLink="false">66c5a349dd1f1e4092a32568</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS Grid ]]>
                    </category>
                
                    <category>
                        <![CDATA[ flexbox ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Fri, 21 Oct 2022 23:12:52 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/10/WebLayouts-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Your web layout is to your website what a floor plan is to a building. Without them, you’re just building castles in the air. </p>
<p>The first thing to do when you have a website or application to build or design is to decide on the layout. This is important because it is within this layout that you specify how elements are arranged so that you can assess them in their intended manner and hierarchy.</p>
<p>Basically, the aim of every web layout is to reduce confusion, enhance usability and to ultimately give your users an enjoyable experience. Some of the main elements of a layout are navigation, menus and content. </p>
<p>In web and front-end development, having a layout in mind ahead of building can help you decide on what CSS layout module to use: Flexbox or Grid.</p>
<p>In this article, we’re going to learn what each of these tools are and the best way to use them by building a simple yet beautiful landing page.</p>
<h2 id="heading-what-were-going-to-build">What We're Going To Build</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/homepage-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>landing page design</em></p>
<p>Check it out on Codepen <a target="_blank" href="https://codepen.io/ophyboamah/pen/KKRLoJr">here</a>.</p>
<h2 id="heading-project-functionality">Project Functionality</h2>
<ol>
<li>Web Layout: Create a beautiful landing page</li>
<li>Mobile Responsiveness</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>Basic knowledge of HTML and CSS.</li>
<li>An IDE (text editor) like VS Code</li>
<li>A web browser</li>
</ul>
<h2 id="heading-setup">Setup</h2>
<ol>
<li>Create a folder for your project and open in an IDE.</li>
<li>Within your project folder, create index.html and style.css files.</li>
<li>Create an asset folder to store images.</li>
<li>Within your index.html file, create your HTML boilerplate and link your CSS file and font URL within the <code>&lt;head&gt;</code> tag.</li>
</ol>
<h2 id="heading-resources">Resources</h2>
<ol>
<li><strong>Font:</strong> <a target="_blank" href="https://fonts.googleapis.com/css2?family=Epilogue:wght@500;700&amp;family=Poppins:wght@400;500;700&amp;display=swap">https://fonts.googleapis.com/css2?family=Epilogue:wght@500;700&amp;family=Poppins:wght@400;500;700&amp;display=swap</a></li>
<li><strong>Desktop Image:</strong> <a target="_blank" href="https://i.postimg.cc/0Nt97Bhf/image-hero-desktop.png">https://i.postimg.cc/0Nt97Bhf/image-hero-desktop.png</a></li>
<li><strong>Mobile Image:</strong> <a target="_blank" href="https://i.postimg.cc/ZnYfhwwW/image-hero-mobile.png">https://i.postimg.cc/ZnYfhwwW/image-hero-mobile.png</a></li>
<li><strong>Client Logo (Databiz):</strong> <a target="_blank" href="https://i.postimg.cc/gJ9Y84m6/client-databiz.png">https://i.postimg.cc/gJ9Y84m6/client-databiz.png</a></li>
<li><strong>Client Logo (Audiophile):</strong> <a target="_blank" href="https://i.postimg.cc/15DDqYSD/client-audiophile.png">https://i.postimg.cc/15DDqYSD/client-audiophile.png</a></li>
<li><strong>Client Logo (Meet):</strong> <a target="_blank" href="https://i.postimg.cc/5ybQqfbv/client-meet.png">https://i.postimg.cc/5ybQqfbv/client-meet.png</a></li>
<li><strong>Client Logo (Maker):</strong> <a target="_blank" href="https://i.postimg.cc/g2NsxByN/client-maker.png">https://i.postimg.cc/g2NsxByN/client-maker.png</a></li>
</ol>
<h1 id="heading-how-to-use-flexbox">How to Use Flexbox</h1>
<p>Generally, HTML elements align according to their default display style. This means, without external styling with CSS, block elements like <code>p</code> and <code>div</code> will start on a new line. Inline elements like <code>input</code> and <code>span</code>, on the other hand, are arranged next to each other on the same line.</p>
<p>However, the concept of Flexbox allows you to easily place these elements either horizontally or vertically in what’s often referred to as one dimension. In order to achieve this, at least two elements are required: <strong>flex container</strong> and <strong>flex item</strong>. These refer to a parent and child element, respectively.</p>
<p>In responsive design, the purpose of Flexbox is to allow containers and their child elements to fill defined spaces or shrink depending on a device’s dimensions.</p>
<h2 id="heading-flex-direction-and-axes">Flex-direction and Axes</h2>
<p>Flex-direction is an important property of CSS Flexbox, because it is what determines the direction that flex items are arranged in. It does this by pointing out the main axis of a flex container.</p>
<p>There are two main axes, namely <strong>main axis</strong> and <strong>cross axis</strong>. The main axis is the defined direction of how your flex items are placed in the flex container, whilst the cross axis is always the axis at the opposite side of the main axis. </p>
<p>It can be dangerous to try using the concept of x and y axis from math to understand this. This is mainly because in Flexbox the main axis can be vertical or horizontal, always depending on the value of the flex-direction.</p>
<p>The values accepted by the flex-direction property include row (which is default), row-reverse, column, and column-reverse. For the purposes of this project, we’re going to look at row and column.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/flexdirection.png" alt="Image" width="600" height="400" loading="lazy">
<em>flex-direction: row</em></p>
<p>When the flex-direction attribute has a value of row, the main axis is horizontal and the cross axis is vertical, as shown in the image above. This means flex items will be arranged horizontally. </p>
<p>Since the row is the default value, if you display a container as flex but don't specify the flex-direction, the flex items will automatically be in a row.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/flexdirectioncolumn.png" alt="Image" width="600" height="400" loading="lazy">
<em>flex-direction: column</em></p>
<p>When the flex-direction attribute has a value of column, the main axis is vertical and the cross axis is horizontal, as shown in the image above. This means flex items will be arranged vertically. </p>
<h2 id="heading-how-to-build-the-navbar">How to Build the Navbar</h2>
<p>Now that we know how Flexbox works, let’s start building our navbar. We'll first provide the content within it, that is the menu items and logo. We’ll give them descriptive classes so that we can easily reference them within our CSS file.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"logo"</span>&gt;</span>snap<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"menu-items"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Features<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Company<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Careers<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>About<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">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"cta-btns"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Register<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">nav</span>&gt;</span>
</code></pre>
<p>The image below is the output for the code above. Because both <code>&lt;ul&gt;</code> and <code>&lt;li&gt;</code>  are block elements, each of the items we specified within them will be displayed on a new line.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/preflexx-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Navbar content output</em></p>
<p>Flexbox layout display is declared on parent containers and affects child elements. This means that if you had a list of groceries in an unordered list, display flex can’t be applied on the <code>&lt;li&gt;</code>s which are child elements in this case. Instead, to display them as flex, you’d first have to create a parent container and apply it to that. </p>
<p>In our CSS code below, we're defining the font style and size for our project as well as our navbar logo. We're also displaying our nav elements and some of the elements within those as flex. </p>
<pre><code class="lang-css">* {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Epilogue"</span>, sans-serif;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.85rem</span>;
}

<span class="hljs-selector-class">.logo</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.3rem</span>;
}

<span class="hljs-selector-tag">nav</span>,
<span class="hljs-selector-class">.cta-btns</span>,
<span class="hljs-selector-class">.menu-items</span> {
  <span class="hljs-attribute">display</span>: flex;
}
</code></pre>
<p>The image below is the output for the code above. The elements have been displayed as flex. Yet because we didn't specify the flex-direction, they're automatically arranged in a row. </p>
<p>But as you can see below using the ruler (red line), the flex items are not aligned as they should be. Let's fix that by learning another important flex element.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/displayflex.png" alt="Image" width="600" height="400" loading="lazy">
<em>Flex without alignment</em></p>
<h3 id="heading-how-to-use-the-align-items-attribute">How to use the <code>align-items</code> attribute</h3>
<p>This is a Flexbox attribute that controls the arrangement of flex items on the cross axis. The values it takes are flex-start, flex-end and center depending on the element's alignment needs. The image below shows how each of them works. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/align-items-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Image credit: freeCodeCamp</em></p>
<p>From the image above, we can see that if we want to ensure that the flex items within our <code>&lt;nav&gt;</code> are aligned properly, on that element we must give the align-items attribute a value of center. So we have to add an attribute of <em>align-items</em> and a value of <em>center</em> to our flex container as shown in the CSS code below:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">nav</span>,
<span class="hljs-selector-class">.cta-btns</span>,
<span class="hljs-selector-class">.menu-items</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
}
</code></pre>
<p>As you can see in the image below, the flex items are now aligned as they should be. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/aligncenter.png" alt="Image" width="600" height="400" loading="lazy">
<em>Flex with center alignment</em></p>
<p>But once again there is something missing. We want to have our items spread out properly on the navbar: the logo on the extreme left, login and register at the extreme right, and the rest in the middle. </p>
<p>We can achieve this with the <code>justify-content</code> attribute. Let's learn about it next and then implement it.</p>
<h3 id="heading-how-to-use-the-justify-content-attribute">How to use the <code>justify-content</code> attribute</h3>
<p>This is a Flexbox attribute that controls the arrangement of flex items on the main axis. It also defines how browsers distribute space between and around flex items within a flex container. </p>
<p>To achieve responsiveness, it helps with allocating any excess space that is leftover after flex-items have been arranged.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/justifycontentstyles.png" alt="Image" width="600" height="400" loading="lazy">
<em>justify-content styles</em></p>
<p>From the styles associated with the various values of the justify-content attribute, we can see that the bottom two are more similar to what we're trying to achieve. </p>
<p>We can either go for the space around or the space-between and provide some padding on the sides to push the items on the extreme ends from the edges. We also give the list-syle attribute a value of none to remove the dots in front of the list items.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">li</span> {
  <span class="hljs-attribute">list-style</span>: none;
}

<span class="hljs-selector-tag">nav</span> {
  <span class="hljs-attribute">justify-content</span>: space-between;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/justifycontent-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>justify-content navbar output</em></p>
<p>Now that we have the items placed at their desired positions, we need to create slight spaces between them. In this case, we're going to give each list item a margin-right of 1rem. We also set other styles like size of fonts, color and a border for the register item. </p>
<pre><code class="lang-css"><span class="hljs-selector-tag">nav</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> <span class="hljs-number">1.5rem</span> <span class="hljs-number">1.5rem</span> <span class="hljs-number">1.5rem</span>;
  <span class="hljs-attribute">justify-content</span>: space-between;
}

<span class="hljs-selector-class">.logos-section</span> {
  <span class="hljs-attribute">display</span>: flex;
}

<span class="hljs-selector-class">.menu-items</span> <span class="hljs-selector-tag">li</span>,
<span class="hljs-selector-class">.cta-btns</span> <span class="hljs-selector-tag">li</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.7rem</span>;
  <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0%</span>, <span class="hljs-number">41%</span>);
}

<span class="hljs-selector-class">.cta-btns</span> <span class="hljs-selector-tag">li</span><span class="hljs-selector-pseudo">:nth-last-child(1)</span> {
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid gray;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.2rem</span> <span class="hljs-number">0.7rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.3rem</span>;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/justifyandstyles-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Navbar with styles</em></p>
<p>After implementing the above code, this is the final look of our navbar. And this marks the end of our Flexbox section. Next, we'll build the final part of our landing page with CSS Grid.</p>
<h1 id="heading-how-to-use-css-grid">How to Use CSS Grid</h1>
<p>CSS Grid is a life-changing tool for creating web layouts. It helps you make both simple and complex layouts. The main difference is that while Flexbox helps with one dimensional arrangement of elements, CSS grid is able to do two dimensional arrangements. </p>
<p>The concept of axes we learnt about under Flexbox still applies here. You can use CSS Grid to arrange elements on the main axis and cross axis at the same time. </p>
<p>In summary, Flexbox, allows you to either arrange elements horizontally (in a row) or vertically (in a column). But with CSS Grid you can align elements both vertically and horizontally.</p>
<p>The CSS Grid layout is declared only on parent elements or containers. In effect, all its children become grid items. Once you have the target container, you give it an attribute of display and value of grid. The size of a grid’s row and column can be determined with <code>grid-template-rows</code> and <code>grid-template-columns</code>, respectively.</p>
<h2 id="heading-how-to-build-the-homepage">How to Build the Homepage</h2>
<p>Just like we did with the navbar, let's start by defining our content within a <code>&lt;main&gt;</code> section in our HTML file. </p>
<p>Looking at our target image, we have two main sections: the left section will have text and logos whilst the right section has a hero image. That’s for the web view of our project. </p>
<p>Let's start by defining our content. The section with class text-side contains: heading, paragraph text, button and logo. The section with class img-side only contains an image.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"text-side"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Make <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>remote work<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
          Get your team in sync, no matter your location. Streamline processes,
          create team rituals, and watch productivity soar.
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Learn more<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"clients-logos"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./assets/images/client-databiz.svg"</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./assets/images/client-audiophile.svg"</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./assets/images/client-meet.svg"</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./assets/images/client-maker.svg"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"img-side"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./assets/images/image-hero-desktop.png"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
</code></pre>
<p>Within the main section, we created the two sections we needed and gave them descriptive id's: text-side and img-side. </p>
<p>Within the text-side, we added a heading, paragraph text, button and a div to display clients' logos. The only thing we need for the img-side is the display image.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Client Logos */</span>
<span class="hljs-selector-class">.clients-logos</span> <span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">5rem</span>;
  <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">1rem</span>;
}

<span class="hljs-selector-class">.clients-logos</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">4rem</span>;
}

<span class="hljs-selector-class">.clients-logos</span> <span class="hljs-selector-tag">img</span><span class="hljs-selector-pseudo">:nth-child(2)</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">3rem</span>;
}

<span class="hljs-comment">/* Main */</span>
<span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">3rem</span>;
}

<span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.7rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">18rem</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0%</span>, <span class="hljs-number">41%</span>);
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">0.9rem</span>;
}

<span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0%</span>, <span class="hljs-number">8%</span>);
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.7rem</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.6rem</span> <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.4rem</span>;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">1rem</span>;
}

<span class="hljs-selector-id">#text-side</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">3rem</span>;
}
<span class="hljs-comment">/* Hero Image */</span>
<span class="hljs-selector-class">.img-side</span> <span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">20rem</span>;
}
</code></pre>
<p>Within our CSS file, we need to style the client logos div as well as the child elements. We also set a font-size for the heading and paragraph. Next, we style our button and assign a width to our image.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/pregrid1-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>pre-grid homepage display</em></p>
<p>The image above shows how our web page will look after defining the content and styling just the heading, button and logos – that is, we haven't declared our container as a grid yet. Because almost all the elements we have here are block elements, we see them align on top of one another.</p>
<h2 id="heading-grid-template-rows-and-columns">Grid Template Rows and Columns</h2>
<p>The <code>grid-template-columns</code> property specifies the number and widths of columns in a grid, defining a grid container's column by specifying the size of its tracks and line names. </p>
<p>The <code>grid-template-rows</code> property is the direct opposite. It specifies the number and heights of rows in a grid, also defining a grid container's row by specifying the size of its tracks and line names. </p>
<p>As you can see in the image below, <code>grid-template-rows</code> arranges elements from the top to bottom of the device screen. <code>grid-template-columns</code> arranges elements from the left to right side of the device screen. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/CSS-Grid.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>For our project, we're going to make use of <code>grid-template-columns</code> since we want to arrange our two sections side by side, letting each section occupy an equal part of the overall project width. We do this by assigning it as an attribute on the same container that we specified a display of grid on. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/displaygrid.png" alt="Image" width="600" height="400" loading="lazy">
<em>display: grid</em></p>
<p>Now that the two sections inside our <code>&lt;main&gt;</code> tag have been placed equally using the grid-template-columns, we have two last things to do. </p>
<p>We need to align them horizontally, by positioning both elements in the center of the page, with the extra space on the left of the image, evenly distributed on both sides. We also need to align them vertically by positioning both of them in the center of the page, with the extra space on the bottom, evenly distributed above and beneath.</p>
<h2 id="heading-align-and-justify-in-css-grid">Align and Justify in CSS Grid</h2>
<p>Good news – we don't have to learn any new concepts to achieve our desired alignments in CSS Grid Layouts. Because fortunately, <code>align-items</code> and <code>justify-content</code>, as we learnt earlier, are not exclusive to Flebox. You can also use them to position items both horizontally and vertically.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">main</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">2</span>, <span class="hljs-number">1</span>fr);
  <span class="hljs-attribute">height</span>: <span class="hljs-number">70vh</span>;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">8rem</span>;
}
</code></pre>
<p>As you can see in the code above, we only had to give the value of center to both align-items and justify-content attributes on the parent tag (grid container). </p>
<p>To ensure that we see the effect of position in the perfect center, we also had to specify a height for the section. The image below is the final output of our project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/homepage-4.png" alt="Image" width="600" height="400" loading="lazy">
<em>Landing page final look</em></p>
<h2 id="heading-how-to-make-it-responsive">How to Make it Responsive</h2>
<p>So far, everything we've built is for the web. But for the sake of users who want to access the landing page on mobile, we have to make our project accessible on smaller screens. In our case, we're looking at screens that are greater than 300px but less than 480px. </p>
<p>As you can see in the code below, we're hiding our nav items and displaying an emoji with class of mobile-nav. Beside that, we're hiding the desktop header image and showing the mobile header image. </p>
<pre><code class="lang-css"><span class="hljs-comment">/* Responsive */</span>
<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">min-width:</span> <span class="hljs-number">300px</span>) <span class="hljs-keyword">and</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">480px</span>) {
  * {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  }

  <span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100vw</span>;
    <span class="hljs-attribute">overflow-y</span>: hidden;
    <span class="hljs-attribute">overflow-x</span>: hidden;
  }

  <span class="hljs-selector-tag">nav</span> {
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> <span class="hljs-number">1.5rem</span> <span class="hljs-number">0</span> <span class="hljs-number">1.5rem</span>;
  }

  <span class="hljs-selector-tag">nav</span> <span class="hljs-selector-tag">ul</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  <span class="hljs-selector-class">.mobile-nav</span> {
    <span class="hljs-attribute">display</span>: block;
    <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">2rem</span>;
  }

  <span class="hljs-selector-tag">main</span> {
    <span class="hljs-attribute">display</span>: grid;
    <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
  }

  <span class="hljs-comment">/* Clients logos */</span>
  <span class="hljs-selector-class">.clients-logos</span> {
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">2rem</span>;
  }

  <span class="hljs-selector-class">.desktop-logos</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  <span class="hljs-selector-class">.mobile-logos</span> {
    <span class="hljs-attribute">display</span>: block;
  }

  <span class="hljs-comment">/* Images */</span>
  <span class="hljs-selector-class">.desktop-img</span> {
    <span class="hljs-attribute">display</span>: none;
  }
  <span class="hljs-selector-class">.mobile-img</span> {
    <span class="hljs-attribute">display</span>: block;
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">3rem</span>;
  }

  <span class="hljs-selector-class">.cta-btns</span>,
  <span class="hljs-selector-class">.menu-items</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  <span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">h1</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2.5rem</span>;
  }

  <span class="hljs-comment">/* Client Logos */</span>
  <span class="hljs-selector-class">.clients-logos</span> <span class="hljs-selector-tag">img</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">4.5rem</span>;
    <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">0.8rem</span>;
  }

  <span class="hljs-selector-class">.attribution</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">13rem</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">8rem</span> auto <span class="hljs-number">0</span> auto;
    <span class="hljs-attribute">text-align</span>: center;
  }
}
</code></pre>
<h2 id="heading-full-project-code">Full Project Code</h2>
<p>This is the project we’ve built together in this article:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/homepage-3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here's the full HTML code:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
    <span class="hljs-comment">&lt;!-- displays site properly based on user's device --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"preconnect"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"preconnect"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.gstatic.com"</span> <span class="hljs-attr">crossorigin</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
      <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Epilogue:wght@500;700&amp;family=Poppins:wght@400;500;700&amp;display=swap"</span>
      <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"style.css"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
      <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span>
      <span class="hljs-attr">type</span>=<span class="hljs-string">"image/png"</span>
      <span class="hljs-attr">sizes</span>=<span class="hljs-string">"32x32"</span>
      <span class="hljs-attr">href</span>=<span class="hljs-string">"./images/favicon-32x32.png"</span>
    /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Web Layout | Landing Page<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Feel free to remove these styles or customise in your own stylesheet 👍 --&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"logos-section"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"logo"</span>&gt;</span>snap<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"menu-items"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
            Features<span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
              <span class="hljs-attr">width</span>=<span class="hljs-string">"10"</span>
              <span class="hljs-attr">height</span>=<span class="hljs-string">"6"</span>
              <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">path</span>
                <span class="hljs-attr">stroke</span>=<span class="hljs-string">"#686868"</span>
                <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"1.5"</span>
                <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span>
                <span class="hljs-attr">d</span>=<span class="hljs-string">"m1 1 4 4 4-4"</span>
              /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
            Company<span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
              <span class="hljs-attr">width</span>=<span class="hljs-string">"10"</span>
              <span class="hljs-attr">height</span>=<span class="hljs-string">"6"</span>
              <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">path</span>
                <span class="hljs-attr">stroke</span>=<span class="hljs-string">"#686868"</span>
                <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"1.5"</span>
                <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span>
                <span class="hljs-attr">d</span>=<span class="hljs-string">"m1 1 4 4 4-4"</span>
              /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Careers<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>About<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">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"cta-btns"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Register<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">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mobile-nav"</span>&gt;</span>🌚<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"text-side"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Make <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>remote work<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
          Get your team in sync, no matter your location. Streamline processes,
          create team rituals, and watch productivity soar.
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Learn more<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"clients-logos"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://i.postimg.cc/gJ9Y84m6/client-databiz.png"</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://i.postimg.cc/15DDqYSD/client-audiophile.png"</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://i.postimg.cc/5ybQqfbv/client-meet.png"</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://i.postimg.cc/g2NsxByN/client-maker.png"</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">section</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"img-side"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
          <span class="hljs-attr">class</span>=<span class="hljs-string">"desktop-img"</span>
          <span class="hljs-attr">src</span>=<span class="hljs-string">"https://i.postimg.cc/0Nt97Bhf/image-hero-desktop.png"</span>
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
          <span class="hljs-attr">class</span>=<span class="hljs-string">"mobile-img"</span>
          <span class="hljs-attr">src</span>=<span class="hljs-string">"https://i.postimg.cc/ZnYfhwwW/image-hero-mobile.png"</span>
        /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"attribution"</span>&gt;</span>
      Challenge by
      <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://www.frontendmentor.io?ref=challenge"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>
        &gt;</span>Frontend Mentor<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>
      &gt;</span>. Coded by <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://codehemaa.com"</span>&gt;</span>Ophy Boamah<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>.
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Here's the full CSS code:</p>
<pre><code class="lang-css">* {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Epilogue"</span>, sans-serif;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.3rem</span>;
}

<span class="hljs-selector-class">.logo</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.3rem</span>;
}

<span class="hljs-selector-tag">li</span> {
  <span class="hljs-attribute">list-style</span>: none;
}

<span class="hljs-selector-tag">nav</span>,
<span class="hljs-selector-class">.cta-btns</span>,
<span class="hljs-selector-class">.menu-items</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
}

<span class="hljs-selector-tag">nav</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> <span class="hljs-number">1.5rem</span> <span class="hljs-number">1.5rem</span> <span class="hljs-number">1.5rem</span>;
  <span class="hljs-attribute">justify-content</span>: space-between;
}

<span class="hljs-selector-class">.mobile-nav</span> {
    <span class="hljs-attribute">display</span>: none;
}

<span class="hljs-selector-class">.logos-section</span> {
  <span class="hljs-attribute">display</span>: flex;
}

<span class="hljs-selector-class">.menu-items</span> <span class="hljs-selector-tag">li</span>,
<span class="hljs-selector-class">.cta-btns</span> <span class="hljs-selector-tag">li</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.7rem</span>;
  <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0%</span>, <span class="hljs-number">41%</span>);
}

<span class="hljs-selector-class">.cta-btns</span> <span class="hljs-selector-tag">li</span><span class="hljs-selector-pseudo">:nth-last-child(1)</span> {
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid gray;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.2rem</span> <span class="hljs-number">0.7rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.3rem</span>;
}

<span class="hljs-comment">/* Client Logos */</span>

<span class="hljs-selector-class">.clients-logos</span> <span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">8rem</span>;
  <span class="hljs-attribute">margin-right</span>: -<span class="hljs-number">3rem</span>;
}

<span class="hljs-selector-class">.clients-logos</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">margin-left</span>: -<span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">10rem</span>;
}

<span class="hljs-selector-class">.clients-logos</span> <span class="hljs-selector-tag">img</span><span class="hljs-selector-pseudo">:nth-child(2)</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">7rem</span>;
}

<span class="hljs-comment">/* Main */</span>
<span class="hljs-selector-tag">main</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">2</span>, <span class="hljs-number">1</span>fr);
  <span class="hljs-attribute">height</span>: <span class="hljs-number">70vh</span>;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">8rem</span>;
}
<span class="hljs-comment">/* Images */</span>
<span class="hljs-selector-class">.desktop-img</span> {
  <span class="hljs-attribute">display</span>: block;
}
<span class="hljs-selector-class">.mobile-img</span> {
  <span class="hljs-attribute">display</span>: none;
}

<span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">3rem</span>;
}

<span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.7rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">18rem</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0%</span>, <span class="hljs-number">41%</span>);
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">0.9rem</span>;
}

<span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0%</span>, <span class="hljs-number">8%</span>);
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.7rem</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.6rem</span> <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.4rem</span>;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">1rem</span>;
}

<span class="hljs-selector-id">#text-side</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">3rem</span>;
}
<span class="hljs-comment">/* Hero Image */</span>
<span class="hljs-selector-id">#img-side</span> <span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">20rem</span>;
}

<span class="hljs-selector-class">.attribution</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.7rem</span>;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">5.5rem</span>;
}

<span class="hljs-selector-class">.attribution</span> <span class="hljs-selector-tag">a</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">228</span>, <span class="hljs-number">45%</span>, <span class="hljs-number">44%</span>);
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.7rem</span>;
}

<span class="hljs-comment">/* Responsive */</span>
<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">min-width:</span> <span class="hljs-number">300px</span>) <span class="hljs-keyword">and</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">480px</span>) {
  * {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  }

  <span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100vw</span>;
    <span class="hljs-attribute">overflow-y</span>: hidden;
    <span class="hljs-attribute">overflow-x</span>: hidden;
  }

  <span class="hljs-selector-tag">nav</span> {
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> <span class="hljs-number">1.5rem</span> <span class="hljs-number">0</span> <span class="hljs-number">1.5rem</span>;
  }

  <span class="hljs-selector-tag">nav</span> <span class="hljs-selector-tag">ul</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  <span class="hljs-selector-class">.mobile-nav</span> {
    <span class="hljs-attribute">display</span>: block;
    <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">2rem</span>;
  }

  <span class="hljs-selector-tag">main</span> {
    <span class="hljs-attribute">display</span>: grid;
    <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">margin</span>: -<span class="hljs-number">3rem</span> auto <span class="hljs-number">0</span> auto;
  }

  <span class="hljs-comment">/* Clients logos */</span>
  <span class="hljs-selector-class">.clients-logos</span> {
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">2rem</span>;
  }

  <span class="hljs-selector-class">.clients-logos</span> <span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">30rem</span>;
}

<span class="hljs-selector-class">.clients-logos</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">display</span>: flex;
}

<span class="hljs-selector-class">.clients-logos</span> <span class="hljs-selector-tag">img</span><span class="hljs-selector-pseudo">:nth-child(2)</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">7rem</span>;
}

  <span class="hljs-comment">/* Images */</span>
  <span class="hljs-selector-class">.desktop-img</span> {
    <span class="hljs-attribute">display</span>: none;
  }
  <span class="hljs-selector-class">.mobile-img</span> {
    <span class="hljs-attribute">display</span>: block;
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">3rem</span>;
  }

  <span class="hljs-selector-class">.cta-btns</span>,
  <span class="hljs-selector-class">.menu-items</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  <span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">h1</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2.5rem</span>;
  }

  <span class="hljs-comment">/* Client Logos */</span>
  <span class="hljs-selector-class">.clients-logos</span> <span class="hljs-selector-tag">img</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">4.5rem</span>;
    <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">0.8rem</span>;
  }

  <span class="hljs-selector-class">.attribution</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">13rem</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">10rem</span> auto <span class="hljs-number">0</span> auto;
    <span class="hljs-attribute">text-align</span>: center;
  }
}
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>As a web developer, layouts should be the first thing you consider before writing code. Thankfully, CSS Grid and Flexbox have revolutionized the way we structure and build website and web app layouts. </p>
<p>This makes these concepts a must know so you can specify the arrangement of elements on the web. We've discussed the fundamentals, so that you can easily build up on the knowledge and create beautiful web pages and apps. </p>
<p>Thanks for reading 👋🏾. I hope you found this helpful.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How the JavaScript DOM Works – A Practical Tutorial ]]>
                </title>
                <description>
                    <![CDATA[ If you were listening to music on an app and you wanted to pause or skip a song, you'd have to do that through the app. This process is similar to how the Document Object Model or DOM works. Here, the music app represents the DOM because it serves as... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/the-javascript-dom-a-practical-tutorial/</link>
                <guid isPermaLink="false">66c5a343215f782a032b1cb9</guid>
                
                    <category>
                        <![CDATA[ Document Object Model ]]>
                    </category>
                
                    <category>
                        <![CDATA[ DOM ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Mon, 12 Sep 2022 20:19:15 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/DOMpract-2-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you were listening to music on an app and you wanted to pause or skip a song, you'd have to do that through the app.</p>
<p>This process is similar to how the Document Object Model or DOM works. Here, the music app represents the DOM because it serves as a medium to make changes to the music.</p>
<p>In this tutorial, you'll learn what the DOM is and how it works in a practical way.</p>
<h2 id="heading-what-is-the-dom">What is the DOM?</h2>
<p>The DOM is a Web API that allows developers to use programming logic to make changes to their HTML code. It's a reliable way to make changes that turn static websites into dynamic ones. </p>
<p>It's an important topic in web development because the DOM serves as the initial use of JavaScript in the browser. </p>
<p>HTML code isn’t considered part of the DOM until its parsed by the browser. To see what happens to your HTML code when this parsing happens, copy your code from the <strong><code>&lt;body&gt;</code></strong> tag and paste it <a target="_blank" href="https://software.hixie.ch/utilities/js/live-dom-viewer/">here</a> (within the box with the title 'Markup to test' after the three dots).</p>
<h2 id="heading-what-are-we-building">What are we building?</h2>
<p>In this article, we’re going to learn the most important and often used parts of the DOM by building this simple project:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/domProject-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Check it out on CodePen <a target="_blank" href="https://codepen.io/ophyboamah/pen/bGMdbve">here</a>.</p>
<h2 id="heading-project-functionality">Project Functionality</h2>
<p>As you can see in the project demo above, these are the functionalities we’ll implement:</p>
<ol>
<li><strong>Dynamic color change</strong>: When a color is clicked, the color of the car image, addToCart button, and tag all change to match the selected color.</li>
<li><strong>Button switch</strong>: Clicking on the addToCart button reveals the success button and vice versa.</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>basic knowledge of HTML and CSS.</li>
<li>basic knowledge of JavaScript</li>
<li>an IDE (text editor)</li>
<li>a web browser</li>
</ul>
<p><strong>NB:</strong> Because the goal of the article is to learn about JavaScript and the DOM, we won't place a lot of emphasis on the HTML and CSS code. We'll just go through it quickly first so you can set up the app. Then we'll dive into learning about the DOM.</p>
<h2 id="heading-html-code">HTML code:</h2>
<p>In our <code>index.html</code> file, we'll create the basic structure of the project which includes linking our CSS file, Font Awesome, and Google Fonts – all within our <code>&lt;head&gt;</code> tag. Within our <code>&lt;body&gt;</code> tag, we'll create our product card and link our JavaScript tag at the end of the <code>&lt;body&gt;</code> tag.</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
      <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
      <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.2/css/all.min.css"</span>
      <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha512-1sCRPdkRXhBV2PBLUdRb4tMg1w2YPf37qatUFeS7zlBy7jJI8Lf4VHwWfZZfpXtYSLy85pkm9GaYVYMfw5BC1A=="</span>
      <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>
      <span class="hljs-attr">referrerpolicy</span>=<span class="hljs-string">"no-referrer"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"preconnect"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.gstatic.com"</span> <span class="hljs-attr">crossorigin</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
      <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;700&amp;display=swap"</span>
      <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"style.css"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Practicalized DOM<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"product-card"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"product-image"</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- &lt;img src="./img/gray-benz.jpg" alt="cars" /&gt; --&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">"product-description"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tag"</span>&gt;</span>CAR<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"product-title"</span>&gt;</span>Mercedez Benz c300 2022<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"product-details"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mileage"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"font-size: 1em; color: black"</span>
              &gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-car"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>
            &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            Mileage: 4,000 miles
          <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fuel"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"font-size: 1em; color: black"</span>
              &gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-gas-pump"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>
            &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            Fuel: 25mpg
          <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"safety"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"font-size: 1em; color: black"</span>
              &gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-shield"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>
            &gt;</span>Safety:
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"stars"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-star"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-star"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-star"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-star"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-star"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Pick a color:<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"colors-price"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"colors"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"red"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"gray"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"black"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pricing"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"new-price"</span>&gt;</span>$134,450<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h4</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"old-price"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">s</span>&gt;</span>$140,500<span class="hljs-tag">&lt;/<span class="hljs-name">s</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h4</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">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"button"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"font-size: 1em; color: white"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-cart-shopping"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"button-text"</span>&gt;</span>Add to Cart<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"feedback"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"white-button"</span>
            &gt;</span>🥳 Woohoo, You're about to own a benz 🎊<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>
          &gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"app.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h2 id="heading-css-code">CSS code:</h2>
<p>In our <code>style.css</code> file, we'll first of all set our general styles like this:</p>
<pre><code class="lang-css">* {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Poppins"</span>, sans-serif;
}

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">overflow-y</span>: hidden;
  <span class="hljs-attribute">background-color</span>: antiquewhite;
}
</code></pre>
<p>Next, we'll style our product, starting with the tag, image, description and details.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* product tag */</span>
<span class="hljs-selector-class">.tag</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.9rem</span>;
  <span class="hljs-attribute">background-color</span>: black;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">4rem</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}

<span class="hljs-comment">/* product*/</span>
<span class="hljs-selector-class">.product-title</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">700</span>;
}

<span class="hljs-selector-class">.product-card</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-comment">/* align-items: center; */</span>
  <span class="hljs-attribute">grid-template-rows</span>: <span class="hljs-number">55%</span> <span class="hljs-number">45%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">80%</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">30%</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">10px</span> <span class="hljs-number">10px</span> <span class="hljs-number">25px</span> <span class="hljs-number">0px</span> <span class="hljs-number">#3c3c3c</span>;
}

<span class="hljs-selector-class">.product-image</span> {
  <span class="hljs-comment">/* border: 2px solid black; */</span>
  <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">"./img/black-benz.jpg"</span>);
  <span class="hljs-attribute">background-position</span>: center;
  <span class="hljs-attribute">background-repeat</span>: no-repeat;
  <span class="hljs-attribute">background-size</span>: cover;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">40px</span> <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">28rem</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">66%</span>;
}

<span class="hljs-selector-class">.product-description</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#62c256</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">67px</span>;
}

<span class="hljs-selector-class">.product-details</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.product-image</span> <span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">28rem</span>;
}

<span class="hljs-selector-class">.stars</span> {
  <span class="hljs-attribute">color</span>: yellow;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1em</span>;
}
</code></pre>
<p>Then, we'll style our colors: their prices, colors as a group, and individual colors.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* colors */</span>
<span class="hljs-selector-class">.colors-price</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">70%</span>;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">15px</span>;
}

<span class="hljs-selector-class">.colors</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">6rem</span>;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <span class="hljs-attribute">cursor</span>: pointer;
}

<span class="hljs-selector-class">.red</span> {
  <span class="hljs-attribute">background</span>: red;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}

<span class="hljs-selector-class">.gray</span> {
  <span class="hljs-attribute">background</span>: gray;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}

<span class="hljs-selector-class">.black</span> {
  <span class="hljs-attribute">background</span>: black;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}

<span class="hljs-selector-class">.pricing</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">12rem</span>;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <span class="hljs-attribute">align-items</span>: center;
}

<span class="hljs-selector-class">.old-price</span> {
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">100</span>;
}
</code></pre>
<p>Finally, we'll style our buttons with this code:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* buttons */</span>
<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">cursor</span>: pointer;
}

<span class="hljs-selector-id">#button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#000</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
}

<span class="hljs-selector-tag">button</span> <span class="hljs-selector-tag">white-button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>;
}

<span class="hljs-selector-class">.button-text</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">5px</span>;
}

<span class="hljs-selector-class">.feedback</span> {
  <span class="hljs-attribute">display</span>: none;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
}
</code></pre>
<h2 id="heading-dom-implementation">DOM Implementation</h2>
<p>Everything in the DOM falls into one of these two categories: selecting elements and manipulating elements. After creating our HTML and CSS files, we head into our <code>app.js</code> file to implement the following:</p>
<ol>
<li><strong>Select</strong>: We reference all elements we want to make dynamic from our HTML code and assign them variables in our JavaScript file.</li>
<li><strong>Manipulate</strong>: Once we have selected and linked the variables, we create the various functions responsible for the manipulations and then link to the variables. </li>
</ol>
<h2 id="heading-how-to-select-elements-in-the-dom">How to Select Elements in the DOM</h2>
<p>To get access to the HTML elements that you want to manipulate, you need to make the JavaScript aware that such elements exist. This is what is generally referred to as "selecting" elements – basically linking them. </p>
<p>In the DOM, there’s no one way to locate and reference an element for manipulation. Instead, it’ll depend on the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors">selector</a> you've used in the element's tag. </p>
<p>You do this by assigning the element to a variable. It takes the following format. Keep in mind that <em>all DOM selectors are preceded by the document object and a dot</em>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> example = <span class="hljs-built_in">document</span>.[DOMselector]
</code></pre>
<p>In our JavaScript file, we have to select all the elements that we want to manipulate such as the button, the colors, the image card, and the tag. </p>
<p>We’re going to use as many of the DOM selectors as possible, so let's learn more about them.</p>
<h3 id="heading-how-to-use-queryselector">How to use <code>querySelector</code></h3>
<p><code>querySelector</code> is a method which accepts the exact CSS selector in a string and returns one element. You can use it to select the red and black colors as well as the image card, using their class names.</p>
<p>If you wanted to use this approach to select and return more than one element, you can use <strong><code>QuerySelectorAll</code></strong> instead.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> redColor = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".red"</span>);
</code></pre>
<p>The code above links the span with class "red" <code>&lt;span class="red"&gt;&lt;/span&gt;</code> from our HTML code to the variable redColor in our JavaScript.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> blackColor = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".black"</span>);
</code></pre>
<p>The code above links the span with class "black" <code>&lt;span class="black"&gt;&lt;/span&gt;</code> from our HTML code to the variable blackColor in our JavaScript.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> imageCard = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".product-image"</span>);
</code></pre>
<p>The code above links the div with class "product-image" <code>&lt;div class="product-image"&gt;</code> from our HTML code to the variable imageCard in our JavaScript.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> feedbackBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".feedback"</span>);
</code></pre>
<p>The code above links the button with class "feedback" <code>&lt;button class="feedback"&gt;</code> from our HTML code to the variable feedbackBtn in our JavaScript. </p>
<h3 id="heading-how-to-use-getelementsbyclassname">How to use <code>getElementsByClassName</code></h3>
<p>You can use this selector to select the gray color. It's very similar to the <code>querySelector</code>. The only difference is that this method accepts just the name of the class, without the preceding dot (.)</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> grayColor = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"gray"</span>);
</code></pre>
<p>The code above links the span with class "gray" <code>&lt;span class="gray"&gt;&lt;/span&gt;</code> from our HTML code to the variable grayColor in our JavaScript.</p>
<h3 id="heading-how-to-use-getelementbyid">How to use <code>getElementById</code></h3>
<p>You can use this selector to select the cart button. It's very similar to the <code>getElementsByClassName</code>. The only difference is that because we use the ID to show uniqueness, it's used on only one element. This method reads getElement, <em>without an s</em>. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> cartButton = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"button"</span>);
</code></pre>
<p>The code above links the button with id "button" <code>&lt;button id="button"&gt;</code> from our HTML code to the variable cartButton in our JavaScript. </p>
<h3 id="heading-how-to-use-getelementsbytagname">How to use <code>GetElementsByTagName</code></h3>
<p>Attributes are not the only ways to select an element. You can also use tag names. If you've used the tag you're targeting more than once, then it will return a list of elements. Use indexing to select the right one.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> itemTag = <span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">"h3"</span>)[<span class="hljs-number">0</span>];
</code></pre>
<p>The code above links the h3 that contains our product tag <code>&lt;h3 class="tag"&gt;</code> from our HTML code to the variable itemTag in our JavaScript. </p>
<p>Of all these, the querySelector and querySelectorAll are probably the most popular because of how general and less restricting they are.</p>
<h2 id="heading-how-to-manipulate-elements-in-the-dom">How to Manipulate Elements in the DOM</h2>
<p>Manipulation is the main purpose of the DOM. It's everything that happens after you reference and select the element(s) you want to work with. This leads to a change in the state of the element, from static to dynamic. </p>
<p>Two concepts that you need to know to understand DOM manipulation are <strong>events</strong> and <strong>handlers</strong>. </p>
<h3 id="heading-what-are-events">What are Events?</h3>
<p>Let's use the same music analogy from earlier. On the music app, you have to perform an action [click or swipe] before the functionalities kick in. </p>
<p>In the DOM, this action is known as an event. There are events such as click, scroll, mouseover, change, and more. </p>
<p>In the DOM, responses are tied to each event. This means that there should be a lookout for the event in order to give a response. This is known as an <strong>event listener</strong>. Event listeners usually come in the form of an <code>addEventListener</code> method which takes two arguments(event, event handler).</p>
<h4 id="heading-anatomy-of-an-event">Anatomy of an Event</h4>
<p>DOM events normally contain an element, its event listener, and a function.</p>
<pre><code>element.[eventListenerMethod(event, eventHandler)
</code></pre><h3 id="heading-what-are-event-handlers">What are Event Handlers?</h3>
<p>Event handlers are the responses that are triggered when our event listener methods read an event. Without event handlers, there would be no way to alert our code that an event has occurred. </p>
<p>All the modifications that happen within the DOM such as styling, appending, removing, and so on rely on event handlers. They are the functions found in the second argument of an <strong>addEventListener</strong> method. They are always alert to run as soon as the event (first argument) happens.</p>
<pre><code class="lang-javascript">redColor.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  cartButton.style.backgroundColor = <span class="hljs-string">"red"</span>;
  itemTag.style.backgroundColor = <span class="hljs-string">"red"</span>;
  imageCard.style.backgroundImage = <span class="hljs-string">'url("./img/red-benz.webp")'</span>;
});
</code></pre>
<p>In the code above, the function after the 'click' event, is the event handler. This means that everything within that function will be implemented as soon as the red color is clicked.</p>
<h2 id="heading-how-to-implement-events-and-event-handlers">How to Implement Events and Event Handlers</h2>
<p>In this project, we’re going to use events and event handlers for about 5 implementations. We'll go through each one now.</p>
<p>First, we'll use them to <strong>make the red color functional</strong>. Once a user clicks the red color, the cart button and item tag are assigned styles in the form of a red background color. The image card also gets assigned a red background image. </p>
<p>We do this by taking the variable <code>redColor</code> and adding an event listener of 'click'. This means we want our code to be alerted when the red color is clicked. In return, the event handler <code>function</code> is in place to run immediately. </p>
<pre><code class="lang-javascript">redColor.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  cartButton.style.backgroundColor = <span class="hljs-string">"red"</span>;
  itemTag.style.backgroundColor = <span class="hljs-string">"red"</span>;
  imageCard.style.backgroundImage = <span class="hljs-string">'url("./img/red-benz.webp")'</span>;
});
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/redColor-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Red color preview</em></p>
<p>Then we'll <strong>make the gray color functional</strong>. When a user clicks the gray color, the cart button and item tag are assigned styles in the form of a gray background color. The image card is also assigned a gray background image. </p>
<p>We do this by taking the variable <code>grayColor</code> and adding an event listener of 'click'. This means we want our code to be alerted when the gray color is clicked. In return, the event handler <code>function</code> is in place to run immediately. </p>
<pre><code class="lang-javascript">grayColor[<span class="hljs-number">0</span>].addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  cartButton.style.backgroundColor = <span class="hljs-string">"gray"</span>;
  itemTag.style.backgroundColor = <span class="hljs-string">"gray"</span>;
  imageCard.style.backgroundImage = <span class="hljs-string">'url("./img/gray-benz.jpg")'</span>;
});
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/grayColor-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Gray color preview</em></p>
<p>Next we'll make the <strong>black color functional</strong>. When the user clicks the black color, the cart button and item tag are assigned styles in the form of a black background color. The image card is also assigned a black background image. </p>
<p>We do this by taking the variable <code>blackColor</code> and adding an event listener of 'click'. This means we want our code to be alerted when the black color is clicked. In return, the event handler <code>function</code> is in place to run immediately. </p>
<pre><code class="lang-javascript">blackColor.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  cartButton.style.backgroundColor = <span class="hljs-string">"black"</span>;
  itemTag.style.backgroundColor = <span class="hljs-string">"black"</span>;
  imageCard.style.backgroundImage = <span class="hljs-string">'url("./img/black-benz.jpg")'</span>;
});
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/blackColor-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Black color preview</em></p>
<p>We've looked at one approach to event handlers, which is creating the function within the addEventListener method. </p>
<p>Another approach is to create a function before passing the name of the function as an argument in the addEventListener method. </p>
<h3 id="heading-how-to-implement-the-cart-button">How to Implement the Cart Button</h3>
<p>We start by creating a function named cart. The cart function hides the cart button and shows the feedback button. The function name cart is then passed to the event listener method as the second argument.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> cart = <span class="hljs-function">() =&gt;</span> {
  cartButton.style.display = <span class="hljs-string">"none"</span>;
  feedbackBtn.style.display = <span class="hljs-string">"block"</span>;
};
cartButton.addEventListener(<span class="hljs-string">"click"</span>, cart);
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/cartButton.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Cart button preview</em></p>
<h3 id="heading-how-to-implement-the-feedback-button">How to Implement the Feedback Button</h3>
<p>We first create a function named feedback. The feedback function hides the feedback button and shows the cart button. The function name feedback is then passed to the event listener method as the second argument. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> feedback = <span class="hljs-function">() =&gt;</span> {
  cartButton.style.display = <span class="hljs-string">"block"</span>;
  feedbackBtn.style.display = <span class="hljs-string">"none"</span>;
};
feedbackBtn.addEventListener(<span class="hljs-string">"click"</span>, feedback);
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/feedbackButton.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Feedback button preview</em></p>
<h2 id="heading-full-project-code">Full Project Code</h2>
<p>This is the project we’ve built together in this article:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/domProject-2.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here's the full HTML code:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
      <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
      <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.2/css/all.min.css"</span>
      <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha512-1sCRPdkRXhBV2PBLUdRb4tMg1w2YPf37qatUFeS7zlBy7jJI8Lf4VHwWfZZfpXtYSLy85pkm9GaYVYMfw5BC1A=="</span>
      <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>
      <span class="hljs-attr">referrerpolicy</span>=<span class="hljs-string">"no-referrer"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"preconnect"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.gstatic.com"</span> <span class="hljs-attr">crossorigin</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
      <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;700&amp;display=swap"</span>
      <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"style.css"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Practicalized DOM<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"product-card"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"product-image"</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- &lt;img src="./img/gray-benz.jpg" alt="cars" /&gt; --&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">"product-description"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tag"</span>&gt;</span>CAR<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"product-title"</span>&gt;</span>Mercedez Benz c300 2022<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"product-details"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mileage"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"font-size: 1em; color: black"</span>
              &gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-car"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>
            &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            Mileage: 4,000 miles
          <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fuel"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"font-size: 1em; color: black"</span>
              &gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-gas-pump"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>
            &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            Fuel: 25mpg
          <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"safety"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"font-size: 1em; color: black"</span>
              &gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-shield"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>
            &gt;</span>Safety:
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"stars"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-star"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-star"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-star"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-star"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-star"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Pick a color:<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"colors-price"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"colors"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"red"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"gray"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"black"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pricing"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"new-price"</span>&gt;</span>$134,450<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h4</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"old-price"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">s</span>&gt;</span>$140,500<span class="hljs-tag">&lt;/<span class="hljs-name">s</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h4</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">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"button"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"font-size: 1em; color: white"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa-solid fa-cart-shopping"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"button-text"</span>&gt;</span>Add to Cart<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"feedback"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"white-button"</span>
            &gt;</span>🥳 Woohoo, You're about to own a benz 🎊<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>
          &gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"app.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Here's the CSS:</p>
<pre><code class="lang-css">* {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Poppins"</span>, sans-serif;
}

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">overflow-y</span>: hidden;
  <span class="hljs-attribute">background-color</span>: antiquewhite;
}

<span class="hljs-comment">/* product tag */</span>
<span class="hljs-selector-class">.tag</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.9rem</span>;
  <span class="hljs-attribute">background-color</span>: black;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">4rem</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}

<span class="hljs-comment">/* product*/</span>
<span class="hljs-selector-class">.product-title</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">700</span>;
}

<span class="hljs-selector-class">.product-card</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-comment">/* align-items: center; */</span>
  <span class="hljs-attribute">grid-template-rows</span>: <span class="hljs-number">55%</span> <span class="hljs-number">45%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">80%</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">30%</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">10px</span> <span class="hljs-number">10px</span> <span class="hljs-number">25px</span> <span class="hljs-number">0px</span> <span class="hljs-number">#3c3c3c</span>;
}

<span class="hljs-selector-class">.product-image</span> {
  <span class="hljs-comment">/* border: 2px solid black; */</span>
  <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">"./img/black-benz.jpg"</span>);
  <span class="hljs-attribute">background-position</span>: center;
  <span class="hljs-attribute">background-repeat</span>: no-repeat;
  <span class="hljs-attribute">background-size</span>: cover;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">40px</span> <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">28rem</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">66%</span>;
}

<span class="hljs-selector-class">.product-description</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#62c256</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">67px</span>;
}

<span class="hljs-selector-class">.product-details</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.product-image</span> <span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">28rem</span>;
}

<span class="hljs-selector-class">.stars</span> {
  <span class="hljs-attribute">color</span>: yellow;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1em</span>;
}

<span class="hljs-comment">/* colors */</span>
<span class="hljs-selector-class">.colors-price</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">70%</span>;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">15px</span>;
}

<span class="hljs-selector-class">.colors</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">6rem</span>;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <span class="hljs-attribute">cursor</span>: pointer;
}

<span class="hljs-selector-class">.red</span> {
  <span class="hljs-attribute">background</span>: red;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}

<span class="hljs-selector-class">.gray</span> {
  <span class="hljs-attribute">background</span>: gray;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}

<span class="hljs-selector-class">.black</span> {
  <span class="hljs-attribute">background</span>: black;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}

<span class="hljs-selector-class">.pricing</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">12rem</span>;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <span class="hljs-attribute">align-items</span>: center;
}

<span class="hljs-selector-class">.old-price</span> {
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">100</span>;
}

<span class="hljs-comment">/* buttons */</span>
<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">cursor</span>: pointer;
}

<span class="hljs-selector-id">#button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#000</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
}

<span class="hljs-selector-tag">button</span> <span class="hljs-selector-tag">white-button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>;
}

<span class="hljs-selector-class">.button-text</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">5px</span>;
}

<span class="hljs-selector-class">.feedback</span> {
  <span class="hljs-attribute">display</span>: none;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
}
</code></pre>
<p>Here's the JavaScript code:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// 1. Change color of car and addToCart button color when a color is selected</span>
<span class="hljs-comment">// - Selecting Elements</span>
<span class="hljs-keyword">const</span> redColor = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".red"</span>);
<span class="hljs-keyword">const</span> grayColor = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"gray"</span>);
<span class="hljs-keyword">const</span> blackColor = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".black"</span>);
<span class="hljs-keyword">const</span> cartButton = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"button"</span>);
<span class="hljs-keyword">const</span> itemTag = <span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">"h3"</span>)[<span class="hljs-number">0</span>];
<span class="hljs-keyword">const</span> imageCard = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".product-image"</span>);
<span class="hljs-keyword">const</span> feedbackBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".feedback"</span>);

<span class="hljs-comment">// Modifying Elements</span>
<span class="hljs-comment">// - Add Event Listeners</span>
<span class="hljs-comment">// - Red Color</span>
redColor.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  cartButton.style.backgroundColor = <span class="hljs-string">"red"</span>;
  itemTag.style.backgroundColor = <span class="hljs-string">"red"</span>;
  imageCard.style.backgroundImage = <span class="hljs-string">'url("./img/red-benz.webp")'</span>;
});

<span class="hljs-comment">// - Gray Color</span>
grayColor[<span class="hljs-number">0</span>].addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  cartButton.style.backgroundColor = <span class="hljs-string">"gray"</span>;
  itemTag.style.backgroundColor = <span class="hljs-string">"gray"</span>;
  imageCard.style.backgroundImage = <span class="hljs-string">'url("./img/gray-benz.jpg")'</span>;
});

<span class="hljs-comment">// - Black Color</span>
blackColor.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  cartButton.style.backgroundColor = <span class="hljs-string">"black"</span>;
  itemTag.style.backgroundColor = <span class="hljs-string">"black"</span>;
  imageCard.style.backgroundImage = <span class="hljs-string">'url("./img/black-benz.jpg")'</span>;
});

<span class="hljs-comment">// Button Click Implementation</span>
<span class="hljs-comment">// - Cart Button</span>
<span class="hljs-keyword">const</span> cart = <span class="hljs-function">() =&gt;</span> {
  cartButton.style.display = <span class="hljs-string">"none"</span>;
  feedbackBtn.style.display = <span class="hljs-string">"block"</span>;
};
cartButton.addEventListener(<span class="hljs-string">"click"</span>, cart);

<span class="hljs-comment">// - Feedback Button</span>
<span class="hljs-keyword">const</span> feedback = <span class="hljs-function">() =&gt;</span> {
  cartButton.style.display = <span class="hljs-string">"block"</span>;
  feedbackBtn.style.display = <span class="hljs-string">"none"</span>;
};
feedbackBtn.addEventListener(<span class="hljs-string">"click"</span>, feedback);
</code></pre>
<h1 id="heading-conclusion">Conclusion</h1>
<p>The DOM is an essential part of modern web development because it helps developers transform websites and web applications from static to dynamic. </p>
<p>As a beginner, it can be quite hard to wrap your head around the DOM and all that it entails. Taking time to build a few simple projects like this will help you reinforce the concepts. </p>
<p>Thanks for reading 👋🏾. I hope you found it helpful.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create and Validate Modern Web Forms with HTML5 ]]>
                </title>
                <description>
                    <![CDATA[ HTML forms consist of a body of text boxes, buttons, dropdowns and other selection widgets. Web developers use these elements to receive users' information on a website.  If you've ever searched on Google, signed up or logged into a website, made a p... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-and-validate-modern-web-forms-html5/</link>
                <guid isPermaLink="false">66c5a3380efbb5075dbd11b0</guid>
                
                    <category>
                        <![CDATA[ HTML5 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Wed, 10 Aug 2022 15:45:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/08/Web-Forms-2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>HTML forms consist of a body of text boxes, buttons, dropdowns and other selection widgets. Web developers use these elements to receive users' information on a website. </p>
<p>If you've ever searched on Google, signed up or logged into a website, made a payment, or responded to a questionnaire, you have interacted with a web form.</p>
<p>When building for the web, you must ensure that your application is accessible to all users. This includes those who require assistive technologies such as screen readers to navigate a website. </p>
<p>HTML5 has semantic form elements which are the best way to achieve this. Thankfully, the benefits are beyond accessibility:</p>
<ol>
<li>They make it easier to develop because they come with some free functionality, and is generally easier to understand.</li>
<li>Better on mobile — semantic HTML is easier to make responsive for different screen sizes. Its file are generally lighter than non-semantic spaghetti code.</li>
<li>Good for SEO — your web page will have a higher chance of being found by customers because search engines prioritize keywords inside headings, links, and so on over those in non-semantic <code>&lt;div&gt;</code>s etc.</li>
</ol>
<p>In this article, we’re going to discuss the latest elements and attributes in HTML5 forms that you can use to build and validate the simple yet modern form you see here:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/HTML5Form.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You can see the source code <a target="_blank" href="https://codepen.io/ophyboamah/pen/wvmMagP">here</a>.</p>
<h1 id="heading-how-to-use-new-html5-form-elements">How to Use New HTML5 Form Elements</h1>
<p>Over the years, web forms have gone through various changes until the arrival of HTML5. </p>
<p>With the introduction of new and improved HTML5 elements and their attributes, anyone can learn to build beautiful, functional, and accessible forms. </p>
<p>Out of the numerous form elements, some of the most essential include:</p>
<h2 id="heading-form-outline-how-to-use-fieldset-legend-and-label-tags">Form Outline – How to Use Fieldset, Legend, and Label Tags</h2>
<p>You use the <code>&lt;fieldset&gt;</code> tag to group related elements (controls and labels) in a web form by drawing a box around them. It usually contains elements like legend, label and inputs. </p>
<p>You use the <code>&lt;legend&gt;</code> tag to define captions for fieldset elements. This way it can also be used as a way to group elements. And the <code>&lt;label&gt;</code> tag gives a definition to several elements.</p>
<p>You should always link the <code>&lt;label&gt;</code> tag to an <code>&lt;input&gt;</code> element because:</p>
<ol>
<li>A user can focus on the input by clicking the label</li>
<li>When the input is focused, screen readers read out the label to help differently-abled users.</li>
<li>For checkboxes, especially on mobile, users who aren't able to easily click on smaller items can click on the label to toggle the checkbox on.</li>
</ol>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">fieldset</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"first-section"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">legend</span>&gt;</span>Contact Details<span class="hljs-tag">&lt;/<span class="hljs-name">legend</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"name"</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">autofocus</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Ophy Boamah"</span> <span class="hljs-attr">autocomplete</span>=<span class="hljs-string">"on"</span> <span class="hljs-attr">required</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"ob2@hotmail.com"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"tel"</span>&gt;</span>Phone<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"tel"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tel"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"+233 200001212"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">fieldset</span>&gt;</span>
</code></pre>
<p>In the code above, we're using the fieldset tag to create an initial group tagged "first-section". The legend tag contains text that provides a description for the group of elements. Finally, the label tag identifies each of the inputs and their purpose.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Fieldset-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Fieldset, Legend, and Label</em></p>
<h2 id="heading-how-to-use-placeholder-text">How to Use Placeholder Text</h2>
<p>You use placeholder text within input fields, and it's only removed when the input field is focused or filled. </p>
<p>Usually, placeholder text has a lighter font color compared to the color of the input labels and values. You'll mostly use placeholders to give a user further insights as to what to fill out in a form. Here's an example:</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">"email"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"ob2@hotmail.com"</span>&gt;</span>
</code></pre>
<p>The type="email" attribute ensures that the input doesn't accept any other value than emails. The id attribute links the input element to its label to allow for association and focusing. The "ob2@hotmail.com" gives the user a hint of the kind of value the input expects.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Placeholder.png" alt="Image" width="600" height="400" loading="lazy">
<em>Email input placeholder</em></p>
<h2 id="heading-how-to-use-focus">How to Use Focus</h2>
<p>Initially, users had to click within the first input box in a form in order to start filling it out. But HTML5 lets web developers place emphasis on the inputs users should interact with first. </p>
<p>Autofocus is an attribute that you can add on an <code>&lt;input&gt;</code> or <code>&lt;textarea&gt;</code> element for this purpose. It's an important accessibility feature too because it makes life easier for people who use screen readers, for example.</p>
<p>Here's an example of how to use autofocus:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">autofocus</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">autofocus</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Ophy Boamah"</span> <span class="hljs-attr">required</span>&gt;</span>
</code></pre>
<p>As seen in the code above, you can put the autofocus attribute anywhere within the input tag. It's often followed or surrounded by the other generic attributes like name, id, and so on.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Focus.png" alt="Image" width="600" height="400" loading="lazy">
<em>Input focus</em></p>
<h1 id="heading-how-to-use-new-html5-inputs">How to Use New HTML5 Inputs</h1>
<p>It's probably safe to say that <code>&lt;input&gt;</code> is the most popular attribute of a web form. Actually, everything in a form is an input because it requires some form of data from users. You use this attribute the most to receive text, numbers and emails, and so on.</p>
<p>Various elements are differentiated using the value of the type attribute in inputs. Below are three new and useful examples:</p>
<h2 id="heading-how-to-use-the-search-element">How to Use the Search Element</h2>
<p>You use the search element to let users enter queries when they need to search for something. It is very similar to text inputs. </p>
<p>The main thing that differentiates them would be in the styling as accessing the input using the type input[type=search] tends to be super handy as compared to giving a text input a class.</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">"search"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"ob2@hotmail.com"</span>&gt;</span>
</code></pre>
<p>On certain browsers like Chrome, once you start typing, an 'x' icon is placed at the end of the input field. Clicking on this icon clears the value typed into the input and using the esc key on your keyboard gives the same result. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/search-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Search input</em></p>
<h2 id="heading-how-to-use-the-hidden-element">How to Use the Hidden Element</h2>
<p>Web developers use hidden elements to render an input's content hidden and inaccessible to a user interacting with a form. This input type doesn't exactly render visually. Its content is not seen by the user but upon submitting the form, its sent to the server.</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">"hidden"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"indexNumber"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"indexNumber"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"00202010"</span>&gt;</span>
</code></pre>
<h2 id="heading-how-to-use-the-progress-element">How to Use the Progress Element</h2>
<p>This is an element you can use to indicate the progress of a task. The max attribute is used to indicate the total value of the progress bar. The value attribute essentially shows the percentage of the task that's been completed by coloring in the bar to that extent. The id attribute, as always, is used to link to the the label.</p>
<pre><code class="lang-html"> <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"days"</span>&gt;</span>Proficiency:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">progress</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"days"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"27"</span> <span class="hljs-attr">max</span>=<span class="hljs-string">"100"</span>&gt;</span> 27% <span class="hljs-tag">&lt;/<span class="hljs-name">progress</span>&gt;</span>
</code></pre>
<p>Unlike the input with the type range, the progress element does not allow users to make changes. Instead, it communicates in a read-only style.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/progress.png" alt="Progress bar" width="600" height="400" loading="lazy">
<em>Progress bar</em></p>
<h2 id="heading-how-to-use-the-data-list-element">How to Use the Data List Element</h2>
<p>The data list element specifies a list of pre-defined options for an element. It's often used to offer autocomplete features for a list of items. This is because once you start typing, you get a preview of the list of options available. </p>
<p>As shown below, in order to link an <code>&lt;input&gt;</code> tag with a <code>&lt;datalist&gt;</code>, you have to ensure the value of the 'list' attribute is the same as the 'id' on the datalist. </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"gender"</span>&gt;</span>Gender ??<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">list</span>=<span class="hljs-string">"genders"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"gender"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"gender"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">datalist</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"genders"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"female"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"male"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"other"</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">datalist</span>&gt;</span>
</code></pre>
<p>This input is rendered differently on the various browsers:</p>
<p><strong>Chrome</strong>: Once you hover on the input, there's a dropdown icon added at the end of the input. When you click within the input or on the label, the values of the various options are also shown in a dropdown. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Datalist-Chrome.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><strong>Firefox</strong>: In order to see the option values, the user has to enter a part of the text and the options will be displayed in sort of an autocomplete style.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/datalist.png" alt="Image" width="600" height="400" loading="lazy">
<em>Data list</em></p>
<h1 id="heading-what-is-form-validation">What is Form Validation?</h1>
<p>Building the form is the first step in this process. As a developer, you have to always make sure that your users are providing accurate responses. This is necessary because you shouldn't assume that users will do the right thing. </p>
<p>This is the concept of validation in forms – preventing mistakes or catching them as soon as they happen.</p>
<h2 id="heading-types-of-form-validation">Types of Form Validation</h2>
<p>There are two popular types of validating a web form. They are:</p>
<h3 id="heading-client-side-validation">Client-side Validation</h3>
<p>Client-side validation can be linked to the 'preventing mistakes' part of validation. It involves strategies such as doing certain checks in the browser before submitting the form. </p>
<p>Methods of client-side validation include adding error popups and not letting a user proceed until they fill in the correct info.</p>
<h3 id="heading-server-side-validation">Server-side Validation</h3>
<p>Server-side validation can be linked to the 'catching mistakes' part of validation. </p>
<p>Unlike the client-side, this type doesn't check for errors while users are still on the form. Instead it checks when the form data is sent to your web server. </p>
<p>In this case, you'd show an error page as feedback to indicate the presence of errors.</p>
<h1 id="heading-popular-client-side-validation-methods">Popular Client-side Validation Methods</h1>
<h2 id="heading-basic-client-side-validation">Basic Client-side Validation</h2>
<p>Some examples of basic client-side validation include "This field is required", "Enter a valid email", and "Password should be at least 8 characters long".</p>
<p>These are just a few of the many error messages thrown at users when they don't enter data in the format a form expects. </p>
<p>The most commonly used of these attributes include:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Name-validation.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ol>
<li><strong>Required</strong>: Specifies input fields that need to be filled in before submitting the form.</li>
<li><strong>Minlength and Maxlength</strong>: Specify a string's minimum and maximum length expected.</li>
<li><strong>Min and Max</strong>: Specify the minimum and maximum values of numbers.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Email-Validation.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ol start="4">
<li><strong>Type</strong>: Specifies what kind of data is needed for specific input fields, for example date, number, name, email, and so on.</li>
</ol>
<h2 id="heading-the-constraint-validation-api">The Constraint Validation API</h2>
<p>As the name suggests, the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Constraint_validation">Constraint Validation API</a> is a Web API that offers validating features to web forms. You can use its new properties and methods to modify a form input's validity. </p>
<p>Developers can now easily give custom functionality and error messages. Basically, this API allows you to detect errors and display a custom message based on the type of error.</p>
<p>You can create custom validation and error messages with the setCustomValidity method as well as the validationMessage property.</p>
<h2 id="heading-other-helpful-elements-to-know">Other Helpful Elements to Know</h2>
<table>
<thead>
<tr>
<th>Element</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>autocomplete</code></td>
<td>You can use autocomplete to recall recently typed values in a given input. Besides sensitive data and one-time PINs, it's a time-saving feature. You can turn on its value to recommend it for a particular input field or vice versa.</td>
</tr>
<tr>
<td><code>autocorrect</code></td>
<td>Use these attributes to control automatic correction and capitalization features on some mobile devices (namely, the version of Safari that runs on iPads and iPhones)</td>
</tr>
<tr>
<td><code>spellcheck</code></td>
<td>You can set this attribute to true to indicate that the user should check the spelling of some text, especially strings typed in an input.  The only issue that comes from this is that not all text that is typed in the input is supposed to make sense as actual words.</td>
</tr>
</tbody>
</table>

<h1 id="heading-putting-it-all-together">Putting it All Together</h1>
<p>Here's the outcome of putting the various elements you've learned about in this article together:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/WebForm.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here's the code for that:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Bootcamp Registration<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"preconnect"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"preconnect"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"preconnect"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.gstatic.com"</span> <span class="hljs-attr">crossorigin</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600;700&amp;display=swap"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>&gt;</span> 
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Bootcamp Registration Form<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Complete this form to express your interest in the upcoming web development bootcamp.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
<span class="hljs-comment">&lt;!-- Contact Details --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">fieldset</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"first-section"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">legend</span>&gt;</span>Contact Details<span class="hljs-tag">&lt;/<span class="hljs-name">legend</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"name"</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">autofocus</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">autofocus</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Ophy Boamah"</span> <span class="hljs-attr">autocomplete</span>=<span class="hljs-string">"on"</span> <span class="hljs-attr">required</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"ob2@hotmail.com"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"tel"</span>&gt;</span>Phone<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"tel"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tel"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"+233 200001212"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">fieldset</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Personal Information --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">fieldset</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"second-section"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">legend</span>&gt;</span>Personal Information<span class="hljs-tag">&lt;/<span class="hljs-name">legend</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"dob"</span>&gt;</span>Birth Date<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"date"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"dob"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"gender"</span>&gt;</span>Gender ??<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">list</span>=<span class="hljs-string">"genders"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"gender"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"gender"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">datalist</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"genders"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"female"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"male"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"other"</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">datalist</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"proficiency"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"profeciency"</span>&gt;</span>Proficiency<span class="hljs-tag">&lt;/<span class="hljs-name">label</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">value</span>=<span class="hljs-string">"4"</span> <span class="hljs-attr">max</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"profeciency"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"profeciency"</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">fieldset</span>&gt;</span>
     <span class="hljs-comment">&lt;!-- Preferred Language --&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"terms"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"scales"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"scales"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"checkbox"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"scales"</span>&gt;</span>I have read and agree to the terms and conditions<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">button</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<pre><code class="lang-css">* {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Montserrat'</span>, sans-serif;
}

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">80vh</span>;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">5rem</span>;
  <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">"https://images.unsplash.com/photo-1595675024853-0f3ec9098ac7?ixlib=rb-1.2.1&amp;ixid=MnwxMjA3fDB8MHxzZWFyY2h8Nnx8Y29kaW5nJTIwYm9vdGNhbXB8ZW58MHx8MHx8&amp;auto=format&amp;fit=crop&amp;w=500&amp;q=60"</span>);
  <span class="hljs-attribute">background-repeat</span>: no-repeat;
  <span class="hljs-attribute">background-position</span>: center;
  <span class="hljs-attribute">background-size</span>: cover;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
}

<span class="hljs-selector-class">.form</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">15px</span> <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">80%</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
}

<span class="hljs-selector-class">.checkbox</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">20px</span> <span class="hljs-meta">!important</span>;
}

<span class="hljs-selector-class">.first-section</span> <span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">85%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">5px</span>;
}

<span class="hljs-selector-class">.second-section</span> <span class="hljs-selector-tag">input</span>{
  <span class="hljs-attribute">width</span>: <span class="hljs-number">80%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">5px</span>;
}

<span class="hljs-selector-class">.form</span> <span class="hljs-selector-tag">h1</span>, <span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">text-align</span>: center;
}
<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#1560BD</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">8px</span> <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">display</span>: block;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">20px</span> auto <span class="hljs-number">10px</span> auto;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">120px</span>;
}

<span class="hljs-selector-class">.second-section</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">15px</span>;
}

<span class="hljs-selector-class">.proficiency</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
}

<span class="hljs-selector-class">.terms</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">15px</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
}
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The new HTML5 form elements and attributes make it easy to access certain essential functionalities. Especially those that were otherwise only possible with CSS or many lines of JavaScript. </p>
<p>It's now easier than ever to create web forms that are both modern and functional with only HTML. Most importantly, it brings peace of mind to web developers. Because you know that you can easily create forms that will be uniform across the various browsers.</p>
<p>Thanks for reading 👋🏾. I hope you found this helpful.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Which Programming Language Should You Learn First? ]]>
                </title>
                <description>
                    <![CDATA[ As a code newbie, one of the most intimidating yet fundamental decisions to make is deciding which programming language to learn first.  There is a wide variety of languages, frameworks, and libraries that you'll easily find if you Google around. You... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/first-programming-language/</link>
                <guid isPermaLink="false">66c5a33bdd1f1e4092a32564</guid>
                
                    <category>
                        <![CDATA[ beginner ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Mon, 20 Jun 2022 22:35:17 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/06/what-language-to-learn-image.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As a code newbie, one of the most intimidating yet fundamental decisions to make is deciding which programming language to learn first. </p>
<p>There is a wide variety of languages, frameworks, and libraries that you'll easily find if you Google around. You'll agree though that wherever there are a lot of options to pick from, it's bound to lead to confusion. </p>
<p>This decision is important to discuss because it determines to a large extent the process and outcome of your journey as a developer. </p>
<p>In this article, we’ll discuss the four W questions to answer before picking your first programming language, as well as some helpful tips.</p>
<h2 id="heading-how-to-pick-a-programming-language-to-learn">How to Pick a Programming Language to Learn</h2>
<h3 id="heading-know-your-goals-for-learning-to-code-the-why">Know Your Goals for Learning to Code (The Why)</h3>
<p>Before worrying about what language to learn first, take a moment to consider the goal, or simply your why. </p>
<p>What’s the reason for wanting to learn programming, anyway? Is it to find a job, to automate your work, for a promotion, or for fun – or some combination? Your why should be the first factor to consider when selecting a language because that will serve as motivation to push through when the learning gets difficult.   </p>
<p>Your why will also help narrow down the programming language options you have. For instance, if you’re learning programming to perform better data analysis, then Python should be your go-to. But if your goal is to build for the web, you should learn JavaScript. Or if you’re looking to build native iOS applications, then SwiftUI is your best bet – and so on. </p>
<p>Your why could also be to make a transition and secure a job in a particular industry or company. In such cases, you may want to engage recruiters, senior developers, mentors and current employees. Find out what languages are preferred or may give you a higher chance of getting in and focus on learning one of those.</p>
<h3 id="heading-figure-out-your-time-constraints-the-when">Figure Out Your Time Constraints (The When)</h3>
<p>Contrary to what a lot of people think, learning to code isn't a get-rich-quick scheme. Learning to code takes time and intentional effort, and these must go hand-in-hand. </p>
<p>It can take months or even years to reach proficiency in any given language. That is assuming you're focused and put in the needed effort towards your studies.  </p>
<p>Before picking which language to learn, you'll need to identify your time frame. How long can you dedicate to working and waiting to ensure your dream of learning to code becomes reality? This can be a helpful guide to finding and focusing on languages that are known to be relatively easier to learn if you have limited time, and vice versa. </p>
<p>This is especially true for people who have important life deadlines such as securing a job, getting a promotion, or finishing a project by a given date. </p>
<p>It's always best to dedicate as much time as possible to your studies to avoid putting yourself under unnecessary pressure. And if there's no time limitation and nothing at stake, you may want to explore more complex object-oriented languages.</p>
<h3 id="heading-know-a-languages-potential-the-what">Know a Language's Potential (The What)</h3>
<p>The potential of a language is also an important deciding factor. Potential here refers to the job and freelance opportunities that will be available to you after you learn a particular programming language. It also measures how much employers require that language. </p>
<p>Learning to code in an in-demand programming language means that you become an in-demand developer, which gives you a lot of leverage and opportunities to make money (both by yourself or in a company). This is every developer's dream, unless learning to code as a hobby or for fun.</p>
<p>You can easily figure this out with any of these steps:</p>
<ol>
<li>Check a bunch of different job posts and their requirements – try GlassDoor or LinkedIn. <a target="_blank" href="https://www.linkedin.com/pulse/most-demand-programming-software-development-2022-michael-spencer-?trk=public_post-content_share-article">Here</a>'s an example from Linkedin. </li>
<li>Do a Google search for "Most In-Demand Programming Languages" and the current year (for example 2022) and check results from Reddit or Quora. </li>
<li>Check the StackOverflow Developer survey for the current or past years <a target="_blank" href="https://insights.stackoverflow.com/survey">here</a>.</li>
</ol>
<h3 id="heading-whats-the-support-for-the-language-the-who">What's the Support for the Language? (The Who)</h3>
<p>Look out for languages that are backed by credible institutions, communities, or individuals. They have a higher chance of being around for a longer time and being frequently maintained. </p>
<p>It's important that the language has a community backing it, too. This ensures its constantly maintained through open-source contributions. </p>
<p>This is particularly important because it shows that there are people who use the language and care about it enough to want to contribute to keeping it up-to-date.</p>
<p>Choosing a language with good support also means that should you encounter any difficulties, you will most likely find documented help for a similar error. Even if not, the probability of getting help quickly should still be high.</p>
<p>You shouldn’t follow the crowd and learn a language just because that’s what a lot of people are learning. Still, you don’t want to pick a language that doesn’t have a community you can get help from in case you face issues. In this case, it may be safe to say, the more the merrier.</p>
<h2 id="heading-choosing-a-programming-language-is-a-personal-decision">Choosing a Programming Language is a Personal Decision</h2>
<p>This article has been intentionally objective because different approaches work for different people. </p>
<p>You might be able to identify the language you want to learn based on these factors or not. After answering the questions raised above, you may still find that there are a number of options to pick from. It's very tempting to want to go with a language that is recommended by someone else. </p>
<p>However, try and make this decision by yourself. If you let someone else decide for you, it's very likely that when things go wrong you may regret the decision and start shifting blame. So that when the going gets tough, you'll remind yourself of your reasons and keep going.</p>
<h2 id="heading-focus-on-programming-fundamentals">Focus on Programming Fundamentals</h2>
<p><a target="_blank" href="https://www.freecodecamp.org/news/how-to-think-like-a-programmer-lessons-in-problem-solving-d1d8bf1de7d2/">Problem-solving</a> is the most important skill any developer can cultivate. This is followed by knowing the fundamentals of programming in general. No language is more important than this. </p>
<p>Languages come and go, but these skills help you easily switch or pick up a new language when needed. </p>
<p>You’ll come to find that many times, your strength as a programmer will be measured by how well you’re able to adapt to change. </p>
<p>Even for employers, the majority are more likely to employ a developer who knows how to solve problems programmatically and learn quickly, over one who just knows any specific language.</p>
<h2 id="heading-you-cant-go-wrong-with-html-and-css">You Can’t Go Wrong with HTML and CSS</h2>
<p>There are a lot of people who argue that HTML and CSS are not "programming languages". But as the building blocks of the web, they are the foundation that you can build upon anytime. </p>
<p>This makes them safe to learn, even when you’ve still not decided what other language to start with. Almost all developers start learning from the web before topping up with other programming languages and eventually frameworks.</p>
<h3 id="heading-what-is-html">What is HTML?</h3>
<p>Hyper Text Markup Language refers to the basic building blocks used to structure a web page. For example, its content could be structured within a set of paragraphs, a list of bulleted points, or using images and data tables. </p>
<h3 id="heading-what-is-css">What is CSS?</h3>
<p>Cascading Style Sheets is used to beautify HTML code. It lets you style the elements of your web page and lay them out in certain ways so that your code looks prettier.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Rest assured that these points will be relevant many years from now. The factors discussed above should give you the most effective methods to select your first programming language. </p>
<p>And even though I've put a lot of emphasis on selecting a language, this isn't the end of the story or of the decisions you'll have to make as a new developer. </p>
<p>It's only the first step and you'll have to sustain your learning and development with commitment and hard work. Whichever language you choose – and however hard you work – will ultimately determine how fast you achieve your goal. If you focus and work through a language methodically, it'll help keep you from jumping from one programming language to the other. </p>
<p>Thanks for reading 👋🏾. I hope you found this helpful.  </p>
<p>Let's connect on <a target="_blank" href="https://twitter.com/ophyboamah">Twitter</a> or <a target="_blank" href="https://linkedin.com/in/opheliaboamahampoh">LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
