<?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" version="2.0"><channel><title><![CDATA[Untitled Publication]]></title><description><![CDATA[Writing articles for HTML, CSS and JavaScript projects that are clear and easy to understand.]]></description><link>https://blog.achulslander.com</link><generator>RSS for Node</generator><lastBuildDate>Sun, 12 Apr 2026 06:35:41 GMT</lastBuildDate><atom:link href="https://blog.achulslander.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Make a Shimmer Load Effect - HTML, SCSS]]></title><description><![CDATA[Want to spice up your loading screen? Follow along and we'll make a nice, shimmery loading effect like this one:

We're going to be making a product card with an image, heading, sub-heading and description elements. Below you'll find the starter HTML...]]></description><link>https://blog.achulslander.com/shimmer-load-effect</link><guid isPermaLink="true">https://blog.achulslander.com/shimmer-load-effect</guid><category><![CDATA[HTML5]]></category><category><![CDATA[scss]]></category><category><![CDATA[Shimmer Effect]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[CSS Animation]]></category><dc:creator><![CDATA[AC Hulslander]]></dc:creator><pubDate>Mon, 22 May 2023 21:44:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/a9NQ6z1zqro/upload/4140d7fc68a1712bfac7ad4dba53bac1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Want to spice up your loading screen? Follow along and we'll make a nice, shimmery loading effect like this one:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684789593036/b33b5bf3-983e-4d3a-995c-8e248bd52664.gif" alt class="image--center mx-auto" /></p>
<p>We're going to be making a product card with an image, heading, sub-heading and description elements. Below you'll find the starter HTML and SCSS.</p>
<p>If you get confused along the way, <a target="_blank" href="https://codepen.io/alleycaaat/pen/zYmyeMR?editors=1100">you can check out the finished code here</a>.</p>
<h3 id="heading-quick-terminology-break">Quick terminology break</h3>
<p>What is a CSS <strong>animation</strong>? It's used to gradually change from one style to another. When using <code>animation</code>, as opposed to <code>transition</code> or <code>transform</code>, you need to use <a target="_blank" href="https://www.w3schools.com/cssref/css3_pr_animation-keyframes.php">keyframes</a>, which contain the different styles that will be applied to the element.</p>
<p>Alright, let's move on to the starter code!</p>
<h2 id="heading-html">HTML</h2>
<pre><code class="lang-xml">    <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">'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-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">'desc-wrapper'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">'heading'</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> <span class="hljs-attr">class</span>=<span class="hljs-string">'desc'</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> <span class="hljs-attr">class</span>=<span class="hljs-string">'desc'</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> <span class="hljs-attr">class</span>=<span class="hljs-string">'desc'</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> <span class="hljs-attr">class</span>=<span class="hljs-string">'desc'</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> <span class="hljs-attr">class</span>=<span class="hljs-string">'desc'</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">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">main</span>&gt;</span>
</code></pre>
<p>Note the five <code>p</code> elements with <code>.desc</code>, they can be used to hold product information such as price, color, quantity et cetera. You can use more than one <code>p</code> element to get the multi-line effect, or use a single <code>p</code> that's bigger (to take up more space and have a fluid transition to the actual content) if you're using full paragraphs of text.</p>
<h2 id="heading-scss">SCSS</h2>
<pre><code class="lang-scss"><span class="hljs-selector-class">.card</span> {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">flex-direction</span>: column;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">325px</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">500px</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-selector-class">.product-image</span> {
        <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
        <span class="hljs-attribute">height</span>: <span class="hljs-number">250px</span>;
        <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span> <span class="hljs-number">5px</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span>;
    }
    <span class="hljs-selector-class">.desc-wrapper</span> {
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">5px</span> <span class="hljs-number">25px</span>;
        <span class="hljs-selector-class">.heading</span> {
            <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
            <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;
            <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">25px</span>;
            <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50px</span>;
        }
        <span class="hljs-selector-class">.desc</span> {
            <span class="hljs-attribute">height</span>: <span class="hljs-number">16px</span>;
            <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50px</span>;
            <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
            <span class="hljs-attribute">margin</span>: <span class="hljs-number">15px</span> <span class="hljs-number">0</span>;
        }
    }
}
</code></pre>
<p>Feel free to adjust the HTML or SCSS to fit your needs, just make sure all elements of the loading effect will be applied to have a <code>height</code> and <code>width</code> property, otherwise they won't be visible until they're filled with content.</p>
<h3 id="heading-okay-onward-to-the-fun-stuff">Okay, onward to the fun stuff!</h3>
<p>We want the <code>product-image</code>, <code>heading</code>, <code>sub-heading</code> and <code>desc</code> elements to shimmer while they're waiting for data to display, so we'll give each of them a <code>.shimmer</code> in our HTML. Now let's define <code>.shimmer</code> in our SCSS and make the magic happen!</p>
<p>I'll start off with the full code for the <code>animation</code> styles, and the finished product will have the <a target="_blank" href="https://www.w3schools.com/css/css3_animations.asp">shorthand animation property</a>. Below is an example from the previous link. It condenses this:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">animation-name</span>: example;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">5s</span>;
  <span class="hljs-attribute">animation-timing-function</span>: linear;
  <span class="hljs-attribute">animation-delay</span>: <span class="hljs-number">2s</span>;
  <span class="hljs-attribute">animation-iteration-count</span>: infinite;
  <span class="hljs-attribute">animation-direction</span>: alternate;
}
</code></pre>
<p>into this:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">animation</span>: example <span class="hljs-number">5s</span> linear <span class="hljs-number">2s</span> infinite alternate;
}
</code></pre>
<p>It's a big space saver, but feel free to use the longhand version if you wish!</p>
<p>Our <code>.shimmer</code> will be pretty straightforward, there are a few key features to make it work though.</p>
<h3 id="heading-animation">animation</h3>
<p>I named it <code>shimmering</code>, which will be used later for the <code>keyframes</code>. Duration is up to you, I think something between two and four seconds looks best; if you go much longer, the user may not even see the loading effect. Along the same vein, I didn't want a delay. I kept the speed even for the duration, and set it so the animation loops for as long as it takes to load the content. Here's what that looks like in longhand:</p>
<pre><code class="lang-css">  <span class="hljs-selector-class">.shimmer</span> {
    <span class="hljs-attribute">animation-name</span>: shimmering;
    <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">2.1s</span>;
    <span class="hljs-attribute">animation-iteration-count</span>: infinite;
    <span class="hljs-attribute">animation-timing-function</span>: linear;
}
</code></pre>
<p>and shorthand:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.shimmer</span> {
    <span class="hljs-attribute">animation</span>: shimmering <span class="hljs-number">2.1s</span> linear infinite;
}
</code></pre>
<h4 id="heading-weve-got-our-animation-but-what-is-it-yknow-animating">We've got our animation, but what is it, y'know, <em>animating</em>?</h4>
<p>The background!<br />... Wait, what?<br />Okay, a really <strong><em>big</em></strong> background!<br />...<br />I'll explain: to make the elements look like they're shimmering, we're going to have an oversized <code>linear-gradient</code> background that will repeatedly move from left to right. Still a little confused? Me too, let's crack on!</p>
<h3 id="heading-background-size">background-size</h3>
<p>We're going to add a declaration to <code>.shimmer</code> to give us the really big background: <code>background-size: 1300px 100%</code>. The first value of <code>background-size</code> is the <code>width</code>, and we want that to be at least twice the value of the element that this class is being applied to. Why the oversized background? Without it, the shimmer effect will loop much faster and it won't look as nice, like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684788389128/bac848cd-fcb8-4b08-a12a-5666e102389c.gif" alt class="image--center mx-auto" /></p>
<h3 id="heading-linear-gradient">linear-gradient</h3>
<p>Now let's color in that really big background with a <code>linear-gradient</code>, this part can be fiddley. You'll need two different colors, light and dark. You don't want too much difference between the colors, or it may not end up looking like a shimmery highlight. The dark color will sandwich the light color, causing the highlight effect.</p>
<p>For best results, keep the highest percentage below 50%, and the difference from lowest to highest less than 30% difference. We want the shimmer to happen at the beginning of the animation, and if the highlight is too far away from the darker colors, it fades out and the effect is quite weak. The example below demonstrates <code>background: linear-gradient(90deg, rgba(226, 226, 226, 1) 9%, rgba(238, 238, 238,1) 48%, rgba(226, 226, 226, 1) 71%)</code>. You may need to watch closely to catch the animation, it's quite subtle.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684789023030/bade9abc-9ee3-4fde-ad62-c9c5846dd06b.gif" alt class="image--center mx-auto" /></p>
<p>If you need some help creating a gradient, I love <a target="_blank" href="https://cssgradient.io/">CSS Gradient</a>. It's an easy-to-use generator that provides maximum compatibility code. Tip: If you want to add another color to the gradient, simply move your cursor over the long slider bar and left-click where there isn't already a marker.</p>
<p>So we have our really big gradient background (allegedly, we can't see it!) but it's not doing anything. Time to change that.</p>
<h3 id="heading-keyframes">keyframes</h3>
<p>I said our background is going to move from left to right, and it will carry the highlight across the element with this movement. To achieve this, we're going to utilize the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/background-position">background-position</a>. At 0% we want our background to be fully hidden to the left, achieved by using the same <code>width</code> value as our <code>background-size</code> (be sure to use a negative value to move it to the left along the x-axis!). At 100% it'll be in the default place, covering the entire element.</p>
<h3 id="heading-lets-put-it-all-together-now">Let's put it all together now</h3>
<pre><code class="lang-scss"><span class="hljs-variable">$light</span>: rgba(<span class="hljs-number">238</span>,<span class="hljs-number">238</span>,<span class="hljs-number">238</span>,<span class="hljs-number">1</span>);
<span class="hljs-variable">$dark</span>: rgba(<span class="hljs-number">226</span>,<span class="hljs-number">226</span>,<span class="hljs-number">226</span>,<span class="hljs-number">1</span>);

<span class="hljs-keyword">@keyframes</span> shimmering {
    0% {
        <span class="hljs-attribute">background-position</span>: -<span class="hljs-number">1300px</span> <span class="hljs-number">0</span>;
    }
    100% {
        <span class="hljs-attribute">background-position</span>: <span class="hljs-number">1300px</span> <span class="hljs-number">0</span>;
    }
}

<span class="hljs-selector-class">.shimmer</span> {
    <span class="hljs-attribute">animation</span>: shimmering <span class="hljs-number">3.1s</span> linear infinite;
    <span class="hljs-attribute">background</span>: <span class="hljs-variable">$dark</span>;
    <span class="hljs-attribute">background</span>: linear-gradient(<span class="hljs-number">90deg</span>, <span class="hljs-variable">$dark</span> <span class="hljs-number">9%</span>, <span class="hljs-variable">$light</span> <span class="hljs-number">18%</span>, <span class="hljs-variable">$dark</span> <span class="hljs-number">31%</span>);
    <span class="hljs-attribute">background-size</span>: <span class="hljs-number">1300px</span> <span class="hljs-number">100%</span>;
}
</code></pre>
<p>Congrats, you did it! You made a fancy little loading effect! If you followed along, feel free to leave a comment and share a link to your code. Let me know if you have any questions or a suggestion for another tutorial.</p>
]]></content:encoded></item><item><title><![CDATA[Configure External DNS for Netlify]]></title><description><![CDATA[Today we're going to learn how to use a custom domain name for a site hosted on Netlify.com.
When using Netlify, there are several options for a domain.

Sites are generated with a free sub-domain, no purchase necessary

Purchase one through Netlify ...]]></description><link>https://blog.achulslander.com/configure-external-dns-for-netlify</link><guid isPermaLink="true">https://blog.achulslander.com/configure-external-dns-for-netlify</guid><category><![CDATA[dns]]></category><category><![CDATA[namecheap]]></category><category><![CDATA[Netlify]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[AC Hulslander]]></dc:creator><pubDate>Thu, 02 Mar 2023 18:53:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/IjgAMDFXIiI/upload/2dba97538ef1b81fa70134327b842fd3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today we're going to learn how to use a custom domain name for a site hosted on <a target="_blank" href="https://netlify.com">Netlify.com</a>.</p>
<p>When using Netlify, there are several options for a domain.</p>
<ul>
<li><p>Sites are generated with a free sub-domain, no purchase necessary</p>
</li>
<li><p>Purchase one through Netlify and use their DNS</p>
</li>
<li><p>Purchase one elsewhere and use the domain name provider's DNS</p>
</li>
</ul>
<p>I'm going to be talking about the latter, specifically with a <a target="_blank" href="https://namecheap.com">Namecheap.com</a> domain name.</p>
<p>Let's cover some vocabulary before we get started.</p>
<p><strong>Domain name</strong> - a human readable form of an IP address, the destination a user types into their browser.<br /><strong>DNS</strong> or <strong>domain name system</strong> - translates human readable domain names to machine readable IP addresses.<br /><strong>Apex domain</strong> - a custom domain that does not contain a subdomain such as <code>example.com.</code> Also called bare, base, or root domain.<br /><strong>Subdomain</strong> - a part of another domain, used to organize and navigate to different parts of a website such as blog, store or help. 'www' is a subdomain.</p>
<blockquote>
<p>This tutorial is written from the perspective that you already have a Netlify account and a site created. If you haven't done this yet, please visit <a target="_blank" href="https://netlify.com">Netlify.com</a> to create an account and a site first.</p>
</blockquote>
<hr />
<h2 id="heading-namecheap">Namecheap</h2>
<p>Let's get started. Go to <a target="_blank" href="https://namecheap.com">Namecheap</a> (create an account if you don't have one), and purchase a domain name. For this example, we'll use my website, achulslander.com.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677090876224/1b8036f2-0611-45cc-b466-72d74783049e.png" alt class="image--center mx-auto" /></p>
<p>After purchasing your domain, you'll be directed to your products page. If you've previously bought a domain, log in to your account; your dashboard should come up and show your domain name. Select the <strong>manage</strong> button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677090861626/1d346a74-6e3d-4ab8-bda8-726f03e41137.png" alt class="image--center mx-auto" /></p>
<p>Then select the <strong>Advanced DNS</strong> tab.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677092179751/81437163-7a25-46f7-a312-1549c0695074.png" alt class="image--center mx-auto" /></p>
<p>Now find the <strong>Add New Record</strong> button and click it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677092793917/2db8c96a-cfdf-4d81-9ae2-5ea0034a05e0.png" alt class="image--center mx-auto" /></p>
<p>We need to add two records. The first is going to be an <strong>A record</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677093008149/d5a97d8c-66be-493f-90d3-b50a0a5b8dfc.png" alt class="image--center mx-auto" /></p>
<p>And we'll enter this information:</p>
<pre><code class="lang-plaintext">Type: A Record
Host: @
Value: 75.2.60.5
TTL: 5 min
</code></pre>
<p>Save that by selecting the <strong>checkmark</strong> to the right, and then click the <strong>Add New Record</strong> button again. This time select <strong>CNAME record</strong> from the drop-down and enter the following:</p>
<pre><code class="lang-plaintext">Type: CNAME record
Host: www
Value: [name-of-your-site].netlify.app
TTL: 5 min
</code></pre>
<p><em>(Value will be the address Netlify has generated for your website.)</em><br />And save it by clicking the <strong>checkmark</strong>.</p>
<p><em>So... What did we just do?</em></p>
<p>In simple terms, the <strong>A record</strong> is the IP address where Netlify can be found online. The <strong>CNAME record</strong> will point our domain name to that IP address. When users visit your domain name, they'll end up in the correct place because of these records.</p>
<hr />
<h2 id="heading-netlify">Netlify</h2>
<p>Now we move to Netlify.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677093840840/198888e5-07a4-4e94-96bc-8a2d2c44b9fa.png" alt class="image--center mx-auto" /></p>
<p>Log in to your account and navigate to the <strong>Sites</strong> tab, then click the <strong>existing site</strong> you wish to add a domain name to.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677095004687/b2ecd9ad-b349-4d5f-8755-2794b844afde.png" alt class="image--center mx-auto" /></p>
<p>From the Site Overview page, click <strong>Domain Settings</strong>, then click the <strong>Add a domain</strong> button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677095924587/08a4611d-0e2e-4175-9631-b5e0b5628b5a.png" alt class="image--center mx-auto" /></p>
<p>Enter the <strong>domain name</strong> you registered on Namecheap and click the <strong>Verify</strong> button. You should get a prompt of text below the input box letting you know the domain name is already registered, and the verify button will change to read <strong>Add domain</strong>. Click that <strong>Add domain</strong> button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677097033089/3ccc4bcb-48a9-42a9-bfba-a3579fdbd5db.png" alt class="image--center mx-auto" /></p>
<p>Here's an important step: select the bottom <strong>Options</strong> drop-down and select <strong>Set as primary domain</strong> to remove the apex domain as the primary. This sets our primary domain to <code>www.example.com</code>, instead of the bare domain of <code>example.com</code>. Why does that matter? With Netlify, using a subdomain as the primary allows your site to fully utilize their <a target="_blank" href="https://www.netlify.com/blog/2016/04/15/make-your-site-faster-with-netlifys-intelligent-cdn/#main">CDN</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677098627306/ddca981a-67a6-4005-b01d-bbcfad3e1059.png" alt class="image--center mx-auto" /></p>
<p>Now we can scroll down to the bottom of the page to the <strong>HTTPS</strong> section where our SSL certificate is being provisioned.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677102075143/c95c7fe6-16cb-426c-aee7-7532b431a534.png" alt class="image--center mx-auto" /></p>
<p>If this does not happen automatically, click the <strong>Verify DNS Configuration</strong> button, then the <strong>Provision certificate</strong> button. You may receive a pop-up asking you to confirm by again clicking a <strong>Provision certificate</strong> button.</p>
<p>After a few minutes, our site has HTTPS enabled! Congrats, you did it!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677170960832/cb501255-13a4-43cd-a50a-463f63e3c227.png" alt class="image--center mx-auto" /></p>
<p>Let me know if you have any questions :)</p>
<h3 id="heading-further-reading">Further Reading</h3>
<p><a target="_blank" href="https://docs.netlify.com/domains-https/custom-domains/configure-external-dns/?_ga=2.232211993.728009905.1677097850-1741996428.1673208867">Configure external DNS for a custom domain</a><br /><a target="_blank" href="https://www.netlify.com/blog/2020/03/26/how-to-set-up-netlify-dns-custom-domains-cname-and-a-records/">How to Set Up Netlify DNS - Custom Domains, CNAME, &amp; A Records</a><br /><a target="_blank" href="https://answers.netlify.com/t/support-guide-troubleshooting-ssl-certificate-errors/39865">[Support Guide] Troubleshooting SSL certificate errors</a></p>
]]></content:encoded></item><item><title><![CDATA[How to Make an Accordion FAQ with JS - part 3]]></title><description><![CDATA[In the final step of building our accordion FAQ, we'll add styling to our FAQ project and make it a little easier on the eyes. We'll also have the double chevron to rotate to indicate the direction of movement. Currently, our SCSS looks like this:
.a...]]></description><link>https://blog.achulslander.com/how-to-make-an-accordion-faq-with-js-part-3</link><guid isPermaLink="true">https://blog.achulslander.com/how-to-make-an-accordion-faq-with-js-part-3</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[scss]]></category><category><![CDATA[Accessibility]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[AC Hulslander]]></dc:creator><pubDate>Wed, 04 May 2022 17:23:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/_ASImGUewVM/upload/f6c05be94da0e9d58d7258a8ac7f6392.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the final step of building our accordion FAQ, we'll add styling to our FAQ project and make it a little easier on the eyes. We'll also have the double chevron to rotate to indicate the direction of movement. Currently, our SCSS looks like this:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.answer</span> {
    <span class="hljs-attribute">display</span>: none;
}
<span class="hljs-selector-class">.clicked</span> {
    <span class="hljs-selector-class">.answer</span> {
        <span class="hljs-attribute">display</span>: block;
  }
}
</code></pre>
<p>It's pretty boring, so let's get to work!</p>
<h1 id="heading-scss">SCSS</h1>
<p>Inside our <code>body</code> we're going to have our <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/main#:~:text=The%20HTML%20element%20represents,central%20functionality%20of%20an%20application."><code>main</code></a> that will have a <code>class</code> of <code>container</code>. I set the <code>width</code> to 80vw as I like to set an element's size based on the view's screen size versus a hard number in pixels. The <code>margins</code> are set to auto to keep the container centered save for the top, it's 50px, so the container is dropped down from the top of the screen a bit. Here's the code I ended up with:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.container</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">80vw</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-attribute">margin</span>: <span class="hljs-number">50px</span> auto auto auto;
}
</code></pre>
<p>As I mentioned in part 1, the questions themselves are <code>article</code>s, and will be given a <code>class</code> of <code>q</code>, and the <code>article</code>s will contain a <code>div .title</code>, <code>h2</code> that's the question, our <code>button</code>, a second <code>div</code> with <code>.answer</code> and it will hold a <code>p</code> with the answer to the question.</p>
<p>To keep the code DRY I put some default styles on <code>div</code> like so:</p>
<pre><code class="lang-scss"><span class="hljs-selector-tag">div</span> {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">margin-left</span>: auto;
    <span class="hljs-attribute">margin-right</span>: auto;
    <span class="hljs-attribute">justify-content</span>: center;
    <span class="hljs-attribute">align-items</span>: center;
}
</code></pre>
<p><code>.q</code> has a<code>border-radius</code> of 5px to soften the corners, and I added a <code>box-shadow</code> to give it some depth. To keep my code cleaner I used a variable to add shadows (just one of the great things about Sass/SCSS!); in this instance it's <code>$boxshadow: 0 14px 12px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);</code>, so my <code>.q</code> looks like:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.q</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">background-color</span>: lavender;
    <span class="hljs-attribute">color</span>: <span class="hljs-variable">$purple</span>; <span class="hljs-comment">//variable for #732091</span>
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
    <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">3px</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">5px</span> <span class="hljs-number">5px</span> <span class="hljs-number">17px</span> <span class="hljs-number">5px</span>; <span class="hljs-comment">//bottom margin is larger to accomodate the box-shadow</span>
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">25px</span>;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
    <span class="hljs-attribute">box-shadow</span>: <span class="hljs-variable">$boxshadow</span>;
}
</code></pre>
<p>Inside <code>.q</code> I nested the <code>h2</code> that will be used to hold the question. Notice the <code>margin</code> set to auto to keep the <code>button</code> to the right.</p>
<pre><code class="lang-scss"><span class="hljs-selector-tag">h2</span> {
   <span class="hljs-attribute">padding</span>: <span class="hljs-number">7px</span>;
   <span class="hljs-attribute">font-size</span>: <span class="hljs-number">23px</span>;
   <span class="hljs-attribute">margin</span>: auto;
}
</code></pre>
<p>The <code>button</code>s are next, I gave them a <code>margin-right</code> of 10px to nudge them in a little and <code>transition: transform .5s ease-in-out</code> to soften the transitions between movements. Here's the final result:</p>
<pre><code class="lang-scss"><span class="hljs-selector-tag">button</span> {
    <span class="hljs-attribute">cursor</span>: pointer;
    <span class="hljs-attribute">background-color</span>: rgba(<span class="hljs-number">255</span>,<span class="hljs-number">255</span>,<span class="hljs-number">255</span>,<span class="hljs-number">0</span>); <span class="hljs-comment">//removes the background color</span>
    <span class="hljs-attribute">border</span>: <span class="hljs-number">0px</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">1px</span> <span class="hljs-number">7px</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-variable">$purple</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">25px</span>;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
    <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">text-align</span>: center;
    <span class="hljs-attribute">transition</span>: transform .<span class="hljs-number">5s</span> ease-in-out; 
}
</code></pre>
<p>I gave my <code>button</code>s all <code>.qb</code> (for question button) so I could grab them with the JavaScript to add the rotation.</p>
<p>Nested in <code>button</code> I have <code>img</code>, which is what holds the double chevron. The image I used is larger than what I need, so I set the <code>height</code> and let the <code>width</code> figure itself out:</p>
<pre><code class="lang-scss"><span class="hljs-selector-tag">img</span> {
    <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;
    <span class="hljs-attribute">width</span>: auto;
 }
</code></pre>
<p>You may not need to do this, it'll depend on the image you select.</p>
<p>Now let's move on to <code>.answer</code>. The most important thing to have is what we set up in part 1: <code>display: none</code> so the answers aren't visible. Everything else is just preferences.</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.answer</span> {
    <span class="hljs-attribute">display</span>: none;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">13px</span>;
    <span class="hljs-attribute">background-color</span>: lavender;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">300</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">18px</span>;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
}
</code></pre>
<p>Last is a <code>class</code> that will be added or removed via <code>onClick</code> that will turn the chevron.</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.rotate</span> {
    <span class="hljs-attribute">transform</span>: rotate(<span class="hljs-number">180deg</span>);
}
</code></pre>
<p>Our SCSS is looking pretty good! Now it's time to finish up the JavaScript.</p>
<h1 id="heading-javsscriptmobile">JavsScriptmobile</h1>
<p>We need to get access to the chevrons to turn them: we need to add <code>const arrow=quest.querySelector('.qb');</code> to our JavaScript inside <code>forEach</code>. Next, we'll jump a few lines down into <code>addEventListener</code> where we can toggle the <code>rotate</code> class we just made on <code>arrow</code> like so: <code>arrow.classList.toggle('rotate');</code>. We're using <code>toggle</code> because it's perfect in this situation: if the <code>.rotate</code> isn't present, it's added, otherwise it's removed. Let's take a look at our project:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665610029897/MSwlYS-U-.gif" alt="FAQ-js.gif" /></p>
<p>If you've made it this far, congrats! You made an accessible accordion FAQ using HTML, SCSS and JavaScript!</p>
<p>Here's the complete code used in this three part tutorial:</p>
<h3 id="heading-html">HTML</h3>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</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">article</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"q"</span> <span class="hljs-attr">aria-expanded</span>=<span class="hljs-string">"false"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"title"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>What's the difference between a hippo and a zippo?<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"qb"</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"toggle answer"</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.ibb.co/KKmX2q3/chevron.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"chevron"</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> <span class="hljs-attr">class</span>=<span class="hljs-string">"answer"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>One is really heavy, the other is a little lighter.<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">article</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
</code></pre>
<h3 id="heading-scss-1">SCSS</h3>
<pre><code class="lang-scss"><span class="hljs-variable">$boxshadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">14px</span> <span class="hljs-number">12px</span> <span class="hljs-number">0</span> rgba(<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-number">0</span> <span class="hljs-number">6px</span> <span class="hljs-number">20px</span> <span class="hljs-number">0</span> rgba(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.19</span>);
<span class="hljs-variable">$purple</span>: <span class="hljs-number">#732091</span>;

<span class="hljs-selector-class">.container</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">80vw</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-attribute">margin</span>: <span class="hljs-number">50px</span> auto auto auto;
}
<span class="hljs-selector-tag">div</span> {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">margin-left</span>: auto;
    <span class="hljs-attribute">margin-right</span>: auto;
    <span class="hljs-attribute">justify-content</span>: center;
    <span class="hljs-attribute">align-items</span>: center;
}
<span class="hljs-selector-class">.answer</span> {
    <span class="hljs-attribute">display</span>: none;
}
<span class="hljs-selector-class">.clicked</span> {
    <span class="hljs-selector-class">.answer</span> {
        <span class="hljs-attribute">display</span>: block;
    }
}
<span class="hljs-selector-class">.q</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">background-color</span>: lavender;
    <span class="hljs-attribute">color</span>: <span class="hljs-variable">$purple</span>;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
    <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">3px</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">5px</span> <span class="hljs-number">5px</span> <span class="hljs-number">17px</span> <span class="hljs-number">5px</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">25px</span>;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
    <span class="hljs-attribute">box-shadow</span>: <span class="hljs-variable">$boxshadow</span>;
    <span class="hljs-selector-class">.title</span> {
        <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    }
    <span class="hljs-selector-tag">h2</span> {
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">7px</span>;
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">23px</span>;
        <span class="hljs-attribute">margin</span>: auto;
    }
}
<span class="hljs-selector-tag">button</span> {
    <span class="hljs-attribute">cursor</span>: pointer;
    <span class="hljs-attribute">background-color</span>: rgba(<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">0</span>);
    <span class="hljs-attribute">border</span>: <span class="hljs-number">0px</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">1px</span> <span class="hljs-number">7px</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-variable">$purple</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">25px</span>;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
    <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">text-align</span>: center;
    <span class="hljs-attribute">transition</span>: transform .<span class="hljs-number">5s</span> ease-in-out;
    <span class="hljs-selector-tag">img</span> {
        <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;
        <span class="hljs-attribute">width</span>: auto;
    }
}
<span class="hljs-selector-class">.answer</span> {
    <span class="hljs-attribute">display</span>: none;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">13px</span>;
    <span class="hljs-attribute">background-color</span>: lavender;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">300</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">18px</span>;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
}
<span class="hljs-selector-class">.rotate</span> {
    <span class="hljs-attribute">transform</span>: rotate(<span class="hljs-number">180deg</span>);
}
</code></pre>
<h3 id="heading-javascript">JavaScript</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> question=<span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">'.q'</span>);

question.forEach(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">quest</span>) </span>{
  <span class="hljs-keyword">const</span> btn=quest.querySelector(<span class="hljs-string">'button'</span>);
  <span class="hljs-keyword">let</span> arrow=quest.querySelector(<span class="hljs-string">'.qb'</span>);

  btn.addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{

    quest.classList.toggle(<span class="hljs-string">'clicked'</span>);
    arrow.classList.toggle(<span class="hljs-string">'rotate'</span>);

    <span class="hljs-keyword">let</span> ariaValue=quest.getAttribute(<span class="hljs-string">'aria-expanded'</span>);
    ariaValue = (ariaValue === <span class="hljs-string">'false'</span> ? quest.setAttribute(<span class="hljs-string">'aria-expanded'</span>, <span class="hljs-string">'true'</span>) : quest.setAttribute(<span class="hljs-string">'aria-expanded'</span>, <span class="hljs-string">'false'</span>);
  });

});
</code></pre>
<p>I added a few more styles to my <a target="_blank" href="https://codepen.io/alleycaaat/pen/bGazoZa">finished project</a>, feel free to adjust the styles to your taste. If you've made your own accordion FAQ, please leave a link in the comments! Let me know if you have any questions.</p>
]]></content:encoded></item><item><title><![CDATA[How to Make an Accordion FAQ with JS - part 2]]></title><description><![CDATA[This is part two of my three-part accordion FAQ tutorial. Part two is on accessibility, part three is on making the project look pretty. Why? Because I believe accessibility (a11y) is more important, making sure everyone can use something is more imp...]]></description><link>https://blog.achulslander.com/make-an-accordion-faq-with-js-part-2</link><guid isPermaLink="true">https://blog.achulslander.com/make-an-accordion-faq-with-js-part-2</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Accessibility]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[a11y]]></category><dc:creator><![CDATA[AC Hulslander]]></dc:creator><pubDate>Wed, 27 Apr 2022 19:07:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/uePn9YCTCY0/upload/v1651086086305/lLOcGhXFq.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is part two of my three-part accordion FAQ tutorial. Part two is on accessibility, <a target="_blank" href="https://blog.achulslander.com/how-to-make-an-accordion-faq-with-js-part-3">part three</a> is on making the project look pretty. Why? <a target="_blank" href="https://cariefisher.com/a11y-start/">Because I believe accessibility (a11y) is more important</a>, making sure everyone can use something is more important than how it looks.</p>
<p>And that isn't to say I'm an expert on a11y, I'm not. I am, however, constantly working to improve and continue to make it a priority in my code.</p>
<p>At the end of part one, we had a very bare project:</p>
<h2 id="heading-html">HTML</h2>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"q"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"title"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Question One<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Clicky<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
   <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"answer"</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.<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">article</span>&gt;</span>
</code></pre>
<h2 id="heading-scss">SCSS</h2>
<pre><code class="lang-scss"><span class="hljs-selector-class">.answer</span> {
    <span class="hljs-attribute">display</span>: none;
}
<span class="hljs-selector-class">.clicked</span> {
    <span class="hljs-selector-class">.answer</span> {
        <span class="hljs-attribute">display</span>: block;
  }
}
</code></pre>
<h2 id="heading-javascript">JavaScript</h2>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> question=<span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">'.q'</span>);

question.forEach(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">quest</span>) </span>{
  <span class="hljs-keyword">const</span> btn=quest.querySelector(<span class="hljs-string">'button'</span>);
  btn.addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    quest.classList.toggle(<span class="hljs-string">'clicked'</span>);
  });

});
</code></pre>
<p>We won't be adding much code for this step. Why? By using HTML5 elements, we've already achieved greater a11y. We structured our project using elements that are meaningful to assistive technology. Each question is an <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/article"><code>article</code></a>, and in my <a target="_blank" href="https://codepen.io/alleycaaat/full/bGazoZa">code</a>, (where this is a stand-alone project) the questions are wrapped in <code>&lt;main&gt;</code>. If this is part of a page with more information, wrapping them in <code>&lt;section&gt;</code> nested inside <code>&lt;main&gt;</code> would be best.</p>
<p>These elements are helpful for assistive technology, as opposed to using just <code>&lt;div&gt;</code> elements that don't automatically provide structure.</p>
<h2 id="heading-adding-an-aria-attribute">Adding an ARIA Attribute</h2>
<p>We need to add code so that assistive technology can tell the user if an answer is showing or not. We do that by adding the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-expanded"><code>aria-expanded</code></a> attribute to our <code>&lt;article&gt;</code>, like so:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"q"</span> <span class="hljs-attr">aria-expanded</span>=<span class="hljs-string">"false"</span>&gt;</span>
</code></pre>
<p>This will let users know there's more information that isn't currently visible. Doing this alone is <strong>not</strong> enough, we have to toggle the attribute to <code>"true"</code> when the answer is showing. To do that, we go back to the JavaScriptmobile!</p>
<h2 id="heading-javascriptmobile">JavaScriptmobile</h2>
<p>Inside our <code>eventListener</code> we need to declare a variable for the <code>aria-expanded</code> attribute of the specific question (<code>quest</code>) that is clicked, and we need to use <code>getAttribute</code> to do so.</p>
<p><code>let ariaValue=quest.getAttribute("aria-expanded");</code></p>
<p>If we'd print <code>ariaValue</code> to the console right now, it would display "false", no matter how many times we click the button. To remedy that, we'll use a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">ternary operator</a>. A ternary operator looks at a condition and executes an expression if it's true, a different expression if it's false. In our case, it will look to see if the <code>value</code> of the <code>aria-expanded attribute</code> is true or false, and then set it to the opposite. Keep this in mind as this next part may be confusing at first.</p>
<pre><code class="lang-javascript">ariaValue = (ariaValue === <span class="hljs-string">'false'</span>) 
     ? quest.setAttribute(<span class="hljs-string">'aria-expanded'</span>, <span class="hljs-string">'true'</span>) 
     : quest.setAttribute(<span class="hljs-string">'aria-expanded'</span>, <span class="hljs-string">'false'</span>);
</code></pre>
<p>Now let's break this down a little: <code>ariaValue =</code> is just us wanting to store something in that variable. <code>ariaValue === "false" ?</code> is the condition that's being evaluated, if it evaluates true (meaning the current value is "false"), then <code>aria-expanded</code> is set as <code>true</code>.</p>
<p>If the condition evaluates false (meaning the current value is "true"), then our <code>attribute</code> is set to <code>false</code>. If you're thinking I'm trying to tell you that if something is false, and it should be true it gets set to true, and if something is supposed to be false, and it is false that it's false, it gets set to false anyway... You're correct!</p>
<p>Here's a less maddening example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> skyColor = <span class="hljs-string">'blue'</span>;
<span class="hljs-keyword">var</span> timeOfDay = (skyColor === <span class="hljs-string">'blue'</span>) ?  <span class="hljs-string">'day'</span> : <span class="hljs-string">'night'</span>;
<span class="hljs-built_in">console</span>.log(timeofDay);  <span class="hljs-comment">//'day'</span>
</code></pre>
<p>Currently, <code>skyColor</code> is blue, because that's what the variable is initialized as. The second variable, <code>timeOfDay</code> is going to evaluate the condition <code>(skyColor === 'blue')</code>, and if that expression is found to be true, <code>timeOfDay</code> stores <code>day</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> skyColor = <span class="hljs-string">'black'</span>;
<span class="hljs-keyword">var</span> timeOfDay = (skyColor === <span class="hljs-string">'blue'</span>) ?  <span class="hljs-string">'day'</span> : <span class="hljs-string">'night'</span>;
<span class="hljs-built_in">console</span>.log(timeofDay);  <span class="hljs-comment">//'night'</span>
</code></pre>
<p>In this example, the expression is false, so <code>timeOfDay</code> stores 'night'.</p>
<p>If your brain isn't a tangled mess after all that, congratulations! You're done! If it is a tangled mess, congratulations! You're still done! And here's a bandage for your brain.</p>
<h2 id="heading-visual-effects">Visual Effects</h2>
<p>Here's a gif of a button being clicked and the <code>aria-expanded</code> value changing (our project doesn't look like this <em>yet</em>):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1651085265530/EyAlxMhaI.gif" alt="FAQ-aria.gif" /></p>
<p>I really hope you enjoyed this article and found it helpful. Leave a comment below if you have any questions. Tune in next week for when we style this project!</p>
]]></content:encoded></item><item><title><![CDATA[How to Make an Accordion FAQ with HTML, SCSS and JS]]></title><description><![CDATA[Today I'm going to show how to make a fun little FAQ page that looks a lot fancier than it is difficult. This project will come in three parts: the basic structure, improving accessibility, and the styling.

Finished project code
HTML
First, we need ...]]></description><link>https://blog.achulslander.com/how-to-make-an-accordion-faq-with-html-scss-and-js</link><guid isPermaLink="true">https://blog.achulslander.com/how-to-make-an-accordion-faq-with-html-scss-and-js</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[CSS]]></category><category><![CDATA[scss]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[AC Hulslander]]></dc:creator><pubDate>Tue, 19 Apr 2022 18:40:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/g-Dui8tCdrI/upload/v1650467761432/WhAVvOgVa.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today I'm going to show how to make a fun little FAQ page that looks a lot fancier than it is difficult. This project will come in three parts: the basic structure, improving accessibility, and the styling.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650467681217/TwdC2tTYg.gif" alt="FAQcomplete.gif" /></p>
<p><a target="_blank" href="https://codepen.io/alleycaaat/full/bGazoZa">Finished project code</a></p>
<h2 id="heading-html">HTML</h2>
<p>First, we need our HTML. Each question is going to be an <code>article</code>, and in it will be a question and its answer like so:</p>
<pre><code class="lang-xml"><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">h2</span>&gt;</span>Question One<span class="hljs-tag">&lt;/<span class="hljs-name">h2</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">p</span>&gt;</span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.<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">article</span>&gt;</span>
</code></pre>
<p>For styling purposes, <code>article</code> will have a class of <code>q</code>, the <code>div</code> wrapping the <code>h2</code> will have a class of <code>title</code>, and the <code>div</code> wrapping the <code>p</code> containing the answer will have a class of <code>answer</code>.</p>
<p>The answers won't automatically be visible, this is a fancy-pants FAQ after all! So we'll need a button to expand and collapse the answers:</p>
<p><code>&lt;button&gt;&lt;/button&gt;</code></p>
<p>and we'll tuck that in to our <code>title div</code>. Feel free to add some text in the <code>button</code> or an image that users can click.</p>
<h2 id="heading-scss">SCSS</h2>
<p>Now, the way we're going to make the answers visible is by adding a class to the <code>answer div</code> when a user clicks the <code>button</code>. Initially our SCSS for <code>answer</code> needs to ensure the answer is not visible:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.answer</span> {
    <span class="hljs-attribute">display</span>: none;
}
</code></pre>
<p>and we'll be adding a class called <code>clicked</code> to make it visible:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.clicked</span> {
    <span class="hljs-selector-class">.answer</span> {
        <span class="hljs-attribute">display</span>: block;
  }
}
</code></pre>
<p>But how do we add the <code>clicked</code> class to the <code>div</code>? I'm so glad you asked! That takes us right to our next section.</p>
<h2 id="heading-javascript">JavaScript</h2>
<p>We're going to start out with <code>const question=document.querySelectorAll('.q');</code>, this will get all of our <code>article</code>s, our individual questions.</p>
<p>I had never used <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach"><code>forEach</code></a>, so this was a good excuse to learn about it, and it's perfect for what we're doing. <code>forEach</code> performs an action once on each item in an array. Where's our array? Weeell, we don't have one. Ope.</p>
<p>Luckily <code>querySelectorAll</code> returns a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/NodeList"><code>NodeList</code></a> that <code>forEach</code> treats like an array. So, the tl;dr is <code>querySelectorAll</code> compiles a list of the elements with class <code>q</code>, and <code>forEach</code> performs an action on each item in the list one time.</p>
<p>Still with me? I hope so! Now let's add the <code>forEach</code> we just learned about to our code:</p>
<p><code>question.forEach(function (quest) { })</code></p>
<p>Before we fill in the action to be performed on each <code>question</code>, we need to make it so our <code>button</code>s can be put to work. Inside the curly braces we'll create a variable for them:</p>
<p><code>const btn=quest.querySelector('button');</code></p>
<p>This will give us access to the <code>button</code> elements. Each <code>question</code> has a <code>button</code>, and now that we have access to the latter, we can add an <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener"><code>eventListener</code></a> so we can reveal the <code>answer</code>:</p>
<p><code>btn.addEventListener('click', function() { })</code></p>
<p>Now, when a user clicks a <code>button</code>, a function is executed. How does this happen? That line of code is 'listening' for the user to click on something (in our case a button) so it can perform its task (show the answer).</p>
<p>So for a quick recap: so far with our JavaScript we have gathered all of the questions, we have gained access to the buttons in each of those questions, and we told the buttons to pay attention as they may get clicked.</p>
<p>Speaking of clicked, I mean, <code>.clicked</code>, here's where that class comes in to play. We'll use <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Element/classList"><code>classList</code></a> to make the changes we want. <code>classList</code> returns a <em>live</em> list of the classes an element has. There are different ways to use <code>classList</code> on elements: <code>add()</code> a class, <code>remove()</code> a class, <code>toggle()</code> a class or <code>replace()</code> a class. I want my answers to stay visible until the user decides to close them, so I'm going to use <code>toggle()</code>. And that looks like this:</p>
<p><code>quest.classList.toggle('clicked');</code></p>
<p>So what's happening now? When a user clicks on a <code>button</code>, the <code>eventListener</code> knows the click means to toggle <code>.clicked</code> on <code>quest</code>, which is the question. For a refresher, here's <code>.clicked</code>:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.clicked</span> {
    <span class="hljs-selector-class">.answer</span> {
        <span class="hljs-attribute">display</span>: block;
  }
}
</code></pre>
<p>Or if you're using CSS:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.clicked</span> <span class="hljs-selector-class">.answer</span> {
    <span class="hljs-attribute">display</span>: block;
}
</code></pre>
<p>It's important to note the presence of <code>.answer</code>; if we just added <code>.clicked { display: block }</code> to the <code>article</code>, it wouldn't show the answer. By having <code>.answer</code> in there, it will match an element that has a class of <code>answer</code> <strong>only if</strong> that element has a parent element with <code>.clicked</code>. Which is now what we have: our <code>eventListener</code> adds <code>.clicked</code> to the <code>article</code>, which contains <code>&lt;div class="answer"&gt;</code> and boom! Our answer appears!</p>
<p><em>Please note</em> the space between <code>.clicked</code> and .<code>answer</code> in the CSS version, if that space is removed it will be looking for something different and the answer won't appear.</p>
<p>Here's a visual of what <code>classList.toggle</code> does to the HTML when a <code>button</code> is clicked:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650473661086/ePrPlrajg.gif" alt="FAQclicked.gif" /></p>
<p>And here's what's happening on the styles before and after the click:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650473889333/Ot-GgydX-.gif" alt="FAQclickedstyles.gif" /></p>
<h3 id="heading-thats-all-there-is-to-it-pretty-simple-yeah">That's all there is to it! Pretty simple, yeah?</h3>
<p>Now your project should look something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650474083582/GGHiiEuzn.gif" alt="FAQbarebonesfinished.gif" /></p>
<p>Let me know if you have any questions or comments, and drop a link if you try this out for yourself! Check out <a target="_blank" href="https://blog.achulslander.com/make-an-accordion-faq-with-js-part-2">part 2 where we improve accessibility</a> and <a target="_blank" href="https://blog.achulslander.com/how-to-make-an-accordion-faq-with-js-part-3">part 3</a> where we add styling and rotate that arrow when the user clicks the button.</p>
]]></content:encoded></item><item><title><![CDATA[Collapsible navigation menu with HTML, CSS and JS]]></title><description><![CDATA[Learn to make a sliding navigation panel for your website!

Having your website be responsive is so important and necessary these days, but that doesn't mean you have to sacrifice aesthetics and fun features!  Follow along to learn how to make a simp...]]></description><link>https://blog.achulslander.com/collapsible-navigation-menu-with-html-css-and-js</link><guid isPermaLink="true">https://blog.achulslander.com/collapsible-navigation-menu-with-html-css-and-js</guid><category><![CDATA[HTML]]></category><category><![CDATA[CSS]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Accessibility]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[AC Hulslander]]></dc:creator><pubDate>Tue, 08 Mar 2022 18:55:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/tZc3vjPCk-Q/upload/v1646765487236/u27L5pzjQ.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-learn-to-make-a-sliding-navigation-panel-for-your-website">Learn to make a sliding navigation panel for your website!</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1646763309151/bVDrYJETT.gif" alt="slidingMenu2.gif" /></p>
<p>Having your website be responsive is so important and necessary these days, but that doesn't mean you have to sacrifice aesthetics and fun features!  Follow along to learn how to make a simple navigation menu that slides in and out at the click of a button, perfect for small viewports.  <a target="_blank" href="https://codepen.io/alleycaaat/full/vYWyNoX">Full code can be found here</a>.</p>
<p>Let's dive right in!</p>
<h3 id="heading-html">HTML</h3>
<pre><code><span class="hljs-operator">&lt;</span>nav id<span class="hljs-operator">=</span><span class="hljs-string">"sidenav"</span> class<span class="hljs-operator">=</span><span class="hljs-string">"sidenavbar"</span><span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span>a href<span class="hljs-operator">=</span><span class="hljs-string">"#"</span><span class="hljs-operator">&gt;</span>Home<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>a<span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span>a href<span class="hljs-operator">=</span><span class="hljs-string">"#"</span><span class="hljs-operator">&gt;</span>About<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>a<span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span>a href<span class="hljs-operator">=</span><span class="hljs-string">"#"</span><span class="hljs-operator">&gt;</span>FAQ<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>a<span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span>a href<span class="hljs-operator">=</span><span class="hljs-string">"#"</span><span class="hljs-operator">&gt;</span>Blog<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>a<span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span>a href<span class="hljs-operator">=</span><span class="hljs-string">"#"</span><span class="hljs-operator">&gt;</span>Contact<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>a<span class="hljs-operator">&gt;</span>
<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>nav<span class="hljs-operator">&gt;</span>
<span class="hljs-operator">&lt;</span>button aria<span class="hljs-operator">-</span>expanded<span class="hljs-operator">=</span><span class="hljs-string">"false"</span> class<span class="hljs-operator">=</span><span class="hljs-string">"openbtn"</span> id<span class="hljs-operator">=</span><span class="hljs-string">"openBtn"</span> aria<span class="hljs-operator">-</span>label<span class="hljs-operator">=</span><span class="hljs-string">"mobile navigation"</span> onclick<span class="hljs-operator">=</span><span class="hljs-string">"toggleNav()"</span><span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span>span id<span class="hljs-operator">=</span><span class="hljs-string">"chevron"</span><span class="hljs-operator">&gt;</span><span class="hljs-operator">&amp;</span>raquo;<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>span<span class="hljs-operator">&gt;</span>
<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>button<span class="hljs-operator">&gt;</span>
</code></pre><p>Using <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/nav"><code>&lt;nav&gt;</code></a> we add our links.  Focusing on UX we have <code>aria-expanded="false"</code> that changes to true when the menu is opened, which indicates to screen reader users the visibility of the menu.  I opted to make my menu  a bit fancy using a chevron that rotates to indicate which direction the slider will go <code>onclick</code>,  feel free to use what you'd like.</p>
<h2 id="heading-css">CSS</h2>
<h4 id="heading-on-to-the-styles-for-the-menu-itself">On to the styles for the menu itself:</h4>
<pre><code><span class="hljs-selector-class">.sidenavbar</span> {
    <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">0</span>;  <span class="hljs-comment">/* initial width is set to 0, slide happens with JS */</span>
    <span class="hljs-attribute">position</span>: fixed;  <span class="hljs-comment">/* keeps sidenavbar in place */</span>
    <span class="hljs-attribute">z-index</span>: <span class="hljs-number">1000</span>;  <span class="hljs-comment">/* makes sidenavbar stay on top */</span>
    <span class="hljs-attribute">overflow-x</span>: hidden;  <span class="hljs-comment">/* prevents unwanted scrollbar */</span>
    <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">background-color</span>: darkBlue;
    <span class="hljs-attribute">transition</span>: all ease-in <span class="hljs-number">0.5s</span>;
}
</code></pre><h4 id="heading-link-styles">Link styles</h4>
<pre><code><span class="hljs-selector-tag">a</span> {
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">7px</span> <span class="hljs-number">14px</span> <span class="hljs-number">3px</span> <span class="hljs-number">14px</span>;
        <span class="hljs-attribute">text-decoration</span>: none;
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">20px</span>;
        <span class="hljs-attribute">color</span>: lightGreen;
        <span class="hljs-attribute">display</span>: block;
        <span class="hljs-attribute">transition</span>: all ease <span class="hljs-number">0.3s</span>;
        <span class="hljs-attribute">text-align</span>: center;
}
</code></pre><p><em>Styling note: on my personal website I have the <code>height</code> attribute set to <code>auto</code>, and a class with styling <code>margin-top: 35px</code> added to the first link to create a more balanced look, like so:</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1646760895895/LVtH3b6Lw.jpg" alt="collapsibleMenu.jpg" /></p>
<p><em>Play around and see what you like!</em></p>
<h4 id="heading-now-lets-style-the-button-used-to-open-and-close-the-menu">Now let's style the button used to open and close the menu:</h4>
<pre><code><span class="hljs-selector-class">.openbtn</span> {
    <span class="hljs-attribute">cursor</span>: pointer;
    <span class="hljs-attribute">color</span>: white;
    <span class="hljs-attribute">background-color</span>: darkBlue;
    <span class="hljs-attribute">border</span>: none;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">40px</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">40px</span>;
    <span class="hljs-attribute">position</span>: fixed;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">75px</span>;
    <span class="hljs-attribute">transition</span>: all ease-in .<span class="hljs-number">5s</span>;
<span class="hljs-comment">/* rounds the upper right and lower right corners */</span>
    <span class="hljs-attribute">border-radius</span>:  <span class="hljs-number">0</span> <span class="hljs-number">5px</span> <span class="hljs-number">5px</span> <span class="hljs-number">0</span>;  
    <span class="hljs-attribute">z-index</span>: <span class="hljs-number">999</span>;
}
<span class="hljs-selector-class">.openbtn</span><span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">background-color</span>: lightGreen;
}
</code></pre><p>Pretty straight forward; the most essential part of the <code>openbtn</code> class is the width of the button, which I'll explain shortly.</p>
<h4 id="heading-styles-for-the-chevron">Styles for the chevron:</h4>
<pre><code><span class="hljs-selector-id">#chevron</span> {
    <span class="hljs-attribute">transition</span>: all ease-in .<span class="hljs-number">5s</span>;
    <span class="hljs-attribute">float</span>: right;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">5px</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#FFF</span>;  
}
</code></pre><p>Observant readers may have noticed the <code>transition</code> attribute of the  <code>sidebarnav</code> and <code>openbtn</code> classes and <code>chevron</code> IDs are all the same.  This is critical to ensure a seamless transition.  If you change the values, just make sure to change it on all three or things may look wonky.</p>
<p>The float position of the chevron is significant.  When the button is clicked to open the menu, the button's width actually expands, which makes the button appear to slide.  Here's a visual with the opacity of the menu bar set to 0.5 to show what's happening behind the scenes:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1646763639353/hBXz14_tv.gif" alt="slidingMenuOpacity.gif" /></p>
<p>If the chevron floated left, it wouldn't be visible when the menu is open.</p>
<p>Now let's get to making this menu slide!</p>
<h3 id="heading-javascript">JavaScript</h3>
<p>In the HTML we specify the function of <code>toggleNav</code> to run <code>onclick</code>, so that's where we'll begin:</p>
<pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toggleNav</span>(<span class="hljs-params"></span>) </span>{

}
</code></pre><p>We'll need some variables: one for the menu itself, one to rotate the chevron, one to move the button, and one for the aria value.</p>
<pre><code><span class="hljs-keyword">var</span> sidenav <span class="hljs-operator">=</span> document.getElementById(<span class="hljs-string">"sidenav"</span>),
    chevron <span class="hljs-operator">=</span> document.getElementById(<span class="hljs-string">"chevron"</span>),
    btn <span class="hljs-operator">=</span> document.getElementById(<span class="hljs-string">"openBtn"</span>),
    ariaValue <span class="hljs-operator">=</span> btn.getAttribute(<span class="hljs-string">"aria-expanded"</span>);
</code></pre><p>You can opt to select the elements by class or opt for <code>querySelector</code>, it's up to you.  The <code>ariaValue</code> needs to remain a <code>.getAttribute</code> because we'll be <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set">setting</a> it attribute for <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility">accessibility</a>.</p>
<p>Now, in the CSS the menu's width is set to 0.  So, until the button is clicked we can't see the menu.  JavaScript will make that magic happen in the first line:</p>
<pre><code>sidenav.style.width <span class="hljs-operator">=</span> sidenav.style.width <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">"175px"</span> ? <span class="hljs-string">"0"</span> : <span class="hljs-string">"175px"</span>; 
chevron.style.transform <span class="hljs-operator">=</span> chevron.style.transform <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">"rotate(-180deg)"</span> ? <span class="hljs-string">"rotate(0deg)"</span> : <span class="hljs-string">"rotate(-180deg)"</span>; 
btn.style.width <span class="hljs-operator">=</span> btn.style.width <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">"215px"</span> ? <span class="hljs-string">"40px"</span> : <span class="hljs-string">"215px"</span>;
</code></pre><p>Using a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">ternary operator</a>, we're checking the value of <code>width</code> for the menu.  If it's 0, the value is changed to 175px, which opens the menu.  If <code>width</code> has a value of 175px, the value is then changed to 0, closing the menu.</p>
<p>The chevron also has a ternary operator, too, which causes it to rotate 180 degrees.</p>
<p>The button's width was mentioned earlier to be significant, and here's why:  to properly have the button move out as if attached to the menu, the ternary needs to compare the widths of <em>just</em> the button, to the button <em>plus</em> the width of the menu.  So, if you change the menu or button width in the future, these values will also need to be updated.</p>
<p>Now let's finish up our function by addressing <code>aria-expanded</code>, so screen readers will know if the menu is open or closed.</p>
<pre><code>ariaValue <span class="hljs-operator">=</span> ariaValue <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">"true"</span> ? btn.setAttribute(<span class="hljs-string">"aria-expanded"</span>, <span class="hljs-string">"false"</span>) : btn.setAttribute(<span class="hljs-string">"aria-expanded"</span>, <span class="hljs-string">"true"</span>);
</code></pre><p>Remember when we defined our variables, we used <code>getAttribute</code> to find out the value of <code>aria-expanded</code>.  Now we'll set the attribute accordingly.  It's not difficult or fancy but <em>incredibly</em> important for accessibility.</p>
<h4 id="heading-and-thats-it">And that's it!</h4>
<p>Pretty simple, yeah?  I had a lot of fun making this collapsible menu and hope you've enjoyed following along!</p>
]]></content:encoded></item></channel></rss>