A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.md 15KB

1 month ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. title: An advanced way to use CSS variables
  2. url: https://gomakethings.com/an-advanced-way-to-use-css-variables/
  3. hash_url: a16101277229b3aeca8ac3249c84320c
  4. archive_date: 2024-04-08
  5. og_image: https://gomakethings.com/img/og.png
  6. 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.
  7. favicon: https://gomakethings.com/img/favicon.ico
  8. language: en_US
  9. <p>Let’s dig in!</p>
  10. <h2 id="globals-for-system-or-theme-defaults">Globals for system or theme defaults</h2>
  11. <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>
  12. <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>
  13. <span class="c">/_ Colors _/</span>
  14. <span class="nv">--color-primary</span><span class="p">:</span> <span class="mh">#0088cc</span><span class="p">;</span>
  15. <span class="nv">--color-secondary</span><span class="p">:</span> <span class="kc">rebeccapurple</span><span class="p">;</span>
  16. <span class="nv">--color-black</span><span class="p">:</span> <span class="mh">#272727</span><span class="p">;</span>
  17. <span class="nv">--color-white</span><span class="p">:</span> <span class="mh">#ffffff</span><span class="p">;</span>
  18. <span class="c">/_ Sizes _/</span>
  19. <span class="nv">--size-default</span><span class="p">:</span> <span class="mi">1</span><span class="kt">rem</span><span class="p">;</span>
  20. <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>
  21. <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>
  22. <span class="c">/_ Typefaces _/</span>
  23. <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>
  24. <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>
  25. <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>
  26. <span class="p">}</span></code></pre></div>
  27. <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>
  28. <h2 id="styling-elements">Styling elements</h2>
  29. <p>Let’s look at styles for a <code>button</code> element.</p>
  30. <div class="highlight"><pre class="chroma"><code class="language-css" data-lang="css"><span class="nt">button</span> <span class="p">{</span>
  31. <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>
  32. <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>
  33. <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>
  34. <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>
  35. <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>
  36. <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>
  37. <span class="k">font-weight</span><span class="p">:</span> <span class="kc">normal</span><span class="p">;</span>
  38. <span class="k">line-height</span><span class="p">:</span> <span class="mf">1.2</span><span class="p">;</span>
  39. <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>
  40. <span class="p">}</span>
  41. <span class="nt">button</span><span class="p">:</span><span class="nd">hover</span> <span class="p">{</span>
  42. <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>
  43. <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>
  44. <span class="p">}</span></code></pre></div>
  45. <p>Let’s say we want to add a secondary button style: the <code>.btn-secondary</code> class.</p>
  46. <div class="highlight"><pre class="chroma"><code class="language-html" data-lang="html"><span class="p">&lt;</span><span class="nt">button</span><span class="p">&gt;</span>Primary Button<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
  47. <span class="p">&lt;</span><span class="nt">button</span> <span class="na">class</span><span class="o">=</span><span class="s">"btn-secondary"</span><span class="p">&gt;</span>Secondary Button<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span></code></pre></div>
  48. <p>Using only globals, we might write the CSS like this.</p>
  49. <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>
  50. <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>
  51. <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>
  52. <span class="p">}</span>
  53. <span class="p">.</span><span class="nc">btn-secondary</span><span class="p">:</span><span class="nd">hover</span> <span class="p">{</span>
  54. <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>
  55. <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>
  56. <span class="p">}</span></code></pre></div>
  57. <p>It totally works, and we can easily update our global colors later and have them automatically update the button styles.</p>
  58. <p>But there’s another way we could approach this that I think works a <em>little</em> bit better.</p>
  59. <h2 id="css-variables-scoped-to-the-element">CSS variables scoped to the element</h2>
  60. <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>
  61. <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>
  62. <p>Looking at our <code>button</code> again, I’ll often do something like this…</p>
  63. <div class="highlight"><pre class="chroma"><code class="language-css" data-lang="css"><span class="nt">button</span> <span class="p">{</span>
  64. <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>
  65. <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>
  66. <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>
  67. <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>
  68. <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>
  69. <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>
  70. <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>
  71. <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>
  72. <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>
  73. <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>
  74. <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>
  75. <span class="k">font-weight</span><span class="p">:</span> <span class="kc">normal</span><span class="p">;</span>
  76. <span class="k">line-height</span><span class="p">:</span> <span class="mf">1.2</span><span class="p">;</span>
  77. <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>
  78. <span class="p">}</span></code></pre></div>
  79. <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>
  80. <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>
  81. <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>
  82. <span class="p">}</span></code></pre></div>
  83. <p><a href="https://codepen.io/cferdinandi/pen/gOyovdE">Here’s a demo.</a></p>
  84. <h2 id="a-growing-system">A growing system</h2>
  85. <p>This approach is a little bit more work up-front, but it has bigger payoffs the more you use it.</p>
  86. <p>For example, our <code>.btn-secondary</code> class gets shorter.</p>
  87. <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>
  88. <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>
  89. <span class="p">}</span>
  90. <span class="p">.</span><span class="nc">btn-secondary</span><span class="p">:</span><span class="nd">hover</span> <span class="p">{</span>
  91. <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>
  92. <span class="p">}</span></code></pre></div>
  93. <p>With every utility class you add to modify your base styles, using element-scoped CSS variables makes things a bit easier.</p>
  94. <p>For example, we can add <code>.btn-large</code> and <code>.btn-small</code> classes by doing this…</p>
  95. <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>
  96. <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>
  97. <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>
  98. <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>
  99. <span class="p">}</span>
  100. <span class="p">.</span><span class="nc">btn-small</span> <span class="p">{</span>
  101. <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>
  102. <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>
  103. <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>
  104. <span class="p">}</span></code></pre></div>
  105. <p><a href="https://codepen.io/cferdinandi/pen/vYMpdVV">Here’s another demo.</a></p>
  106. <h2 id="should-you-always-do-this">Should you always do this?</h2>
  107. <p>Nope! It’s a lot more work, and sometimes results in code that’s a bit less readable at first glance.</p>
  108. <p>It’s a good approach to use…</p>
  109. <ul>
  110. <li>For properties that will change through modifier or utility classes.</li>
  111. <li>For design systems where end-users will need to easily override certain styles in ways you can’t predict.</li>
  112. </ul>