|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- title: An advanced way to use CSS variables
- url: https://gomakethings.com/an-advanced-way-to-use-css-variables/
- hash_url: a16101277229b3aeca8ac3249c84320c
- archive_date: 2024-04-08
- og_image: https://gomakethings.com/img/og.png
- description: Yesterday, we learned about CSS variables. Today, I wanted to show you an advanced approach to working with them that I often use with client projects.
- favicon: https://gomakethings.com/img/favicon.ico
- language: en_US
-
- <p>Let’s dig in!</p>
-
- <h2 id="globals-for-system-or-theme-defaults">Globals for system or theme defaults</h2>
-
- <p>I like to scope design system or theme defaults to the <code>:root</code> element. This makes them accessible to every element and class in the design system.</p>
- <div class="highlight"><pre class="chroma"><code class="language-css" data-lang="css"><span class="p">:</span><span class="nd">root</span> <span class="p">{</span>
-
- <span class="c">/_ Colors _/</span>
- <span class="nv">--color-primary</span><span class="p">:</span> <span class="mh">#0088cc</span><span class="p">;</span>
- <span class="nv">--color-secondary</span><span class="p">:</span> <span class="kc">rebeccapurple</span><span class="p">;</span>
- <span class="nv">--color-black</span><span class="p">:</span> <span class="mh">#272727</span><span class="p">;</span>
- <span class="nv">--color-white</span><span class="p">:</span> <span class="mh">#ffffff</span><span class="p">;</span>
-
- <span class="c">/_ Sizes _/</span>
- <span class="nv">--size-default</span><span class="p">:</span> <span class="mi">1</span><span class="kt">rem</span><span class="p">;</span>
- <span class="nv">--size-small</span><span class="p">:</span> <span class="mf">0.875</span><span class="kt">rem</span><span class="p">;</span>
- <span class="nv">--size-large</span><span class="p">:</span> <span class="mf">1.25</span><span class="kt">rem</span><span class="p">;</span>
-
- <span class="c">/_ Typefaces _/</span>
- <span class="nv">--font-sans</span><span class="p">:</span> <span class="s2">"PT Sans"</span><span class="p">,</span> <span class="n">sans</span><span class="p">;</span>
- <span class="nv">--font-serif</span><span class="p">:</span> <span class="s2">"PT Serif"</span><span class="p">,</span> <span class="kc">serif</span><span class="p">;</span>
- <span class="nv">--font-mono</span><span class="p">:</span> <span class="n">Menlo</span><span class="p">,</span> <span class="n">Monaco</span><span class="p">,</span> <span class="s2">"Courier New"</span><span class="p">,</span> <span class="kc">monospace</span><span class="p">;</span>
-
- <span class="p">}</span></code></pre></div>
-
- <p>I typically have variables for <code>--color-*</code>, <code>--size-*</code>, and <code>--font-*</code>, as well as ones to define the max width of containers and how much <code>--spacing</code> to use between paragraphs and various elements.</p>
-
- <h2 id="styling-elements">Styling elements</h2>
-
- <p>Let’s look at styles for a <code>button</code> element.</p>
- <div class="highlight"><pre class="chroma"><code class="language-css" data-lang="css"><span class="nt">button</span> <span class="p">{</span>
- <span class="k">background-color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="o">-</span><span class="n">primary</span><span class="p">);</span>
- <span class="k">border</span><span class="p">:</span> <span class="mf">0.125</span><span class="kt">rem</span> <span class="kc">solid</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="o">-</span><span class="n">primary</span><span class="p">);</span>
- <span class="k">border-radius</span><span class="p">:</span> <span class="mf">0.25</span><span class="kt">em</span><span class="p">;</span>
- <span class="k">color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="o">-</span><span class="kc">white</span><span class="p">);</span>
- <span class="k">display</span><span class="p">:</span> <span class="kc">inline</span><span class="o">-</span><span class="kc">block</span><span class="p">;</span>
- <span class="k">font-size</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">font</span><span class="o">-</span><span class="kc">default</span><span class="p">);</span>
- <span class="k">font-weight</span><span class="p">:</span> <span class="kc">normal</span><span class="p">;</span>
- <span class="k">line-height</span><span class="p">:</span> <span class="mf">1.2</span><span class="p">;</span>
- <span class="k">padding</span><span class="p">:</span> <span class="mf">0.5</span><span class="kt">rem</span> <span class="mf">0.6875</span><span class="kt">rem</span><span class="p">;</span>
- <span class="p">}</span>
-
- <span class="nt">button</span><span class="p">:</span><span class="nd">hover</span> <span class="p">{</span>
- <span class="k">background-color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="o">-</span><span class="n">secondary</span><span class="p">);</span>
- <span class="k">border-color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="o">-</span><span class="n">secondary</span><span class="p">);</span>
- <span class="p">}</span></code></pre></div>
-
- <p>Let’s say we want to add a secondary button style: the <code>.btn-secondary</code> class.</p>
- <div class="highlight"><pre class="chroma"><code class="language-html" data-lang="html"><span class="p"><</span><span class="nt">button</span><span class="p">></span>Primary Button<span class="p"></</span><span class="nt">button</span><span class="p">></span>
- <span class="p"><</span><span class="nt">button</span> <span class="na">class</span><span class="o">=</span><span class="s">"btn-secondary"</span><span class="p">></span>Secondary Button<span class="p"></</span><span class="nt">button</span><span class="p">></span></code></pre></div>
- <p>Using only globals, we might write the CSS like this.</p>
- <div class="highlight"><pre class="chroma"><code class="language-css" data-lang="css"><span class="p">.</span><span class="nc">btn-secondary</span> <span class="p">{</span>
- <span class="k">background-color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="o">-</span><span class="n">secondary</span><span class="p">);</span>
- <span class="k">border-color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="o">-</span><span class="n">secondary</span><span class="p">);</span>
- <span class="p">}</span>
-
- <span class="p">.</span><span class="nc">btn-secondary</span><span class="p">:</span><span class="nd">hover</span> <span class="p">{</span>
- <span class="k">background-color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="o">-</span><span class="n">primary</span><span class="p">);</span>
- <span class="k">border-color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="o">-</span><span class="n">primary</span><span class="p">);</span>
- <span class="p">}</span></code></pre></div>
-
- <p>It totally works, and we can easily update our global colors later and have them automatically update the button styles.</p>
-
- <p>But there’s another way we could approach this that I think works a <em>little</em> bit better.</p>
-
- <h2 id="css-variables-scoped-to-the-element">CSS variables scoped to the element</h2>
-
- <p>While global variables scoped to the <code>:root</code> let me define system-wide defaults, I also like to scope variables for <a href="https://gomakethings.com/hug-css-how-i-approach-css-architecture/">styles that change with utility classes</a> to the element itself.</p>
-
- <p>CSS variables scoped to an element can use other CSS variables as their value. But scoping them to the element provides an easy way to modify them.</p>
-
- <p>Looking at our <code>button</code> again, I’ll often do something like this…</p>
- <div class="highlight"><pre class="chroma"><code class="language-css" data-lang="css"><span class="nt">button</span> <span class="p">{</span>
- <span class="nv">--bg-color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="o">-</span><span class="n">primary</span><span class="p">);</span>
- <span class="nv">--color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="o">-</span><span class="kc">white</span><span class="p">);</span>
- <span class="nv">--size</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">font</span><span class="o">-</span><span class="kc">default</span><span class="p">);</span>
- <span class="nv">--padding-x</span><span class="p">:</span> <span class="mf">0.6875</span><span class="kt">rem</span><span class="p">;</span>
- <span class="nv">--padding-y</span><span class="p">:</span> <span class="mf">0.5</span><span class="kt">rem</span><span class="p">;</span>
-
- <span class="k">background-color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">bg</span><span class="o">-</span><span class="kc">color</span><span class="p">);</span>
- <span class="k">border</span><span class="p">:</span> <span class="mf">0.125</span><span class="kt">rem</span> <span class="kc">solid</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">bg</span><span class="o">-</span><span class="kc">color</span><span class="p">);</span>
- <span class="k">border-radius</span><span class="p">:</span> <span class="mf">0.25</span><span class="kt">em</span><span class="p">;</span>
- <span class="k">color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="p">);</span>
- <span class="k">display</span><span class="p">:</span> <span class="kc">inline</span><span class="o">-</span><span class="kc">block</span><span class="p">;</span>
- <span class="k">font-size</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">size</span><span class="p">);</span>
- <span class="k">font-weight</span><span class="p">:</span> <span class="kc">normal</span><span class="p">;</span>
- <span class="k">line-height</span><span class="p">:</span> <span class="mf">1.2</span><span class="p">;</span>
- <span class="k">padding</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">padding</span><span class="o">-</span><span class="n">y</span><span class="p">)</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">padding</span><span class="o">-</span><span class="n">x</span><span class="p">);</span>
- <span class="p">}</span></code></pre></div>
-
- <p>Now, to change the <code>button:hover</code> style, I only need to update the <code>--bg-color</code> variable, which controls both the <code>background-color</code> and <code>border-color</code> properties.</p>
- <div class="highlight"><pre class="chroma"><code class="language-css" data-lang="css"><span class="nt">button</span><span class="p">:</span><span class="nd">hover</span> <span class="p">{</span>
- <span class="nv">--bg-color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="o">-</span><span class="n">secondary</span><span class="p">);</span>
- <span class="p">}</span></code></pre></div>
- <p><a href="https://codepen.io/cferdinandi/pen/gOyovdE">Here’s a demo.</a></p>
-
- <h2 id="a-growing-system">A growing system</h2>
-
- <p>This approach is a little bit more work up-front, but it has bigger payoffs the more you use it.</p>
-
- <p>For example, our <code>.btn-secondary</code> class gets shorter.</p>
- <div class="highlight"><pre class="chroma"><code class="language-css" data-lang="css"><span class="p">.</span><span class="nc">btn-secondary</span> <span class="p">{</span>
- <span class="nv">--bg-color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="o">-</span><span class="n">secondary</span><span class="p">);</span>
- <span class="p">}</span>
-
- <span class="p">.</span><span class="nc">btn-secondary</span><span class="p">:</span><span class="nd">hover</span> <span class="p">{</span>
- <span class="nv">--bg-color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="kc">color</span><span class="o">-</span><span class="n">primary</span><span class="p">);</span>
- <span class="p">}</span></code></pre></div>
-
- <p>With every utility class you add to modify your base styles, using element-scoped CSS variables makes things a bit easier.</p>
-
- <p>For example, we can add <code>.btn-large</code> and <code>.btn-small</code> classes by doing this…</p>
- <div class="highlight"><pre class="chroma"><code class="language-css" data-lang="css"><span class="p">.</span><span class="nc">btn-large</span> <span class="p">{</span>
- <span class="nv">--size</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">font</span><span class="o">-</span><span class="kc">large</span><span class="p">);</span>
- <span class="nv">--padding-x</span><span class="p">:</span> <span class="mf">0.875</span><span class="kt">rem</span><span class="p">;</span>
- <span class="nv">--padding-y</span><span class="p">:</span> <span class="mf">0.75</span><span class="kt">rem</span><span class="p">;</span>
- <span class="p">}</span>
-
- <span class="p">.</span><span class="nc">btn-small</span> <span class="p">{</span>
- <span class="nv">--size</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">font</span><span class="o">-</span><span class="kc">small</span><span class="p">);</span>
- <span class="nv">--padding-x</span><span class="p">:</span> <span class="mf">0.5</span><span class="kt">rem</span><span class="p">;</span>
- <span class="nv">--padding-y</span><span class="p">:</span> <span class="mf">0.25</span><span class="kt">rem</span><span class="p">;</span>
- <span class="p">}</span></code></pre></div>
-
- <p><a href="https://codepen.io/cferdinandi/pen/vYMpdVV">Here’s another demo.</a></p>
-
- <h2 id="should-you-always-do-this">Should you always do this?</h2>
-
- <p>Nope! It’s a lot more work, and sometimes results in code that’s a bit less readable at first glance.</p>
-
- <p>It’s a good approach to use…</p>
-
- <ul>
- <li>For properties that will change through modifier or utility classes.</li>
- <li>For design systems where end-users will need to easily override certain styles in ways you can’t predict.</li>
- </ul>
|