<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Nathan Minchow</title>
    <description>The latest articles on Forem by Nathan Minchow (@nathanminchow).</description>
    <link>https://forem.com/nathanminchow</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F328611%2F30dc40dc-499c-41e3-becb-615a9026d463.jpg</url>
      <title>Forem: Nathan Minchow</title>
      <link>https://forem.com/nathanminchow</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nathanminchow"/>
    <language>en</language>
    <item>
      <title>Let's Look at prefers-reduced-data</title>
      <dc:creator>Nathan Minchow</dc:creator>
      <pubDate>Sat, 13 Jun 2020 18:57:31 +0000</pubDate>
      <link>https://forem.com/nathanminchow/let-s-look-at-prefers-reduced-data-b5i</link>
      <guid>https://forem.com/nathanminchow/let-s-look-at-prefers-reduced-data-b5i</guid>
      <description>&lt;p&gt;I like web fonts. They are an easy way to enable consistent typography and design for a website.&lt;/p&gt;

&lt;p&gt;Still, I sometimes wonder if I ought to force my users to download a font (even if it &lt;em&gt;might&lt;/em&gt; be cached already) just to view my site. I've encountered plenty of websites filled with custom fonts and images that can take a while to load. This is especially frustrating when I only want to &lt;em&gt;read the content&lt;/em&gt;. And while I do my best to minimize the data load on my sites, I still want things to look nice by default.&lt;/p&gt;

&lt;p&gt;It would be great if users could indicate they'd prefer to minimize their data load as they browse the web, potentially at the cost of high-res images or detailed typography. That's where &lt;code&gt;prefers-reduced-data&lt;/code&gt; comes into play.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://drafts.csswg.org/mediaqueries-5/#prefers-reduced-data"&gt;&lt;code&gt;prefers-reduced-data&lt;/code&gt;&lt;/a&gt; is a user preference media feature like &lt;code&gt;prefers-color-scheme&lt;/code&gt; and &lt;code&gt;prefers-reduced-motion&lt;/code&gt;. Unlike those, &lt;code&gt;prefers-reduced-data&lt;/code&gt; is &lt;a href="https://caniuse.com/#feat=mdn-css_at-rules_media_prefers-reduced-data"&gt;not supported in any browsers yet&lt;/a&gt;, and it's functionality could change bit before we see it implemented anywhere.&lt;/p&gt;

&lt;p&gt;Curiously, &lt;code&gt;prefers-reduced-motion&lt;/code&gt;, &lt;code&gt;prefers-color-scheme&lt;/code&gt;, and &lt;code&gt;prefers-reduced-data&lt;/code&gt; (among others) were all introduced in the &lt;a href="https://drafts.csswg.org/mediaqueries-5/"&gt;Media Queries 5 &lt;/a&gt; spec from the W3C, but &lt;code&gt;prefers-reduced-data&lt;/code&gt; has not seen the progress of the other two. There are some &lt;a href="https://github.com/w3c/csswg-drafts/issues?q=is%3Aissue+is%3Aopen+label%3Amediaqueries-5+prefers-reduced-data"&gt;open questions&lt;/a&gt; related to the feature which could be slowing it down.&lt;/p&gt;

&lt;p&gt;I'm hopeful that we'll see this feature implemented sooner rather than later. The &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; elements both support media queries already, which means we could already account for images, fonts, and libraries without much work. Let's look at a potential method to prevent an image from loading if a user indicated they preferred reduced data.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;min-width&lt;/code&gt; and &lt;code&gt;max-width&lt;/code&gt; are common media queries to pair with the &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element because they allow us to load different images based on the form factor of the user's device (note that the &lt;a href="https://www.smashingmagazine.com/2014/05/responsive-images-done-right-guide-picture-srcset/"&gt;&lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element is not always necessary for this&lt;/a&gt;). In the example below, the image swaps to a different one once the width of the window shrinks below 400px.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://jsfiddle.net/5u3asd7f//embedded/result,html,css//dark" width="100%" height="600"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If we wanted to use &lt;code&gt;prefers-reduced-data&lt;/code&gt; to minimize our data load, we could adapt &lt;a href="https://medium.com/@mike_masey/how-to-use-the-picture-element-to-prevent-images-loading-on-mobile-devices-1376e33b190e"&gt;this technique from a blog post by Mike Masey&lt;/a&gt; to load a tiny, 1x1 transparent gif instead of a full image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;    &lt;span class="nt"&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; 
            &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"https://upload.wikimedia.org/wikipedia/commons/c/ce/Transparent.gif"&lt;/span&gt; 
            &lt;span class="na"&gt;media=&lt;/span&gt;&lt;span class="s"&gt;"(prefers-reduced-data: reduce)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; 
            &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unsplash.com/photos/7hQ4Y_-bSb4/download?force=true&amp;amp;w=640"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The best part about using the &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element like this is that no request is made to retrieve full image, which could save quite a bit of data for the user.&lt;/p&gt;

&lt;p&gt;We could do something similar to prevent the loading and use of web fonts (this example comes &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-data"&gt;from MDN&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"preload"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"fonts/montserrat-regular.woff2"&lt;/span&gt; &lt;span class="na"&gt;as=&lt;/span&gt;&lt;span class="s"&gt;"font"&lt;/span&gt; &lt;span class="na"&gt;media=&lt;/span&gt;&lt;span class="s"&gt;"(prefers-reduced-data: no-preference)"&lt;/span&gt; &lt;span class="na"&gt;crossorigin&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"style.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-reduced-data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;no-preference&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@font-face&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Montserrat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;font-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="py"&gt;font-display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c"&gt;/* latin */&lt;/span&gt;
        &lt;span class="nl"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;'Montserrat Regular'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;'Montserrat-Regular'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sx"&gt;url('fonts/montserrat-regular.woff2')&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;'woff2'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="py"&gt;unicode-range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;0000-00&lt;/span&gt;&lt;span class="n"&gt;FF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;0131&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;0152-0153&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;&lt;span class="n"&gt;BB-02BC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;&lt;span class="n"&gt;C6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;&lt;span class="n"&gt;DA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;&lt;span class="n"&gt;DC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;2000-206&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;2074&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="n"&gt;AC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;2122&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;2191&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;2193&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;2212&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="m"&gt;2215&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="n"&gt;FEFF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="n"&gt;FFFD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Montserrat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;-apple-system&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BlinkMacSystemFont&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;"Segoe UI"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roboto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Helvetica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;"Microsoft YaHei"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;"Apple Color Emoji"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;"Segoe UI Emoji"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;"Segoe UI Symbol"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Until browser support improves, we have other methods like the &lt;a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/save-data"&gt;Save Data HTTP header&lt;/a&gt; to help users minimize data loads when requested. Still, I think &lt;code&gt;prefers-reduced-data&lt;/code&gt; is more elegant and straightforward for developers. I'm looking forward to the day that we can use it in modern browsers.&lt;/p&gt;

&lt;p&gt;If anyone has additional thoughts or interesting use-cases for &lt;code&gt;prefers-reduced-data&lt;/code&gt;, please say so in the comments to this post. Also feel free to check out some of the &lt;a href="https://github.com/w3c/csswg-drafts/issues?q=is%3Aissue+is%3Aopen+label%3Amediaqueries-5+prefers-reduced-data"&gt;issue discussions for this feature on Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>html</category>
      <category>webdev</category>
      <category>css</category>
    </item>
    <item>
      <title>Easy Website Themes with CSS Custom Properties</title>
      <dc:creator>Nathan Minchow</dc:creator>
      <pubDate>Tue, 10 Mar 2020 14:30:50 +0000</pubDate>
      <link>https://forem.com/nathanminchow/easy-website-themes-with-css-custom-properties-1pb7</link>
      <guid>https://forem.com/nathanminchow/easy-website-themes-with-css-custom-properties-1pb7</guid>
      <description>&lt;p&gt;With the &lt;a href="https://mashable.com/article/dark-mode-apps-instagram-google-chrome-apple-ios13/"&gt;advent of dark mode&lt;/a&gt;, website theme customization is becoming an expectation instead of a feature.&lt;/p&gt;

&lt;p&gt;Plenty of websites go a step further and allow their users to select from multiple themes (like &lt;a href="https://dev.to"&gt;dev.to&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aALQnRDg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.nminchow.com/assets/dev.to_theme_picker.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aALQnRDg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.nminchow.com/assets/dev.to_theme_picker.png" alt="Dev.to theme selection page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full website theme customization may be overkill for some sites, but it's still something we ought to keep in mind when designing and developing for the web. Thankfully, modern CSS includes features that make implementing website customization easy. Most of it boils down to CSS Custom Properties.&lt;/p&gt;

&lt;h1&gt;
  
  
  CSS Properties: A Quick Overview
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/--*"&gt;CSS Custom Properties&lt;/a&gt; allow us to define reusable variables in CSS without a preprocessor. They aren't exactly &lt;em&gt;new&lt;/em&gt;; &lt;a href="https://caniuse.com/#feat=css-variables"&gt;most modern browsers have supported them since 2016&lt;/a&gt;. And since they are variables, we can update them dynamically.&lt;/p&gt;

&lt;p&gt;Custom Properties can be defined on any element by prefixing the property name with &lt;code&gt;--&lt;/code&gt;. If we wanted to create reusable properties on the &lt;code&gt;root&lt;/code&gt; element, we could define them like so (these examples are taken from &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/--*"&gt;MDN&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--first-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#488cff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--second-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ffff8c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can access these properties in child elements via the &lt;code&gt;var()&lt;/code&gt; keyword:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nf"&gt;#firstParagraph&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--first-color&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--second-color&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;#secondParagraph&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--second-color&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--first-color&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;#container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--first-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#48ff32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see this in action, I've defined three different colors in the example below. When the checkbox is toggled, the CSS properties update and colors change wherever they are referenced:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/nathanspenner/embed/LYVxpjP?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Custom Properties can do a lot of useful things. I recommend reading &lt;a href="https://www.smashingmagazine.com/2018/05/css-custom-properties-strategy-guide/"&gt;this excellent article&lt;/a&gt; by Michael Riethmuller for a more in-depth look at CSS Custom Properties, how to use them, and how they differ from preprocessor variables.&lt;/p&gt;

&lt;h1&gt;
  
  
  Theme Customization Use Cases
&lt;/h1&gt;

&lt;p&gt;Since Custom Properties can be reused and updated dynamically, they are a good fit for theme customization. Let's look at how we can use Custom Properties to customize a site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Dark Mode
&lt;/h2&gt;

&lt;p&gt;The most straightforward way to add a dark mode to your site is via the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme"&gt;&lt;code&gt;prefers-color-scheme&lt;/code&gt;&lt;/a&gt; media query. This media query typically corresponds to the theme of the user's operating system.&lt;/p&gt;

&lt;p&gt;So, if we have some scoped properties defined like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;    &lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="py"&gt;--primary-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;cyan&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="py"&gt;--secondary-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;orange&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="py"&gt;--tertiary-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;yellow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can simply update their values in the media query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;    &lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="py"&gt;--primary-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;gray&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="py"&gt;--secondary-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;darkgray&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="py"&gt;--tertiary-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lightgray&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And any elements using those properties will update dynamically when the user's theme changes. Here's how that might look in practice:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SuVwAF7S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.nminchow.com/assets/prefers_color_scheme.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SuVwAF7S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.nminchow.com/assets/prefers_color_scheme.gif" alt="Operating system color selection reflected on a webpage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Theme Selection
&lt;/h2&gt;

&lt;p&gt;While &lt;code&gt;prefers-color-scheme&lt;/code&gt; is a great starting point, sometimes we want to give the user the ability to select a theme at will.&lt;/p&gt;

&lt;p&gt;If you've designed your site to take advantage of Custom Properties, we can accomplish this fairly easily. All we need to do is modify them, which we can do via CSS or Javascript.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modify Custom Properties with CSS
&lt;/h3&gt;

&lt;p&gt;Custom Properties, like any other CSS, can be updated as long as we have the proper selector.&lt;/p&gt;

&lt;p&gt;If you examine the CSS from my earlier example, you'll notice that I've scoped my Custom Properties to the &lt;code&gt;main&lt;/code&gt; element. When the checkbox is toggled, a selector updates the scoped properties inside it. This causes all elements within the &lt;code&gt;main&lt;/code&gt; element to update with the new values:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/nathanspenner/embed/LYVxpjP?height=600&amp;amp;default-tab=css,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;While this method is pretty quick to implement, CSS selectors can be somewhat fickle (and dependent on our HTML). Furthermore, in most cases we'd want to save a user's theme choice. Javascript gives us more flexibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modify Custom Properties with Javascript
&lt;/h3&gt;

&lt;p&gt;We can use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration/setProperty"&gt;&lt;code&gt;setProperty()&lt;/code&gt; method&lt;/a&gt; to update our Custom Properties from Javascript.&lt;/p&gt;

&lt;p&gt;If we have some Custom Properties scoped to a &lt;code&gt;main&lt;/code&gt; element, we can query for it in our Javascript and call &lt;code&gt;setProperty()&lt;/code&gt; to update its properties to new values:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/nathanspenner/embed/zYGEVGx?height=600&amp;amp;default-tab=js,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;It's common to see Custom Properties defined in the &lt;code&gt;:root&lt;/code&gt; pseudo-class. In that case, the Custom Properties can be updated by calling &lt;code&gt;setProperty&lt;/code&gt; on the root element:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/nathanspenner/embed/QWbqXKY?height=600&amp;amp;default-tab=js,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;While those examples only altered a few &lt;code&gt;div&lt;/code&gt; elements, the same technique can be used to alter the theme for an entire site. To demonstrate this, I modified &lt;a href="https://html5up.net/read-only"&gt;a template from HTML5UP&lt;/a&gt; to use Custom Properties for most backgrounds, text colors, and accents. Then, I added a toggle button that updates those properties with dark values instead:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4vLfVX6C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.nminchow.com/assets/theme_demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4vLfVX6C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.nminchow.com/assets/theme_demo.gif" alt="Custom portfolio site with toggle theme button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code for the theme switch is very similar to the CodePens above. I define a couple "Theme" objects in my Javascript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;darkTheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--accent-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#4acaa8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--background-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#343737&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--active-scroll-background&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#343737&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--color-text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--sidebar-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#444c48&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lightTheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--accent-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#4bcdab&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--background-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#f0ffff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--active-scroll-background&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#f0ffff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--color-text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#777&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--sidebar-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#4bcdab&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, when the toggle button is pressed, I update the Custom Properties I've defined on the root element with properties from a given "Theme":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;applyTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--accent-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--accent-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--background-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--background-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--active-scroll-background&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--active-scroll-background&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--color-text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--color-text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--sidebar-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--sidebar-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feel free to take a look at the preview &lt;a href="https://nspenner.github.io/theme-lab/"&gt;here&lt;/a&gt;, with the source code available &lt;a href="https://github.com/nspenner/theme-lab"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By implementing theme customization like this, adding a new theme to the site is as simple as creating a new theme object. We could save a user's preference via &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage"&gt;local storage&lt;/a&gt; or a database depending on what tools we have available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Color Selection
&lt;/h2&gt;

&lt;p&gt;Some websites and apps allow users to create and modify themes directly. Once again, we can use &lt;code&gt;setProperty()&lt;/code&gt; to update a Custom Property with any value, including ones exposed for input.&lt;/p&gt;

&lt;p&gt;In the Codepen below, the colors of the first square and the borders of all squares are exposed as input elements. When the form is submitted, these values are updated and are reflected in the result:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/nathanspenner/embed/yLNPExq?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Naturally, we could extend this to expose the various properties used on an entire website or application. Those preferences could then be exported or saved to remember a user's choice (or to allow users to share themes). &lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Custom Properties allow us to make sweeping changes to our website without much work. This makes them a great tool for implementing theme customization, whether for automatically detecting a user's theme preference with &lt;code&gt;prefers-color-scheme&lt;/code&gt; or allowing them to pick (and potentially modify) their own themes.&lt;/p&gt;

</description>
      <category>css</category>
      <category>html</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Creating a Resume in HTML and CSS</title>
      <dc:creator>Nathan Minchow</dc:creator>
      <pubDate>Tue, 04 Feb 2020 15:48:59 +0000</pubDate>
      <link>https://forem.com/nathanminchow/creating-a-resume-in-html-and-css-5258</link>
      <guid>https://forem.com/nathanminchow/creating-a-resume-in-html-and-css-5258</guid>
      <description>&lt;p&gt;Standard word processors don't hold a candle to HTML and CSS when it comes to controlling the finer details of styling and layout. I've had difficulty fine-tuning my resume in a word processor, so I started using HTML and CSS to create and maintain my resume instead. I've found it to work a lot better overall, but there are a few helpful things to know before beginning the transition.&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting Started
&lt;/h1&gt;

&lt;p&gt;First, a disclaimer: this guide is not meant to provide resume templates or styling advice. Rather, I'm detailing a process for handling a resume print layout in HTML/CSS. This includes setup, print styling, and a final PDF export.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wireframe
&lt;/h2&gt;

&lt;p&gt;It's much easier to write HTML and CSS when working from a mockup or wireframe. I used an old resume from Word as my baseline, but you could just as easily mock something up in a free tool like &lt;a href="https://www.adobe.com/products/xd.html"&gt;Adobe XD&lt;/a&gt; or &lt;a href="https://www.figma.com/"&gt;Figma&lt;/a&gt; (Figma even supports print sizes by default).&lt;/p&gt;

&lt;p&gt;If you already have content from a past resume ready to go (like I did), you can break out your design into sections and add the details later:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UAxEFEfv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qeaqk9f8l2oi1da9u5wd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UAxEFEfv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qeaqk9f8l2oi1da9u5wd.png" alt="Wireframe of resume built in Figma"&gt;&lt;/a&gt;&lt;/p&gt;
Wireframe of resume built in Figma



&lt;p&gt;We don't have to adhere to the exact styling of a template or mockup, but it can be useful for organizing the overall layout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a "Canvas"
&lt;/h2&gt;

&lt;p&gt;To better visualize your resume as you code, I'd recommend creating a "canvas" – an HTML container with the same proportions as your resume. By placing this container on an empty page, you'll get a view very similar to a typical word processor:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S5dnmyWm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4h5l8z53ww4iz029fq9b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S5dnmyWm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4h5l8z53ww4iz029fq9b.png" alt="Canvas example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can actually use physical measurement units in CSS (even though they end up &lt;a href="https://css-tricks.com/the-lengths-of-css/"&gt;mapping to pixels anyway&lt;/a&gt;), so it was quite easy to set this canvas up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.canvas-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* for centering, feel free to use flexbox or some other method*/&lt;/span&gt;
  &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5in&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* controls margins */&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8.5in&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;11in&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;-3px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what that might look like on a barebones page (use 0.5x or 0.25x zoom for the best effect):&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/nathanspenner/embed/wvBVWvr?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
 &lt;/p&gt;

&lt;p&gt;Use your canvas container to set default styles on your entire page, similar to defaults in a word processor. Other good properties to consider adding here are &lt;code&gt;line-height&lt;/code&gt; and font properties like &lt;code&gt;font-size&lt;/code&gt; and &lt;code&gt;font-family&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Layout and Content
&lt;/h1&gt;

&lt;p&gt;Using your wireframe for reference, map out how you will divide your canvas space into sections of content. This is where tools like &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Grid"&gt;Flexbox&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Grid"&gt;Grid&lt;/a&gt; will come in handy if your layout is more complex.&lt;/p&gt;

&lt;p&gt;My setup was fairly straightforward: each area of my resume was broken into a &lt;code&gt;section&lt;/code&gt; element. Whenever I had content spanning two columns, I used a grid to split them up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.multicolumn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what that looks like in practice:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/nathanspenner/embed/povMyXK?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
 &lt;/p&gt;

&lt;p&gt;In my resume, I only needed a multicolumn layout for two sections, &lt;strong&gt;Experience&lt;/strong&gt; and &lt;strong&gt;Certifications / Skills&lt;/strong&gt;. I hid the content, but here's how those grids are situated on my current layout:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vxSMTzHq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jcg465dlj6rjfq2npubn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vxSMTzHq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jcg465dlj6rjfq2npubn.png" alt="HTML document container with grid lines"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One added bonus of using something like &lt;code&gt;grid&lt;/code&gt; is maintainability; I could very easily add another instance of work experience and have the grid automatically adjust without destroying the rest of my layout:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ee1EdtTY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zoxc790z098ja798bp19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ee1EdtTY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zoxc790z098ja798bp19.png" alt="HTML document container with more grid lines"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apart from using &lt;code&gt;grid&lt;/code&gt; in those two instances, everything else fit nicely into sections using &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Normal_Flow"&gt;normal flow&lt;/a&gt;. Feel free to use whatever works best for you.&lt;/p&gt;
&lt;h1&gt;
  
  
  Exporting
&lt;/h1&gt;

&lt;p&gt;Most companies and recruiters won't accept an HTML page as a valid resume. Therefore, you'll want to export your page as a PDF. Browsers can do this readily via the Print command, but we'll need to do some adjustments to our CSS beforehand.&lt;/p&gt;
&lt;h2&gt;
  
  
  Print Styles
&lt;/h2&gt;

&lt;p&gt;We'll be taking advantage of the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media"&gt;print media query&lt;/a&gt; to style our exported page. It allows us to apply styles specifically when a browser attempts to print.&lt;/p&gt;

&lt;p&gt;If you followed my advice of building everything inside a container, this should be a straightforward process. For simplicity, I made the entire &lt;code&gt;html&lt;/code&gt; element's width and height match the print size of my container. You may also need to remove any margins (and box-shadows!) for elements between the &lt;code&gt;body&lt;/code&gt; and your container, otherwise the added space might cause an extra page to render:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;11in&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8.5in&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nc"&gt;.canvas-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Generating a PDF
&lt;/h2&gt;

&lt;p&gt;With browser styles in place, we can use the browser's Print dialog to save our page as a PDF.&lt;/p&gt;

&lt;p&gt;While I love Firefox, Blink's Print functionality tends to do a much better job of accurately exporting a page. I used Chrome for my final export – as detailed in the following instructions.&lt;/p&gt;

&lt;p&gt;After opening the print dialog, set your Destination to "Save as PDF". Additionally, you'll want to adjust a few settings before saving the final result. Expand the "More settings" option and check the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Color is enabled if you are using anything other than shades of gray&lt;/li&gt;
&lt;li&gt;Paper size is set to your preferred size (I used Letter throughout this guide)&lt;/li&gt;
&lt;li&gt;Margins should be set to None&lt;/li&gt;
&lt;li&gt;Scale should be set to 100&lt;/li&gt;
&lt;li&gt;Background Graphics are enabled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1FyRBBOm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/di4qn5y0o48ju7o3j3qh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1FyRBBOm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/di4qn5y0o48ju7o3j3qh.png" alt="Chrome Print Dialog Settings"&gt;&lt;/a&gt;&lt;/p&gt;
Example of Chrome's print dialog with proper settings for PDF export



&lt;p&gt;Go ahead and save the page. With that, you should have both an easily maintainable HTML resume and a PDF export to use for actual applications.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I hope this guide was a helpful starting point in how to create a resume in HTML and CSS.&lt;/p&gt;

&lt;p&gt;If you're curious for what my final result was, the source code for my current implementation is available &lt;a href="https://github.com/nspenner/portfolio/tree/master/pages/resume"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you've gone through this process or have any additional tips for handling a print layout in HTML/CSS, please let me know in the comments below.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post originally appeared on &lt;a href="https://blog.nminchow.com/2020-01-30/resume-redo"&gt;my personal blog&lt;/a&gt;, with a few modifications here for brevity.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>career</category>
      <category>html</category>
      <category>resume</category>
    </item>
  </channel>
</rss>
