<?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>DEV Community: Kevin Pennekamp</title>
    <description>The latest articles on DEV Community by Kevin Pennekamp (@vyckes).</description>
    <link>https://dev.to/vyckes</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%2F14404%2F8c9873e6-1703-4441-a769-3ee3f8a18a20.png</url>
      <title>DEV Community: Kevin Pennekamp</title>
      <link>https://dev.to/vyckes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vyckes"/>
    <language>en</language>
    <item>
      <title>A nth-child CSS trick</title>
      <dc:creator>Kevin Pennekamp</dc:creator>
      <pubDate>Wed, 25 Jan 2023 15:27:06 +0000</pubDate>
      <link>https://dev.to/vyckes/a-nth-child-css-trick-413c</link>
      <guid>https://dev.to/vyckes/a-nth-child-css-trick-413c</guid>
      <description>&lt;p&gt;Sometimes you figure out a cool trick that just feels so powerful. It opens you up to a range of new possibilities. That you, quite frankly, rarely use. But still, it is a cool trick. For me, the latest of these tricks is setting a CSS custom property value, corresponding with the &lt;code&gt;:nth-child&lt;/code&gt; value. Why? Because now we can use the &lt;code&gt;--nth-child&lt;/code&gt; custom property inside &lt;code&gt;calc()&lt;/code&gt; functions. &lt;/p&gt;

&lt;h2&gt;
  
  
  But why not use X?
&lt;/h2&gt;

&lt;p&gt;Sure, in most, if not all, of my projects I use SCSS instead of CSS. But CSS is getting more and more features, making SCSS redundant for me. Looking at you &lt;a href="https://www.w3.org/TR/css-nesting-1/" rel="noopener noreferrer"&gt;CSS nesting&lt;/a&gt;. With each trick or implementation, you can remove another dependency on SCSS, and go back to plain CSS. Using &lt;code&gt;@for-&lt;/code&gt;loops makes it easy to achieve the same result. But you will generate roughly the same CSS selector several times.   &lt;/p&gt;

&lt;p&gt;You might also think using &lt;code&gt;:nth-child(n)&lt;/code&gt; would allow you to achieve the same, without all the custom properties. Unfortunately, the &lt;code&gt;n&lt;/code&gt; is not useable in the &lt;code&gt;calc()&lt;/code&gt; function. So, we use custom properties.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to set it up
&lt;/h2&gt;

&lt;p&gt;On the highest level of your CSS, you define a list like the one below. This results in all elements having access to a &lt;code&gt;--nth-child&lt;/code&gt; custom property. At least as long as you don’t exceed the length of your list.&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;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--nth-child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--nth-child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--nth-child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--nth-child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--nth-child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What can we do with this trick?
&lt;/h2&gt;

&lt;p&gt;Glad you asked! In the last few years, I came across two use cases. Two, whole, use cases. In the latest use case, I wanted to automatically generate a color palette. Not to match a branding of a company. But to automatically populate different series of data in a chart. With this trick, we can do that with a single line.&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;background-color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;hsl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;calc&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nt"&gt;var&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;--nth-child&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="err"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="err"&gt;40&lt;/span&gt;&lt;span class="o"&gt;%);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In an earlier use case, I replicated the UI implementation of toasts from &lt;a href="https://vercel.com/design/toast" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt;. On the link, you see a list of toast messages stacked with a little bit of perspective. I originally used an SCSS implementation, looking like the snippet below. Note it uses &lt;code&gt;:nth-last-of-type&lt;/code&gt;, given the reversed order and bottom orientation. But the general idea remains the same.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@for&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="ow"&gt;from&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;through&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;:nth-of-type&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="mi"&gt;.15&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="nf"&gt;translate3d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="nf"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;px&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;-1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
          &lt;span class="nf"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="nf"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="mi"&gt;.05&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&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;This would create twenty different CSS selectors, all with a different value for &lt;code&gt;$i&lt;/code&gt;. But using this little trick, we can reduce the code, and make it more maintainable in the process.&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;.class&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;/* We want to start counting at 0 */&lt;/span&gt;
    &lt;span class="py"&gt;--v&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;--nth-last-child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&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;-&lt;/span&gt; &lt;span class="n"&gt;calc&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;--v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="m"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;translate3d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-5px&lt;/span&gt; &lt;span class="err"&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;--v&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; 
            &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-1px&lt;/span&gt; &lt;span class="err"&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;--v&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; 
        &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calc&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;-&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;--v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="m"&gt;0.05&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;That was it. That was my latest CSS trick.&lt;/p&gt;

</description>
      <category>css</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Creating a stacked bar chart using only CSS</title>
      <dc:creator>Kevin Pennekamp</dc:creator>
      <pubDate>Mon, 23 Jan 2023 08:37:12 +0000</pubDate>
      <link>https://dev.to/vyckes/creating-a-stacked-bar-chart-using-only-css-3jc1</link>
      <guid>https://dev.to/vyckes/creating-a-stacked-bar-chart-using-only-css-3jc1</guid>
      <description>&lt;p&gt;In various projects, I always seem to struggle with responsive charts. These libraries generate charts in SVGs, often with fixed dimensions or ratios. This means that different screen sizes either get additional whitespace, or parts of the chart get hidden. Horrible. So I gave myself a challenge to create a responsive CSS-only bar chart, the one visualized below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F72rw8t3ss451q2lh5qzg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F72rw8t3ss451q2lh5qzg.gif" alt="GIF with the expected result" width="1024" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The base of the chart
&lt;/h2&gt;

&lt;p&gt;Alright, let’s first make the graph itself. The graph is nothing more than multiple bars aligned horizontally. Or, you know, in a &lt;code&gt;row&lt;/code&gt;. As we want all the bars to stick to the bottom, we need to set &lt;code&gt;align-items: flex-end&lt;/code&gt;. Floating bars from the top look cool, but in the end, add little value to most charts. The &lt;code&gt;gap&lt;/code&gt; is needed to tell each of the bars apart.&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;.chart&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;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex-end&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;2px&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"chart"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can start defining our bars. Each of the bars is a vertical stack of sections. So, a flexbox with the direction &lt;code&gt;column&lt;/code&gt; would suffice. With the &lt;code&gt;flex-grow: 1&lt;/code&gt; we ensure the bars fill up all the available horizontal space equally. As you can see in the example, we do expect that a bar that is being hovered gets more space. This allows us to display values with the bar the user is (kinda) interacting with.&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;.bar&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;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;flex-grow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.bar&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;flex-grow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6&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;
  
  
  The size of the bars
&lt;/h2&gt;

&lt;p&gt;Now we only need to determine the height of each of the bars. Ideally, I would have liked to use a &lt;code&gt;data-*&lt;/code&gt; attribute. Reading values in CSS from these attributes can be done using the &lt;code&gt;attr()&lt;/code&gt; function, as it only works with string values, and. But unfortunately, that will not work. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;attr()&lt;/code&gt; function can only work with string values. This means it only has value for the &lt;code&gt;content&lt;/code&gt; attribute in CSS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The only way I could make it work is by adjusting custom properties via the &lt;code&gt;style&lt;/code&gt; attribute on the HTML element, like shown below. It’s not a solution I prefer, but for our use case, it does work. And combined with modern JavaScript frameworks it is often hidden for developers in custom UI components.&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"chart"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bar"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"--bar-ratio: 68%;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see in both the HTML snippet above and the CSS snippet below, we are working with percentages. To have the chart scale nicely, we need to give the bar with the highest value a height of &lt;code&gt;100%&lt;/code&gt;, and all others scale according to their values.&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;.bar&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="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--bar-ratio&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Stacking the bars
&lt;/h2&gt;

&lt;p&gt;As we are looking at a stacked bar chart, we need to add sections to each of the bars. We already know that a bar is set up as a vertical flexbox. To ensure each section fills up the space of the bar corresponding to their value. If we have three sections with values &lt;code&gt;10&lt;/code&gt;, &lt;code&gt;20&lt;/code&gt;, and &lt;code&gt;30&lt;/code&gt;, we can achieve the result to set &lt;code&gt;flex-grow&lt;/code&gt; to this value. In summary, &lt;code&gt;flex-grow: var(--value)&lt;/code&gt;. Like with the height of the bar, we need to inject the value through the &lt;code&gt;style=“--value: 30;”&lt;/code&gt; tag.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the value is small compared to the other sections, other CSS attributes, such as padding, might impact the correct distribution.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.section&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;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;flex-grow&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;--value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.section&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;flex-grow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="err"&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;--value&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;From a user experience perspective, we want to highlight the section on interactivity, i.e. hover. By simply expanding the &lt;code&gt;flex-grow&lt;/code&gt;, just like with the bar, we get the effect that we want. Both the bar within the entire chart, as the section in the bar is expanding in size on hover.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improve the experience
&lt;/h2&gt;

&lt;p&gt;Stacked bar charts visualize different series of data. Each nth section of a bar belongs to the same series of data. This means we need to have a way to indicate that they belong to each other. In most libraries, you can define a set of colors. But I wanted a more CSS-only solution. I already deviated from this by setting values through the &lt;code&gt;style&lt;/code&gt; attribute. So I want to avoid more deviation. &lt;/p&gt;

&lt;p&gt;A nifty little trick that I learned is setting a &lt;code&gt;--nth-child&lt;/code&gt; custom property in the root of your styling, as shown below. This makes it possible to use these values with the &lt;code&gt;calc()&lt;/code&gt; function.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You might think using &lt;code&gt;:nth-child(n)&lt;/code&gt; would allow you to achieve the same, without all the custom properties. Unfortunately, the &lt;code&gt;n&lt;/code&gt; is not useable in the &lt;code&gt;calc()&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--nth-child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--nth-child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--nth-child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--nth-child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--nth-child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;:::&lt;br&gt;
If you have different types of children within a parent, you can use &lt;code&gt;:nth-of-type&lt;/code&gt;. This does target HTML tags. If you only use &lt;code&gt;&amp;lt;div /&amp;gt;&lt;/code&gt; it will make no difference.&lt;br&gt;
:::&lt;/p&gt;

&lt;p&gt;Now we have a variable that we can use to indicate the index of an element. We can use math to visualize sections of the same series. Examples are &lt;code&gt;background-color&lt;/code&gt; or &lt;code&gt;opacity&lt;/code&gt;. Let’s go for background-color. The easiest way would be to use the &lt;code&gt;hsl()&lt;/code&gt; function and change the degrees of the colors, as shown below. As there are 256 degrees, taking a base of 100 gives us at least six different colors, before colors (almost) start looking the same.&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;.section&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;hsl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="err"&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;--nth-child&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt; &lt;span class="m"&gt;40%&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;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;By combining different forms of flexbox, &lt;code&gt;:hover&lt;/code&gt; and some small tricks, we can create a nice responsive bar chart. The only downside is you need to bind the values via the &lt;code&gt;style&lt;/code&gt; attribute in the HTML templates. This should not be an issue in most modern frameworks. But, it is still something to be aware of. Curious about the live example? Then visit &lt;a href="https://codepen.io/kevtiq/pen/QWaQVMb" rel="noopener noreferrer"&gt;this codepen.io&lt;/a&gt; link.&lt;/p&gt;

</description>
      <category>learning</category>
    </item>
    <item>
      <title>Authentication token management</title>
      <dc:creator>Kevin Pennekamp</dc:creator>
      <pubDate>Thu, 18 Nov 2021 13:24:43 +0000</pubDate>
      <link>https://dev.to/vyckes/authentication-token-management-2669</link>
      <guid>https://dev.to/vyckes/authentication-token-management-2669</guid>
      <description>&lt;p&gt;In several large projects (React-based SPA applications) managing authentication tokens is a challenge. These solutions implement an OAuth flow using access and refresh tokens. Many of these types of applications live in an enterprise or business setting. This means users are often logged in to the application a lot longer than the access token is valid. The access token needs to be refreshed in the background.&lt;/p&gt;

&lt;p&gt;But that is not the only issue. Many pages need more than one &lt;code&gt;GET&lt;/code&gt; request when it is loaded. This adds an extra dimension to the issue. A dashboard where each card requires different data is a good example. Many solutions cannot handle such a situation and result in many refresh attempts that happen at the same time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The flow of the solution
&lt;/h2&gt;

&lt;p&gt;Solving this issue in complex applications can be done in several ways. A brute-force way is to refresh the access token on each outgoing request, or page navigation. But this means that every user action requires at least one more network request. This would decrease the performance of the application, and thus the user experience.&lt;/p&gt;

&lt;p&gt;A second solution would refresh when you hit a &lt;code&gt;401&lt;/code&gt; HTTP error (unauthorized) from the server. This would create a hit on user experience only once within the expiration timeframe. But this hit can be significant. First, we have to do a request to the server. We get back a &lt;code&gt;401&lt;/code&gt;. Now we have to refresh the tokens and execute the requests again. Three requests instead of one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2lorrcmmmzsainws61du.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2lorrcmmmzsainws61du.png" alt="Image description" width="800" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My proposed solution is to proactively refresh the token. We know when it expires. Before each request, we can check if the token is expired. When this happens, we can send refresh the token before we execute the original request. The user experience is less decreased compared to the previous solution. But this solution still has an issue. It cannot handle many requests at the same time that need refreshing. By introducing a &lt;code&gt;queue&lt;/code&gt; and an extra check, this can be solved. All requests that need to be sent out while the application is refreshing are put in the queue. Once refreshing is complete, the queue is emptied.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;The core of this solution is replacing the standard fetch requests, with a &lt;code&gt;fetchOrRefresh&lt;/code&gt; request. An example implementation can be seen in the code block below.&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;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;refreshing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;expiresOn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2021-11-01T00:00:00.000Z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchOrRefresh&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expiresOn&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;refreshing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;refreshing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;refresh&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;refreshing&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;refreshing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;The example also uses a simple object to store information, but a central application state that can be used is a better solution. Lastly, the refresh function itself is not filled in. When you solve two 'blanks' you are able to use this code as middleware in libraries like &lt;code&gt;axios&lt;/code&gt; and &lt;code&gt;redux&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Large applications used in a business setting often see long user sessions. This requires us to ensure authentication tokens are refreshed in the background. But, complex applications have many requests happening at the same time. Many solutions cannot handle this and result in many refresh attempts. The flow and code example introduced in this post can help you overcome these issues without impacting the user experience.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>architecture</category>
      <category>react</category>
    </item>
    <item>
      <title>Code stability and interdependencies</title>
      <dc:creator>Kevin Pennekamp</dc:creator>
      <pubDate>Wed, 15 Sep 2021 17:39:37 +0000</pubDate>
      <link>https://dev.to/vyckes/code-stability-and-interdependencies-f1b</link>
      <guid>https://dev.to/vyckes/code-stability-and-interdependencies-f1b</guid>
      <description>&lt;p&gt;As engineers, we have the tendency to over-engineer our solutions, make our code as reusable as possible. We make our code DRY (don't repeat yourself). Although these are good rules to go by in most cases, they can also lead to problematic maintenance issues. In our DRY-quest, we can create unstable, yet reusable code that is used in more than one place. Sometimes it is ok to write our code WET (write everything twice). Why? Because it creates more stable code around interdependencies. &lt;/p&gt;

&lt;h2&gt;
  
  
  The stability rule
&lt;/h2&gt;

&lt;p&gt;The stability rule is very simple. In this rule, stability means the &lt;em&gt;likeliness the code will change&lt;/em&gt;. Every function, module, or UI component we write, is as stable as the lowest stability of its dependencies. Think about it. If a dependency changes, our code has to (potentially) change as well. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every function, module, or UI component we write, is as stable as the lowest stability of its dependencies&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But how do you determine the stability of dependencies? This is, unfortunately, no exact science. It depends heavily on the type of dependency as well. We can set third-party packages to fixed version numbers, making them very stable. We can assume browsers API will, &lt;a href="https://www.techradar.com/news/google-reverses-embarrassing-website-breaking-chrome-update" rel="noopener noreferrer"&gt;most likely&lt;/a&gt;, not change. But the code we write ourselves can change. You can measure how many times a function/module changes, or you can make a guess how likely it will change. In both cases, you can give a function or module a &lt;em&gt;score&lt;/em&gt; of its stability. With this score, you can create a &lt;em&gt;dependency graph&lt;/em&gt; of your codebase, like the one below. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flj2cr3s92yy6l4bhupf7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flj2cr3s92yy6l4bhupf7.png" alt="Alt Text" width="800" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above graph, we see that 'Function B' is dependent on 'Function A' and 'Package A'. Function B uses Function A and Package A. All elements also got a score attached. The higher the score, the more stable the element. The ones with a keen eye will see the above dependency graph is actually wrong. It does not comply with the stability rule. The score of 'Component A' cannot be 7, as they depend on a function with lower stability. We have either have to update the graph or change our code. &lt;/p&gt;

&lt;h2&gt;
  
  
  Splitting code
&lt;/h2&gt;

&lt;p&gt;Based on mismatching stability scores, we can find possible improvements. It allows us to reorder code to improve its stability. But, it also allows for conscious decisions to not change anything at all. In our example, it is highly likely that 'Function B' is only unstable because it has some code only used for 'Component B'. At this point we have three options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Split 'Function B' into two functions. One function contains stable code used by both components. Another function contains code used by 'Component B'.&lt;/li&gt;
&lt;li&gt;Migrate the unstable part of 'Function B' to 'Component B'. This makes 'Function B' smaller, but more stable. &lt;/li&gt;
&lt;li&gt;Don't change anything.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We find ourselves with these examples more often than we would like to admit. How many times have you thought: "if I add this option to the function, I can use it here as well". This is the moment where we need to look at the dependencies and their stabilities. Only then will we achieve stable code. &lt;/p&gt;

&lt;h2&gt;
  
  
  Systems, architecture, and patterns
&lt;/h2&gt;

&lt;p&gt;Most of our time spent during development is around unstable code. We focus on implementing UI and features that are each unique and add a different value to a user or business. This makes the code by default less reusable. But, these features are built upon systems, architectural decisions, and patterns. These dependencies allow us to stabilize a certain core of the application. Some examples: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A design system or UI library provides stable low-level UI components that can be used in many different UI components. Think of input fields, buttons, tables, or even cards. &lt;/li&gt;
&lt;li&gt;In React you can create generic hooks abstracting low-level logic (e.g. fetching data, including loading state). &lt;/li&gt;
&lt;li&gt;Standardized object validation logic through libraries as &lt;a href="https://github.com/jquense/yup" rel="noopener noreferrer"&gt;Yup&lt;/a&gt; or &lt;a href="https://github.com/crinklesio/schematiq#object-validation" rel="noopener noreferrer"&gt;schematiq&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;Standardize fetch requests and state management around basic CRUD operations. &lt;/li&gt;
&lt;li&gt;Adopt an architecture or design patterns (e.g. &lt;a href="https://github.com/crinklesio/reference-architecture" rel="noopener noreferrer"&gt;client-side reference architecture&lt;/a&gt;) that help you determine which parts should be stable. Patterns and consistent architecture help to create imaginary boundaries between functions and modules as well. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And many more ways can be found to stabilize parts of your codebase. Everybody following a recent tutorial knows packages like &lt;code&gt;lodash&lt;/code&gt;. These packages or ideas, regardless if you build them yourself, or download them, help you create maintainable code. &lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Determining the correct interdependencies on code stability is no exact science. You can measure how often code changes. But, when determining interdependencies, you have to look into the future. You have to determine how &lt;em&gt;likely&lt;/em&gt; code is to change in the future. This is not something you do every day. You are not going to create a dependency graph for each change. But having a sense of stability on various levels helps a lot. You will see the &lt;em&gt;quality&lt;/em&gt; of your code increase and become more &lt;em&gt;maintainable&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>Demystifying state management</title>
      <dc:creator>Kevin Pennekamp</dc:creator>
      <pubDate>Thu, 26 Aug 2021 05:52:21 +0000</pubDate>
      <link>https://dev.to/vyckes/demystifying-state-management-2c1c</link>
      <guid>https://dev.to/vyckes/demystifying-state-management-2c1c</guid>
      <description>&lt;p&gt;State management is one of the most complicated, and opinionated topics in modern and JavaScript-focused front-end development. But at its core, it is not that complicated. We just make it complicated. In this article I will try to demystify state and state management for you, and challenge your mental models around them. &lt;/p&gt;

&lt;h2&gt;
  
  
  What are state and state management?
&lt;/h2&gt;

&lt;p&gt;Is state some weird data storage? Is it the data from a database? No. State is nothing more than a JavaScript value that lives within in scope. It can be a boolean, a string, but is in most cases a (complex) object. But it remains a value. In most cases, it is even an object living on the same level as the &lt;code&gt;window&lt;/code&gt; object. It has become a global value in the JavaScript environment, the browser window. From our code (e.g. UI components), we can use this value to determine what to show or what interactions to allow. In complex applications there are a few different types of state we can have. But remember, they are nothing more than values.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local&lt;/strong&gt;: state that is used by a single UI component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared&lt;/strong&gt;: state that is used by many UI components. It is often managed in a parent or wrapper component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global&lt;/strong&gt;: a special kind of &lt;em&gt;shared&lt;/em&gt; state, as it lives on the highest level, accessible to all UI components (or even helper functions).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Meta&lt;/strong&gt;: also known as 'state about state'. It tells you something about&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Route&lt;/strong&gt;: state stored in the current URL of the application (e.g. object IDs or pagination information).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remote&lt;/strong&gt;: a copy of the data coming from a server. The responses of fetch requests are stored as 1-on-1 copies in this state. It should not deviate from the server (except when applying &lt;a href="https://www.smashingmagazine.com/2016/11/true-lies-of-optimistic-user-interfaces/" rel="noopener noreferrer"&gt;optimistic UI&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So what about state management? For many, state management feels like a black box. What is happening within Redux? Why does it feel so complicated. I look at it this way: state management is nothing more than patterns we use to make using and changing state, manageable. It is not black box magic, it is just patterns. Why not group all the mutations you can make on your state in one place? And how about giving these mutations simple, but understandable names? In complex applications, adopting these types of patterns makes our code more maintainable. Or so they say (it is true though). In the sections below, we go deeper into different kind of state management patterns. &lt;/p&gt;

&lt;h2&gt;
  
  
  Event-driven pattern
&lt;/h2&gt;

&lt;p&gt;The best-known pattern is the flux pattern. It gained popularity with the 'Redux' package. It is a great example of an event-driven pattern. Let's take a closer look at its flow. The user, via the view, dispatches an action, via an action creator. It might seem daunting or overly complex. But it is nothing more as I said before. It is a way to group all possible state mutations together, and allow us to use simple 'actions' with memorable names from our UI components.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7xa0exqvu0q9y708fbjz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7xa0exqvu0q9y708fbjz.png" alt="Alt Text" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Such a pattern allows us to keep the code in our UI components small and clean. When hitting an issue where our state takes the wrong shape, we know where to look. That is why it is called state management. &lt;/p&gt;

&lt;p&gt;A core concept that came with this pattern are &lt;em&gt;reducers&lt;/em&gt;. Reducers are these big complex switch statements that hold all our state mutation logic. They can really feel like a black box sometimes. But don't get fooled. The concept is really simple. When removing the complexity of the switch statement your are left with something like the snippet below. A reducer is a simple function that gets a state and returns a state. Nothing more, nothing less. It uses additional input to mutate the state in between, or don't do anything at all.&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="nf"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;newState&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;Redux relies heavily on reducers. When setting things up, you add all your reducers to your Redux store. Redux really takes event-driven from server-side patterns at heart. All reducers are allowed to act upon the dispatched actions. However, I cannot say I have seen this happen in production(-like) environment. &lt;/p&gt;

&lt;p&gt;Event-driven state management is related to &lt;a href="https://statecharts.dev/" rel="noopener noreferrer"&gt;state machines&lt;/a&gt;. State machines allow us to clearly define the shape of the state, and when which mutation is allowed. Below is an example of a state machine for an animated toast message. This toast message should disappear after X seconds. The &lt;a href="https://redux.js.org/style-guide/style-guide#treat-reducers-as-state-machines" rel="noopener noreferrer"&gt;Redux style guide&lt;/a&gt; shows you how to model reducers into state machines. If this feels complicated, you can get a long way by adding if-statements in your switch statements. "You can do action X if we are in state Y".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7xa0exqvu0q9y708fbjz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7xa0exqvu0q9y708fbjz.png" alt="Alt Text" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Atomic pattern
&lt;/h2&gt;

&lt;p&gt;Many state management libraries force you to create one big state that lives on the highest level of the application. This came in a time where we put our 'remote' state in this store. But solutions like &lt;a href="https://react-query.tanstack.com/" rel="noopener noreferrer"&gt;React Query&lt;/a&gt;, &lt;a href="https://swr.vercel.app/" rel="noopener noreferrer"&gt;SWR&lt;/a&gt; and &lt;a href="https://www.apollographql.com/docs/react/" rel="noopener noreferrer"&gt;Apollo Client&lt;/a&gt; handle this for us now. Less and less data needs to get managed on a global level. The need to inject your store setup in your highest-level component wrapper also became redundant.  &lt;/p&gt;

&lt;p&gt;With an atomic pattern, we have many different global states of single values. Its approach really embraces the nature of JavaScript and the idea that state are just values. Each atom is a single value. In most cases, atoms also live on the global level in the JavaScript environment. However, you don't have to define all atoms in one place. If you modularize your application, you can have the code of different atoms live in different modules. You group atoms closely to where you use them. You &lt;a href="https://kentcdodds.com/blog/colocation" rel="noopener noreferrer"&gt;colocate&lt;/a&gt; them. &lt;/p&gt;

&lt;p&gt;This gives the pattern a &lt;em&gt;decoupled&lt;/em&gt; nature. You don't have to configure all atoms in a generic store. Also, they do not have to be directly injected into your UI component wrapper. Most frameworks allow you (e.g. via hooks) to interact with atoms in components directly. Lastly, atoms can be combined (in most implementations). This means you can use atoms in other atoms. When an underlying atom changes, the parent atom changes as well. You don't have to worry about re-render or listening, it is all managed for you.&lt;/p&gt;

&lt;p&gt;It does have some downsides. When the number of atoms grows, managing them can become a hassle. You have to name them all, and you have to be aware that they exist. Also, managing a complex structure of dependencies between atoms can become quite a task for developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reactivity and proxies
&lt;/h2&gt;

&lt;p&gt;Many modern front-end frameworks are &lt;em&gt;reactive&lt;/em&gt;. When a state changes, the framework knows that it should re-render. Or in other words, the state lets the framework knows it changed. This mental model is very like a &lt;em&gt;proxy&lt;/em&gt;. A proxy is a wrapper object that is being called, instead of accessing the targeted object . This allows us to add custom behavior to various calls. &lt;/p&gt;

&lt;p&gt;Proxies are ideal to create reactive and robust state management. The basic power lays in the fact that we can add listeners to state changes. Besides, the values of a proxy can directly be changed. You do not have to invoke the change via a function. If you want to create a more complex proxy, you could implement validators that validate changes before applying a state change. You could even add several layers of 'middleware' before each state change. You can go nuts.&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;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&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;listener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Count updated:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Count updated: 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code snippet above shows an example proxy. As you can see, we add a &lt;code&gt;listener&lt;/code&gt; function for when the value of &lt;code&gt;count&lt;/code&gt; changes. Now when we change the value of &lt;code&gt;count&lt;/code&gt;, the &lt;code&gt;listener&lt;/code&gt; function is triggered. Do note that this particular implementation is not &lt;em&gt;immutable&lt;/em&gt;. You can change the value . Many people prefer to have an immutable state, as it is less prone to development errors. &lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Now you should have a better understanding of some fundamentals of state management. Knowing the different types of state and how to manage state is the start. With proper state management, you can get a long way in complex web applications. But it is the start. There are many (more) ways to manage data that are important in client-side applications. When you master state, go dive into persistent storage or caching.    &lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Horizontal centering in CSS</title>
      <dc:creator>Kevin Pennekamp</dc:creator>
      <pubDate>Sun, 20 Jun 2021 11:17:42 +0000</pubDate>
      <link>https://dev.to/vyckes/horizontal-centering-in-css-jgk</link>
      <guid>https://dev.to/vyckes/horizontal-centering-in-css-jgk</guid>
      <description>&lt;p&gt;In a previous &lt;a href="https://dev.to/crinklesio/modern-css-grid-solutions-to-common-layout-problems-hk9"&gt;article&lt;/a&gt; I wrote about modern CSS layout solutions. As horizontal centering is a common layout pattern, the grid-based solution was a prime candidate to convert into a generic class when creating &lt;a href="https://github.com/crinklesio/feo-css" rel="noopener noreferrer"&gt;Feo CSS&lt;/a&gt;. But I encountered an issue. When combining this solution with other CSS layout patterns (e.g. the &lt;a href="https://github.com/crinklesio/feo-css#flow-x-and-flow-y" rel="noopener noreferrer"&gt;flow&lt;/a&gt; pattern) my layout would break. Both patterns are targeting the &lt;code&gt;display&lt;/code&gt; property, but with different values. To allow both patterns to work together, I had to find a different solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  The center layout pattern
&lt;/h2&gt;

&lt;p&gt;The &lt;em&gt;center&lt;/em&gt; layout pattern allows you to horizontally center elements on the screen. But more importantly, it allows child elements to have a different width as the parent. These can be images that span the entire width of the screen in articles, regardless of the screen size. Or when we want selected elements to break away from the paddings on the side. On small screens, we want small padding around the text, and images span the entire width.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa84irlhgsy6memmul828.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa84irlhgsy6memmul828.png" alt="The required layout" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS grid-based solution
&lt;/h2&gt;

&lt;p&gt;This solution creates a three-column grid. The outer columns act as the padding and overflow of the layout. By giving them a minimum width via &lt;code&gt;minmax(1rem, 1fr)&lt;/code&gt;, you ensure small padding exists on small screens. The center column takes the space required for the content but is capped at the maximum width. You can achieve this with &lt;code&gt;minmax(auto, 60ch)&lt;/code&gt;. This gives the combined implementation as displayed below.&lt;/p&gt;

&lt;p&gt;:::&lt;br&gt;
The used examples make use of CSS custom properties. This allows for adjustable layouts based on utility classes. Examples can be found in &lt;a href="https://github.com/crinklesio/feo-css#center" rel="noopener noreferrer"&gt;Feo CSS&lt;/a&gt;.&lt;br&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="nc"&gt;.center&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="py"&gt;--mw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50rem&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="n"&gt;minmax&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;--gap&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="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;auto&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;--mw&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;minmax&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;--gap&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="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Center all children */&lt;/span&gt;
&lt;span class="nc"&gt;.center&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&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;By overwriting the default &lt;code&gt;grid-column: 2&lt;/code&gt; to &lt;code&gt;grid-column: 1 / -1&lt;/code&gt;, you can achieve the effect described in the previous section. This effectively makes the element the same width as the entire grid, not only the center column.&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;.center&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;.exception&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;-1&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this has a downside: does not allow to set a different &lt;code&gt;display&lt;/code&gt; value on the parent element. This makes &lt;code&gt;.center&lt;/code&gt;  less useful for non-article-based elements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Back to the old school solution
&lt;/h2&gt;

&lt;p&gt;In finding a solution for my problem, I looked at the solution that was used years before CSS grid became a thing. On Stack Overflow, you will still find enough answers pointing to this solution. Of course, I am talking about the &lt;code&gt;margin: 0 auto&lt;/code&gt; solution. Let's modernize it a bit though.&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;.center&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="py"&gt;--mw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50rem&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;max-width&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;--mw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;margin-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding-left&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;--gap&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;padding-right&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;--gap&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;This is always a solid solution for horizontally centering solutions. But it has one issue though, and the reason why I did not use it in the first place. It does not easily allow child elements to 'overflow' and has an increased width. This issue can be avoided by using the method below. However, I found that this gave me issues with the responsiveness of the exception elements. So my search for a better solution continued.&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;.exception&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;100vw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-50%&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;
  
  
  Out with the old, in with new
&lt;/h2&gt;

&lt;p&gt;By slightly adjusting the old school solution, we can create a class that allows for the same behavior as the shown grid-based solution. Instead of setting the properties on the parent, you should set the &lt;em&gt;same&lt;/em&gt; properties on the children by using the child combinator (&lt;code&gt;parent &amp;gt; child&lt;/code&gt;). Similar to the grid-based solution, we can create a &lt;code&gt;.exception&lt;/code&gt; class. When children are given this class, they are allowed to have a different width. They can flow outside of the parent's boundaries.&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;.center&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.center&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;.exception-1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&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="c"&gt;/* a solution with a different max-width */&lt;/span&gt;
&lt;span class="nc"&gt;.center&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;.exception-2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;min&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="m"&gt;50rem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;padding-left&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="nl"&gt;padding-right&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting the &lt;code&gt;max-width&lt;/code&gt; to none allows a child element to have no restrictions on its width. It can become &lt;code&gt;100%&lt;/code&gt; while all the other elements are capped at a maximum of &lt;code&gt;50rem&lt;/code&gt;. Similar to the grid-based solution, you can now create more dynamic layouts. The use of CSS custom properties even allows you to define utility classes that gave you more control over the layout.&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;.center-g-sm&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;*&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;0.5rem&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;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;The grid-based solution works well for articles. But when converting the class to a generic layout pattern, I encountered some issues. The main issue was that the &lt;code&gt;display&lt;/code&gt; property on the parent was taken. By altering the solution used many years before CSS grids became a thing, I was able to come with a new solution. This creates the same layout with the same responsiveness advantages but gives me more flexibility. I am sure I will encounter another case where my new solution just does not work well. But for now, I settled for it.&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>html</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Creating an auto-layout algorithm for graphs</title>
      <dc:creator>Kevin Pennekamp</dc:creator>
      <pubDate>Thu, 10 Jun 2021 19:58:00 +0000</pubDate>
      <link>https://dev.to/vyckes/creating-an-auto-layout-algorithm-for-graphs-436k</link>
      <guid>https://dev.to/vyckes/creating-an-auto-layout-algorithm-for-graphs-436k</guid>
      <description>&lt;p&gt;In the last few months I worked on a &lt;a href="https://fsm.crinkles.io/" rel="noopener noreferrer"&gt;finite state machine editor&lt;/a&gt; build on &lt;a href="https://reactflow.dev/" rel="noopener noreferrer"&gt;React Flow&lt;/a&gt;. At a certain point I wanted to import a configuration, that &lt;em&gt;magically&lt;/em&gt; visualizes the state machine. I was in the need of a &lt;em&gt;graph layout algorithm&lt;/em&gt;. A few years back, I have implemented a similar feature for a workflow editor. The biggest problem to solve? Ensuring the resulting visualization is understandable and readable. This requires a solid algorithm.&lt;/p&gt;

&lt;p&gt;If all nodes in the graph are scattered across the screen, it will become hard to follow the lines between them. The approach I took is based on the paper &lt;a href="https://ieeexplore.ieee.org/document/221135" rel="noopener noreferrer"&gt;"A technique for drawing directed graphs (1993)"&lt;/a&gt;. It is a technique based on finding a (local) minimum in the number of crossing edges, as visualized below. My implementation consists out of three steps: (1) rank all nodes, (2) optimize the order of the nodes, and (3) determine the position of each node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxoc1yj0fk011vtvyq0i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxoc1yj0fk011vtvyq0i.png" alt="Alt Text" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Rank all nodes
&lt;/h2&gt;

&lt;p&gt;The first step of the algorithm is to &lt;em&gt;rank all nodes&lt;/em&gt;. All graphs have an initial node. It is the starting point of a process/workflow or the initial state of a state machine. This particular node is placed in &lt;em&gt;rank 0&lt;/em&gt;. With this starting point, we follow three steps to determine an initial rank for all the nodes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Determine the initial rank of each node. The rank of a node equals the length of the shortest route between this node and the initial node. The rank can be determined using a &lt;a href="https://en.wikipedia.org/wiki/Breadth-first_search" rel="noopener noreferrer"&gt;breadth-first search algorithm&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Determine all possible paths from the starting node, using a &lt;a href="https://en.wikipedia.org/wiki/Depth-first_search" rel="noopener noreferrer"&gt;depth-first search algorithm&lt;/a&gt;, like displayed below.&lt;/li&gt;
&lt;li&gt;Order all nodes within a rank, based on their occurrence in the longest path. Nodes in longer paths are placed higher within a rank.
&lt;/li&gt;
&lt;/ol&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="nf"&gt;getPaths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&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;children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;nodeId&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;_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// To avoid cycles in paths&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAllPaths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&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;The example below visualizes a result when following these steps. You can see that all nodes are ranked as described. In this example, &lt;em&gt;node 4&lt;/em&gt; is placed at the top of &lt;em&gt;rank 2&lt;/em&gt;, as it appears in the longest path, while &lt;em&gt;node 5&lt;/em&gt; does not.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxoc1yj0fk011vtvyq0i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxoc1yj0fk011vtvyq0i.png" alt="Alt Text" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimize the order of the nodes
&lt;/h2&gt;

&lt;p&gt;The above visualization shows that ranking nodes following these steps can produce readable results. But, improvements can be achieved. As this is a so-called &lt;a href="https://en.wikipedia.org/wiki/NP-hardness" rel="noopener noreferrer"&gt;'NP-hard'&lt;/a&gt; problem, there is no perfect solution possible. But, by following a certain sequence of steps, several times until we hit a boundary condition, we can approach a (local) optimum. Or you know, the minimum number of crossing edges. This is called a heuristic.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A heuristic is a practical problem-solving approach that is not guaranteed to be optimal, perfect, or rational. It is enough for an (intermediate) goal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A vital part of this heuristic is the ability to give a configuration a &lt;em&gt;score&lt;/em&gt;. This score is used to compare various mutations of the graph and find a (local) best based on this score. As mentioned before, the idea of this algorithm revolves around minimizing the amount of crossing edges. Thus, our score needs to be related to that. An easy scoring mechanism can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Count the number of edges that have the source and target in the same rank and are &lt;em&gt;not&lt;/em&gt; next to each other. You can also count the number of nodes between them. This would give a higher score when the source and target are further apart.&lt;/li&gt;
&lt;li&gt;Look at all combinations of ranks and count all edges between these two ranks (regardless of their directions), where the condition shown below is met.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Assumes both edges have the source in a lower rank&lt;/span&gt;
&lt;span class="c1"&gt;// edge = [sourceIndexInRank, targetIndexInRank]&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;edgesCross&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;edge1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;edge2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;edge1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;edge2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;edge1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;edge2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;edge1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;edge2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;edge1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;edge2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&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;With the scoring mechanism determined, it's time to look at the actual heuristic. The heuristic I choose is iteratively moving through all ranks and swaps two adjacent nodes. If they improve (or at least not worsen) the score, the mutation stays, for now. As this mechanism is not perfect, as not all possible mutations are explored, we can apply this heuristic for a maximum of &lt;em&gt;X&lt;/em&gt; times, to balance between performance and optimal results. The detailed steps of the heuristic are outlined below.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Let &lt;code&gt;i = 1&lt;/code&gt; and move to &lt;code&gt;rank[i]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Let &lt;code&gt;j = 0&lt;/code&gt;. Swap &lt;code&gt;rank[i][j]&lt;/code&gt; with &lt;code&gt;rank[i][j + 1]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Determine the score of the new graph, if the score becomes worse, reverse the mutation, else keep the mutation.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;j = j + 1&lt;/code&gt; if possible, else set &lt;code&gt;i = i + 1&lt;/code&gt; if possible, and repeat step 2. If neither is possible, proceed to step 5.&lt;/li&gt;
&lt;li&gt;If the resulting graph has a better score, repeat step 1 for the new graph, for a maximum of &lt;em&gt;X&lt;/em&gt; times. Else you found a (local) optimum.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ctwfhi084g9ta8a7gwk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ctwfhi084g9ta8a7gwk.png" alt="Alt Text" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The example graph used before has two crossing edges. By applying the above heuristic, we can optimize this by applying two mutations, as visualized above. When we swap nodes &lt;em&gt;2&lt;/em&gt; and &lt;em&gt;3&lt;/em&gt;, we are getting the same score of &lt;code&gt;2&lt;/code&gt;. This means to apply the mutation and continue. Nodes &lt;em&gt;2&lt;/em&gt; and &lt;em&gt;9&lt;/em&gt; cannot be swapped, as it worsens the score of the graph. When swapping &lt;em&gt;4&lt;/em&gt; and &lt;em&gt;5&lt;/em&gt; after swapping &lt;em&gt;2&lt;/em&gt; and &lt;em&gt;3&lt;/em&gt;, we find a perfect score and thus our resulting graph.&lt;/p&gt;

&lt;h2&gt;
  
  
  Determine the position of each node
&lt;/h2&gt;

&lt;p&gt;After we have optimized all our ranks of nodes, it is time to determine the position of each node. Various routes can be taken, but the easiest is to place nodes in a grid. In the end, our ranks are a grid. This is illustrated below, using the running example from the previous sections. By using a grid, you create several options for yourself to lay out your graph. You can take a traditional route, like the visualization shown in the previous section.&lt;/p&gt;

&lt;p&gt;You could also go for a more balanced graph, where all nodes are laid out around a centerline. In your initial rank, you always have one node. Depending on the orientation of your graph, this initial node is placed on a horizontal or vertical centerline. As you can see in the example, nodes &lt;em&gt;1&lt;/em&gt;, &lt;em&gt;2&lt;/em&gt;, and &lt;em&gt;8&lt;/em&gt; all line on this centerline, instead of having five nodes on a single line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|   |   | 3 |   |   |   |   |   |   |
|   |   |   |   | 5 |   | 6 |   |   |
| 1 |   | 2 |   |   |   |   |   | 8 |
|   |   |   |   | 4 |   | 7 |   |   |
|   |   | 9 |   |   |   |   |   |   |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Solving the automatic (or magical) layout of a directed graph (or state machine) is one of the most fun challenges I ever had. By doing research I found an algorithm I understood and could put in place. The described algorithm proves to be effective for small to medium-sized graphs. Most of these graphs are not spiderwebs and have limited edges (e.g. 2-3 outgoing edges per node). Don't believe me? I use the algorithm in an online &lt;a href="https://fsm.crinkles.io" rel="noopener noreferrer"&gt;state machine editor&lt;/a&gt; I have created. But, it is a heuristic and by definition not perfect. Some improvements I can think of already are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make it possible to change the weight of certain types of crossing edges (e.g. edges crossing with a rank have a higher weight). This allows you to control the algorithm to your own needs.&lt;/li&gt;
&lt;li&gt;Allow for nodes to move between ranks during the optimization step. This is a helpful improvement when you have a graph with a fixed start and end node, but a big variation in the length of paths.&lt;/li&gt;
&lt;li&gt;Optimize how mutations and which mutations are applied. Check only adjacent ranks to improve the performance for example. This can worsen the result though.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;I've created a JavaScript package called &lt;a href="https://github.com/crinklesio/digl" rel="noopener noreferrer"&gt;DIGL&lt;/a&gt; that implements the described algorithm. It is framework agnostic and can be used in the front-end or back-end.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Binding CSS and JavaScript with HTML data-attributes</title>
      <dc:creator>Kevin Pennekamp</dc:creator>
      <pubDate>Sun, 25 Apr 2021 09:02:53 +0000</pubDate>
      <link>https://dev.to/vyckes/binding-css-and-javascript-with-html-data-attributes-1pl0</link>
      <guid>https://dev.to/vyckes/binding-css-and-javascript-with-html-data-attributes-1pl0</guid>
      <description>&lt;p&gt;My &lt;a href="https://dev.to/crinkle/css-methodology-and-architecture-3b34"&gt;CSS architecture&lt;/a&gt; is based on &lt;a href="https://cube.fyi" rel="noopener noreferrer"&gt;CUBE CSS&lt;/a&gt;. One of the layers of CUBE CSS describes &lt;em&gt;exceptions&lt;/em&gt;. Although I see exceptions as an integral part of the &lt;em&gt;block&lt;/em&gt; layer, they are important nonetheless. Exceptions are often captured by targeting semantic HTML attributes or &lt;code&gt;data-*&lt;/code&gt; attributes in your CSS selectors. But what do these attributes enable you to do in CSS?&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing HTML &lt;code&gt;data-*&lt;/code&gt; attributes
&lt;/h2&gt;

&lt;p&gt;HTML 5 was designed with extensibility in mind. On the data level, this is achieved with &lt;code&gt;data-*&lt;/code&gt; attributes. They allow you to define your attributes on HTML elements. By using the &lt;code&gt;data-&lt;/code&gt; prefix you cannot define non-existing attributes, or override attributes with non-valid values. If you did, you would invalidate your HTML. But with the &lt;code&gt;data-*&lt;/code&gt; attributes you are free to add whatever your heart desires. Let's take a closer look at how this looks in HTML.&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;button&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Click me!&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we added the &lt;code&gt;data-type&lt;/code&gt; attribute to a button, with the value &lt;code&gt;primary&lt;/code&gt;. All UIs have multiple types of buttons. Most CSS implementations choose to create a base &lt;code&gt;.btn&lt;/code&gt; class. On top of this class, we define the &lt;a href="http://getbem.com/naming/" rel="noopener noreferrer"&gt;modifier from the BEM notation&lt;/a&gt;. In this case, &lt;code&gt;.btn--primary&lt;/code&gt;. Should be enough, right?&lt;/p&gt;

&lt;p&gt;Now assume the case where you use an existing UI library for your buttons. Most of these come with a predefined set of button types. But now you want to create another type? Though luck. The library does not allow for defining button types and their styles yourself. You are not able to extend the stylesheet with a style definition for your &lt;code&gt;newtype&lt;/code&gt; button, extending the &lt;code&gt;.ui-btn&lt;/code&gt; class of the library.&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;.ui-btn&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;'newtype'&lt;/span&gt;&lt;span class="o"&gt;]&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;red&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;blockquote&gt;
&lt;p&gt;This definition has a higher specificity compared to the &lt;code&gt;.ui-btn&lt;/code&gt;. It will override any styles defined in the default &lt;code&gt;.ui-btn&lt;/code&gt; class.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Linking JavaScript and CSS
&lt;/h2&gt;

&lt;p&gt;Although defined in HTML, &lt;code&gt;data-*&lt;/code&gt; attributes play a very important part in linking JavaScript with CSS. Many front-end developers tend to use JavaScript to define what CSS classes should be applied to an element. Modern JavaScript frameworks like React make this very easy. Although nothing is wrong with this approach, your code can become unmaintainable quickly. You often go to string manipulations to determine the modifier class it needs to apply.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;primary&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`ui-btn ui-btn--&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;classes&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Click Me!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you forget to define the default value of a property, you apply &lt;code&gt;ui-btn ui-btn--undefined&lt;/code&gt; to your element. What happens when there is more than one type of modifier that can be applied to your element? Your code became a lot less maintainable. By utilizing &lt;code&gt;data-*&lt;/code&gt; attributes you can avoid this. It allows you to minimize the amount of JavaScript required to determine which styles need to be applied.&lt;/p&gt;

&lt;p&gt;On the other hand, it powers up your CSS. The &lt;code&gt;data-*&lt;/code&gt; attributes allow you the apply pattern matching as well. 'Contains' (&lt;code&gt;*=&lt;/code&gt;), 'starts with' (&lt;code&gt;^=&lt;/code&gt;), or 'part of list' (&lt;code&gt;~=&lt;/code&gt;) are just some pattern matching examples. You can even apply matching using a case insensitive query using &lt;code&gt;[data-type='primary' i]&lt;/code&gt; in your CSS. But when would you match patterns? Is this not a too complex feature for CSS?&lt;/p&gt;

&lt;h2&gt;
  
  
  Using &lt;code&gt;data-*&lt;/code&gt; for real-life scenarios
&lt;/h2&gt;

&lt;p&gt;Let's take a look at an example to show why it can be of value. Everybody &lt;em&gt;loves&lt;/em&gt; creating tables in Excel. You add some bold font to the header cells, as they indicate what information is present in the columns. And the same goes for the first column, as those cells indicate what is in the rows. Maybe you go exotic and apply even more styling next to some bold fonts. Something similar can be created using &lt;code&gt;data-*&lt;/code&gt;. Look at the partial code-snippet below.&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"data-grid"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"cell"&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"first-row first-column"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"cell"&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;"first-column"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code below, we can target both cells with the displayed CSS selector. As both cells have a different &lt;code&gt;data-type&lt;/code&gt; we cannot apply one-on-one pattern matching. But with the &lt;code&gt;~=&lt;/code&gt; operator, we can search if the value is present in a 'space separated list'. So with the CSS selector below, we can target both cells with one definition.&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="o"&gt;//&lt;/span&gt; &lt;span class="nt"&gt;targets&lt;/span&gt; &lt;span class="nt"&gt;all&lt;/span&gt; &lt;span class="nt"&gt;cells&lt;/span&gt; &lt;span class="nt"&gt;in&lt;/span&gt; &lt;span class="nt"&gt;the&lt;/span&gt; &lt;span class="nt"&gt;first&lt;/span&gt; &lt;span class="nt"&gt;column&lt;/span&gt;
&lt;span class="nc"&gt;.cell&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-type&lt;/span&gt;&lt;span class="o"&gt;~=&lt;/span&gt;&lt;span class="s2"&gt;'first-column'&lt;/span&gt;&lt;span class="o"&gt;]&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;red&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;
  
  
  State machines
&lt;/h2&gt;

&lt;p&gt;But one of the biggest advantages of &lt;code&gt;data-*&lt;/code&gt; has not yet been discussed: state machines! State machines are upcoming in front-end development but are an old concept. As outlined in &lt;a href="https://www.smashingmagazine.com/2018/01/rise-state-machines/" rel="noopener noreferrer"&gt;this&lt;/a&gt; article on CSS-tricks, state machines allow you to simplify your code by mitigating side-effects (e.g. in fetch requests). It is a powerful method to define complex logic. If an element requires different styling based on the state, &lt;code&gt;data-*&lt;/code&gt; are here to help you out! It is as simple as the snippet below.&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;.my-element&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;'init'&lt;/span&gt;&lt;span class="o"&gt;]&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;red&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;blockquote&gt;
&lt;p&gt;A state machine is a machine that can be in one state at any given time. The machine can change from one state to another, based on transitions. A statechart allows for nesting, delays, automatic transitions, and parallel regions in state machines. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;State machines have a lot of value in complex state management. In those cases, styling is often not impacted. Parts of the DOM tree are disregarded based on the current state. Although this could also be achieved with CSS (&lt;code&gt;display: none&lt;/code&gt;), it is not the main strength of combining CSS and state machines. I have listed more practical use cases below. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Disabling interactive elements (e.g. buttons) based on the loading state of fetch requests, and provide visual guidance. &lt;/li&gt;
&lt;li&gt;Different visualization of checkboxes (checked, unchecked, semi-checked). &lt;/li&gt;
&lt;li&gt;Different combinations of (un-)selected, hovering, and active. &lt;/li&gt;
&lt;li&gt;CSS animations based on statecharts with timers (e.g. fly-out animation). &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By combining semantic HTML, HTML-attributes and &lt;code&gt;data-*&lt;/code&gt; attributes, styling based on states can be made possible. It allows you to reduce the amount of JavaScript and use CSS what it is intended for in the first place: layout and styling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Good use of semantic HTML attributes make it possible to link CSS to JavaScript. As we have seen, the &lt;code&gt;data-*&lt;/code&gt; attributes allow the creation of generic UI components that are styling less. Instead of imposing an opinionated style, they allow developers to override every aspect. When combined with semantic HTML-attributes, styling for state machines can be implemented, as in line with &lt;a href="https://cube.fyi" rel="noopener noreferrer"&gt;CUBE CSS&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>css</category>
      <category>html</category>
      <category>javascript</category>
    </item>
    <item>
      <title>CSS methodology and architecture</title>
      <dc:creator>Kevin Pennekamp</dc:creator>
      <pubDate>Fri, 16 Apr 2021 08:02:54 +0000</pubDate>
      <link>https://dev.to/vyckes/css-methodology-and-architecture-3b34</link>
      <guid>https://dev.to/vyckes/css-methodology-and-architecture-3b34</guid>
      <description>&lt;p&gt;For years I have used &lt;a href="https://www.xfive.co/blog/itcss-scalable-maintainable-css-architecture/" rel="noopener noreferrer"&gt;ITCSS&lt;/a&gt; as my goto CSS architecture for large projects. It helped me to keep my CSS maintainable with a small team. But in the last two years, I've found myself applying &lt;em&gt;utilities&lt;/em&gt; more, and writing CSS components/blocks less. More and more parts of ITCSS were left untouched and unused. My CSS architecture had become too complex for my daily use. And it was not just me. You see the movement in the community, but also within my own team.&lt;/p&gt;

&lt;p&gt;I am a not &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;utility-first&lt;/a&gt; guy. But 80% of my CSS code is utilities these days. The remaining parts consist of CSS targeting layouts (e.g. grids) and blocks that could be solved with utilities (e.g. using operators like &lt;code&gt;+&lt;/code&gt; or &lt;code&gt;~&lt;/code&gt;). At this point, I came across the &lt;a href="https://cube.fyi/" rel="noopener noreferrer"&gt;CUBE CSS&lt;/a&gt; of &lt;a href="https://twitter.com/piccalilli_" rel="noopener noreferrer"&gt;Andy Bell&lt;/a&gt;. It is the methodology describing how I was, and still am, implementing CSS. So as every self-respecting front-end developer with an online presence, I took it, changed it, created a framework, and wrote about it!&lt;/p&gt;

&lt;h2&gt;
  
  
  From methodology to framework
&lt;/h2&gt;

&lt;p&gt;CUBE CSS is a methodology with &lt;em&gt;simplicity&lt;/em&gt; at its core. It values CSS for what it is. The methodology works well with &lt;em&gt;custom properties&lt;/em&gt; to implement a &lt;a href="https://github.com/kevtiq/feo-css" rel="noopener noreferrer"&gt;framework&lt;/a&gt;. The combination creates a &lt;em&gt;flexible&lt;/em&gt;, &lt;em&gt;scalable&lt;/em&gt; and &lt;em&gt;extensible&lt;/em&gt; CSS architecture. The custom properties act as &lt;a href="https://css-tricks.com/what-are-design-tokens/" rel="noopener noreferrer"&gt;design tokens&lt;/a&gt; and can be used across all layers of the architecture. My framework consists of three layers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Layout&lt;/strong&gt;: classes that look at the macro-level of an application, like the once I described &lt;a href="https://dev.to/crinkle/modern-css-grid-solutions-to-common-layout-problems-hk9"&gt;here&lt;/a&gt;. They provide flexible and responsive layout solutions that are common across an application. For inspiration on common layout patterns, check &lt;a href="https://every-layout.dev" rel="noopener noreferrer"&gt;every-layout.dev&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Utilities&lt;/strong&gt;: classes that do one job and do one job well. This is often a class that alters a single property. But utilities like the &lt;a href="https://github.com/kevtiq/feo-css/blob/main/src/utilities/click-area.scss" rel="noopener noreferrer"&gt;&lt;code&gt;.click-area&lt;/code&gt; class&lt;/a&gt; cover more than a single property but still do only one thing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blocks&lt;/strong&gt;: correspond to UI components. That what cannot be solved with layout and/or utility classes alone can be solved in blocks. You can choose to cover all styles of a component in a block, or you can only put those styles not covered by other classes in a block.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;CUBE CSS does include a fourth layer, exceptions. Although I love the &lt;code&gt;data-&lt;/code&gt;attributes on HTML tags, I see them as a part of the blocks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you look closely at the code of &lt;a href="https://github.com/kevtiq/feo-css" rel="noopener noreferrer"&gt;my framework (Feo)&lt;/a&gt;, it has the architecture outlined below. As you can see, it only focuses on layout and utility classes. Blocks and exceptions are very project-specific, and often tied to UI components. Therefore they are left out of scope in this framework. However, there are many ways how you can add blocks in conjunction with this framework to a project. You can add a directory to the framework, but I would suggest &lt;em&gt;co-locate&lt;/em&gt; it near the corresponding UI components. You could do this via CSS modules, styled-components, scoped styles in Svelte, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;styles/
├── layout/        // classes for layout patterns
├── utilities/     // utility classes
├── _global.scss   // global styles targeting HTML tags
├── _reset.scss    // CSS reset
├── _tokens.scss   // design tokens
└── index.scss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Implementing and using this correctly requires some basic knowledge about specificity and the cascade. Many of the layout patterns will apply CSS properties with a higher specificity compared to utilities. In some cases, the specificity might be the same, but you should not override layout properties with utilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  detailed look at the framework
&lt;/h2&gt;

&lt;p&gt;At its core is the &lt;code&gt;_token.scss&lt;/code&gt; file. In this file, you define all your design tokens as SCSS variables. But why not define them as custom properties? As the framework is &lt;em&gt;extensible&lt;/em&gt;, you should be able to define your own names for the variables, with your preferred names. Do you want to use &lt;code&gt;-xs&lt;/code&gt; or &lt;code&gt;-4&lt;/code&gt; as a name for spacing? This makes it impossible to correctly define all utility classes. But by using SCSS variables as the definitions, we can generate custom properties that can be used for all your additional (block) classes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'black'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#000&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'white'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#fff&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@each&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$color&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$colors&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nd"&gt;:&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$color&lt;/span&gt;&lt;span class="si"&gt;}&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;With the design tokens, we can generate all utility classes. Instead of setting the value of all the utility classes, we refer to the corresponding custom property, as shown below. Assume you change the value of &lt;code&gt;--black&lt;/code&gt; for a specific page to &lt;code&gt;#fff&lt;/code&gt;. All utility classes (and blocks) that have a reference to the custom property &lt;code&gt;--black&lt;/code&gt;, will now use the value &lt;code&gt;#fff&lt;/code&gt; instead of &lt;code&gt;#000&lt;/code&gt; on this specific page. This creates a consistent but flexible experience for both the user and developer. We let the cascade of CSS do its work for custom properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@each&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$color&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$colors&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;.bg-&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="si"&gt;}&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="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="si"&gt;}&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;A similar approach is taken for the layout patterns. Many of the layout patterns still have properties that you want to adjust. Take the example below. This generates a responsive overview of tiles. But you want to be able to set the size of the gap. By generating utility classes we allow developers to set classes like &lt;code&gt;tiles tiles-g-xs&lt;/code&gt; on elements. Similarly, other properties can be identified that can be replaced by additional layout utility classes (e.g. replacing the &lt;code&gt;20rem&lt;/code&gt;). Although this flurries the lines between layout and utilities, this is okay. It aids towards the goal of covering 80% of the applied styles with this framework.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.tiles&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;--tiles-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;spacing-0&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="na"&gt;grid-row-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;tiles-gap&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="na"&gt;grid-column-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;tiles-gap&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="na"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto-fit&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;20rem&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1fr&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="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Generate classes to set the tile gap&lt;/span&gt;
&lt;span class="k"&gt;@each&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$space&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$spacing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;.tiles-g-&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;--tiles-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;spacing-&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="si"&gt;}&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;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;The moment I read about CUBE CSS, I was a fan of the methodology. How could I not? It was basically describing how I felt about CSS and how I was using it. At the same time, I became a big fan of customer properties. So why not combine the two into a framework? Which is what I did. The current version of the framework is open on &lt;a href="https://github.com/kevtiq/feo-css" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. It is small but used in two projects. It has several layout and utility classes build in. For now, I intend to continue to improve and enrich the framework when I can. Let me know in the &lt;a href="https://github.com/kevtiq/feo-css/issues" rel="noopener noreferrer"&gt;GitHub issues&lt;/a&gt; what you think should be added!&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>html</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Getting my SvelteKit website on Netlify</title>
      <dc:creator>Kevin Pennekamp</dc:creator>
      <pubDate>Sat, 10 Apr 2021 18:15:16 +0000</pubDate>
      <link>https://dev.to/vyckes/getting-my-sveltekit-website-on-netlify-26m0</link>
      <guid>https://dev.to/vyckes/getting-my-sveltekit-website-on-netlify-26m0</guid>
      <description>&lt;p&gt;After tackling the &lt;a href="https://dev.to/crinkle/my-journey-from-gatsby-to-sveltekit-5g32"&gt;development&lt;/a&gt; of a SvelteKit version of my website, it is time to get it running in production! Or in this case, hosted on &lt;a href="https://www.netlify.com" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt;. It was in this part I found out the &lt;em&gt;hard&lt;/em&gt; way that SvelteKit is in beta and not production-ready. Let me take you on my journey to get the website deployed on Netlify, and see if I was successful (spoiler: you are reading this on the SvelteKit version).&lt;/p&gt;

&lt;h2&gt;
  
  
  Hosting on Netlify
&lt;/h2&gt;

&lt;p&gt;Now that I had my website locally working, I had to get it deployed on &lt;a href="https://www.netlify.com" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt;. SvelteKit has an &lt;code&gt;adapter-netlify&lt;/code&gt; package. This package creates a Netlify function that acts as the 'server' for the SSR website. So I swapped the default &lt;code&gt;adapter-node&lt;/code&gt; to the Netlify version and let GitHub and Netlify do the magic. And... errors.&lt;/p&gt;

&lt;p&gt;This is the moment I found out why SvelteKit is still in beta. In general, all the packages are &lt;code&gt;devDependencies&lt;/code&gt;. But, the Netlify Functions could not find the packages needed. So I moved the packages from &lt;code&gt;devDependencies&lt;/code&gt; into &lt;code&gt;dependencies&lt;/code&gt; and hit deploy again. Progress! The Netlify function can now find the package. Some issues remained, but progress nonetheless. Back to the local version to fix them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvgccfmndtc1ti1q07l0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvgccfmndtc1ti1q07l0.png" alt="Question marks" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But wait a minute? The local version is not working anymore? Apparently, &lt;a href="https://vitejs.dev" rel="noopener noreferrer"&gt;Vite&lt;/a&gt;, the local build tool, did not like it when I moved the packages. After trying several things, I gave up. As SvelteKit is still in beta, community resources are scarce. I did found a few &lt;a href="https://sapper.svelte.dev" rel="noopener noreferrer"&gt;Sapper&lt;/a&gt; examples, the predecessor of SvelteKit, using the &lt;code&gt;adapter-static&lt;/code&gt;. Success! Well... kind of.&lt;/p&gt;

&lt;p&gt;I found that a few of my markdown files got transformed into pages correctly, but not all. After searching and debugging, I found the issue. The &lt;code&gt;adapter-static&lt;/code&gt; traverses all links starting from the index route and generates pages for all the linked pages it can find. If a markdown file is not present as a link on a page (yet), it does not get generated.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;adapter-static&lt;/code&gt; changes the solution from SSR to SSG: the pre-rendered HTML is generated on build time instead of runtime.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Optimizing the website for SEO
&lt;/h2&gt;

&lt;p&gt;In general SSR and SSG are SEO-friendly ways to create modern websites. Both Gatsby and Svelte(Kit) should enable me to create an SEO-friendly website. I used the &lt;a href="https://web.dev/measure/" rel="noopener noreferrer"&gt;web.dev measure&lt;/a&gt; tool to determine my website score. The homepage of the Gatsby version scored a 100 on all categories. But so does the SvelteKit version.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2b85n166sk3x0cjqwdmd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2b85n166sk3x0cjqwdmd.png" alt="Example screenshot of web.dev measure scores" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But the scores are not the only metrics found in this tool. Most metrics were the same for both versions of the website, except &lt;em&gt;time to interactivity&lt;/em&gt;. For the Gatsby version, this was around 2.4 seconds, while the SvelteKit version has a time of around 1.0 seconds. Both good scores, but SvelteKit is superior.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Time to interactivity&lt;/strong&gt;: the actual time it takes to load everything allowing the user to interact with the page&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is driven by the files transferred on loading the page. The Gatsby version had to download around 950 kB across 24 files. The SvelteKit version only needs around 280 kB over 14 files. A big win for SvelteKit!&lt;/p&gt;

&lt;p&gt;But we can test more than the homepage. Other pages did not score that well for SvelteKit. One of the bigger issues found by web.dev is redirects. At the moment of building the website, SvelteKit has &lt;em&gt;no&lt;/em&gt; trailing slashes in URLs &lt;a href="https://github.com/sveltejs/kit/issues/192" rel="noopener noreferrer"&gt;by design&lt;/a&gt;. But, Netlify &lt;a href="https://docs.netlify.com/routing/redirects/redirect-options/#trailing-slash" rel="noopener noreferrer"&gt;normalizes&lt;/a&gt; all URLs to a version with trailing slashes. It adds the below redirect headers to each page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/post-title /post-title/ 301!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By playing around with the 'Asset optimization' settings on Netlify, I was able to turn off this normalization. After redeploying and re-evaluating, the web.dev scores increased significantly. Now individual post pages score much better compared to their Gatsby counterpart. Especially on the 'time to interactivity' metric.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Turning off all asset optimizations on Netlify increased performance on my website. But, it can have unwanted side-effect due to the lack of URL normalization. Use with caution.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;When moving from the stable Gatsby to the unstable SvelteKit public beta, I took a risk. Not only did I have to learn a new framework, I had to build logic to replace community plugins. I was at risk of encountering bugs that few encountered before me. With the knowledge that I could not rely on Google or Stack Overflow, I jumped into the deep. But in the end, it all paid off. I build a new website that is not only faster but more enjoyable for me to work on. The experience that Svelte and SvelteKit bring is promising, and now I cannot shut up about it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are curious about the result, check the code on the open &lt;a href="https://github.com/kevtiq/crinkle.dev" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>svelte</category>
      <category>showdev</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Converting my Gatsby website to SvelteKit</title>
      <dc:creator>Kevin Pennekamp</dc:creator>
      <pubDate>Sat, 10 Apr 2021 18:09:03 +0000</pubDate>
      <link>https://dev.to/vyckes/my-journey-from-gatsby-to-sveltekit-5g32</link>
      <guid>https://dev.to/vyckes/my-journey-from-gatsby-to-sveltekit-5g32</guid>
      <description>&lt;p&gt;For the last few weeks or months, I was getting restless about everything: my work, my website, the environment, the World. I had to find something to change my focus to, restore my energy. Around a week or two ago, I found the news of &lt;a href="https://svelte.dev/blog/sveltekit-beta" rel="noopener noreferrer"&gt;SvelteKit going into public beta&lt;/a&gt;. This sparked excitement in myself I had not felt in a long time. So during Easter weekend, while in a Corona lockdown, I started with a new journey. An exciting journey. I was going to learn a new framework and rebuild this website! Or at least, try.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Svelte and SvelteKit
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://reactjs.org" rel="noopener noreferrer"&gt;React&lt;/a&gt; is a JavaScript library that makes it easy to write UIs. As it is a library, your code plus the library is shipped to the browser and executed there. Also, you have to write your HTML (or JSX) inside the &lt;code&gt;return&lt;/code&gt; of a function, while other lifecycle information is also encapsulated inside that function. &lt;a href="https://www.gatsbyjs.com/" rel="noopener noreferrer"&gt;Gatsby&lt;/a&gt; is a &lt;em&gt;static site generation (SSG)&lt;/em&gt; solution build on top of React, and was used in the previous version of this website. An easy next step would be migrating to &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt;, a &lt;em&gt;static-site rendering (SSR)&lt;/em&gt; solution build on React. But then I came across the news of the SvelteKit public beta. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;SSG vs. SSR&lt;/strong&gt;: in both cases the server is responsible to pre-render the requested HTML page (in contrast to client-side rendering (CSR)). With SSG this happens at &lt;em&gt;build&lt;/em&gt; time: all possible pages get pre-rendered. With SSR this happens at &lt;em&gt;runtime&lt;/em&gt;: upon a page visit, the HTML gets pre-rendered using a template. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; is not a library or a framework, it is a compiler. This means that your code is not shipped in combination with packages to a browser, but it gets compiled to something else. This something is shipped to the browser. Because all code gets compiled, the total size decreases, but the performance increases. Besides, it allows you to break away from writing everything inside a JavaScript function, and have its optimized format.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kit.svelte.dev/" rel="noopener noreferrer"&gt;SvelteKit&lt;/a&gt; is for Svelte, what Gatsby and NextJS are for React. It is an opinionated framework build on top of Svelte that allows you to create SSR (and SSG) websites and applications. At its core, it uses a flexible filesystem-based routing in the &lt;code&gt;/routes&lt;/code&gt; directory. Not only do the templates for the pages in this directory, but the code that runs on the server is co-located here as well. It is the next iteration of the Sapper framework. So a great choice for a blog-driven website.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working with (S)CSS in SvelteKit
&lt;/h2&gt;

&lt;p&gt;I am a big fan of CSS and have a strong &lt;a href="https://github.com/kevtiq/css-framework" rel="noopener noreferrer"&gt;opinion&lt;/a&gt; on how it should be applied to websites/projects. My setup allows me to extract general layout patterns and combine them with general utility-first CSS. When I read about the 'scoped' styles of Svelte I got a bit anxious. Would my way of working deviate too much from Svelte(Kit)?&lt;/p&gt;

&lt;p&gt;But quickly it hit me. The combination could work perfectly. It could allow me to create global &lt;code&gt;layout&lt;/code&gt; and &lt;code&gt;utility&lt;/code&gt; CSS, and use the 'scoped' CSS of Svelte to add styles specific to components or pages. The styles defined in the Svelte component could replace the entire &lt;code&gt;block&lt;/code&gt; directory of my framework. This means that components would look something like shown below. On the &lt;code&gt;div&lt;/code&gt; instead of the &lt;code&gt;header&lt;/code&gt; tag, you see various utility classes applied, but also the defined &lt;code&gt;.inner&lt;/code&gt; class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"inner | flex-row items-center mb-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Logo&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style &lt;/span&gt;&lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"scss"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;...&lt;/span&gt;

    &lt;span class="err"&gt;.inner&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This worked beautifully, for the most part. The compiler of Svelte is smart enough to identify unused local styles, and not bundle them. However, in SvelteKit you can render an HTML string using the &lt;code&gt;@html&lt;/code&gt; flag. The compiler cannot link the two and will flag local styles as unused. This results in styles not being applied, but also not bundled. You cannot find the styles with the browser Inspection Tool, they do not exist. To solve this issue, the &lt;code&gt;:global()&lt;/code&gt; helper has to be used. But except for that, even my opinionated way of working just works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="nd"&gt;:global&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.post&lt;/span&gt; &lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I think I am good at CSS, but bad at animations. I know my way around CSS transitions, but that is as far as I go. Luckily Svelte got a lot of sweet stuff built in. The &lt;code&gt;svelte/transition&lt;/code&gt;, &lt;code&gt;svelte/animate&lt;/code&gt;, &lt;code&gt;svelte/easing&lt;/code&gt; (and potentially more) packages really make your life easier. They enabled me to implement page transitions (with the code below), or logo hover animation with ease. These little touches credit the name of my website, Crinkle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fly&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svelte/transition&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;fly&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting up the markdown file handling
&lt;/h2&gt;

&lt;p&gt;But I do not write my articles in HTML, Svelte, or React, I write them in markdown. With Gatsby several steps had to be taken to make it all work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The markdown files inside the &lt;code&gt;/pages&lt;/code&gt; directory needed to have a template name indicated as an attribute in the front-matter section.&lt;/li&gt;
&lt;li&gt;In the &lt;code&gt;gatsby-node.js&lt;/code&gt; file you put the code on how the actual files should be handled. With a GraphQL query, all pages can be retrieved and you can transform the data into the format you require in your template file (e.g. in my case I had to extract the &lt;em&gt;next&lt;/em&gt; and &lt;em&gt;previous&lt;/em&gt; articles). &lt;/li&gt;
&lt;li&gt;The template file, located in a &lt;code&gt;/templates&lt;/code&gt; directory allows query (again through GraphQL) an object defined (in my case an article and the adjacent articles) in the previous step can be obtained and transformed into an HTML page through React components.&lt;/li&gt;
&lt;li&gt;Configure a shit tone of plugins to handle images, code highlighting, relocation of files, etc. in the &lt;code&gt;gatsby-config.js&lt;/code&gt; file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I don't know about you, but I found it not developer-friendly. Things are scattered everywhere, it is unclear why you have to use GraphQL everywhere, and the plugins obfuscate the actual logic. SvelteKit is much more intuitive. The &lt;code&gt;/routes&lt;/code&gt; directory holds the code for rendering the pages, not the markdown files. It combines the &lt;code&gt;/templates&lt;/code&gt; and parts of the &lt;code&gt;gatsby-node.js&lt;/code&gt; corresponding to a page in one place. This co-location makes much more sense. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;[slug].json.js&lt;/code&gt; file contains the logic of transforming a markdown file in a JSON structure that can be sent to a browser. &lt;code&gt;slug&lt;/code&gt; corresponds to the filename without the extension. Instead of installing several plugins, I only had to install three npm packages, nothing more, nothing less.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;front-matter&lt;/code&gt;: to read additional attributes at the top of the markdown file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;markedjs&lt;/code&gt;: parse markdown into HTML.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;prismjs&lt;/code&gt;: add code highlighting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The resulting JSON string is returned at the end of the function. On the &lt;code&gt;[slug].svelte&lt;/code&gt; side, we need to fetch the generated JSON and return it in the &lt;code&gt;props&lt;/code&gt;. We can then expose the property as shown below. This allows us to use the &lt;code&gt;article&lt;/code&gt; object in the rendering code of this svelte plugin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;context=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="p"&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;article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/writing/&amp;amp;{page.params.slug}.json`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;article&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;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the above was sufficient to have my Gatsby website transformed into a SvelteKit website, almost. There were small issues left. For instance, images on the articles were wrapped in a &lt;code&gt;&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&lt;/code&gt; tag, which made a &lt;a href="https://dev.to/writing/css-layout-patterns#dynamic-centered-layout"&gt;styling element&lt;/a&gt; I used impossible (until the &lt;a href="https://drafts.csswg.org/selectors-4/#relational" rel="noopener noreferrer"&gt;&lt;code&gt;:has()&lt;/code&gt;&lt;/a&gt; gets released). But luckily you can alter how &lt;code&gt;markedjs&lt;/code&gt; works.&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;marked&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;markedjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="nx"&gt;marked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paragraph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;img&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;/p&amp;gt;&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;With a few more of these alterations (lazy loading of images and anchor tags on headings), I was able to create the same website in SvelteKit. Or even a better website, with &lt;a href="https://drafts.csswg.org/selectors-4/#relational" rel="noopener noreferrer"&gt;less code&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Up until this moment, the development experience (DX) of Svelte and SvelteKit has been tremendous. Don't get me wrong, I loved Gatsby the first time I used it. But after working with Svelte(Kit) I found its DX inferior to SvelteKit. For UI components that do not require (a lot of) state management, Svelte is also superior to React. But when moving to SvelteKit, you loose the community and plugins of Gatsby. This makes Gatsby superior for less tech-savvy people, or when you want to move quicker and do not want to control each detail. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are curious about the result, check the code on the open &lt;a href="https://github.com/kevtiq/crinkle.dev" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>svelte</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Modern CSS grid solutions to common layout problems</title>
      <dc:creator>Kevin Pennekamp</dc:creator>
      <pubDate>Mon, 06 Jul 2020 11:33:54 +0000</pubDate>
      <link>https://dev.to/vyckes/modern-css-grid-solutions-to-common-layout-problems-hk9</link>
      <guid>https://dev.to/vyckes/modern-css-grid-solutions-to-common-layout-problems-hk9</guid>
      <description>&lt;p&gt;Layout and composition are some of the most challenging topics within CSS. Especially when you have to take responsiveness into account. We often fall back no media-queries. But adding many media-queries for various breakpoints can make your CSS unmaintainable. But with the addition of grids, we can overcome media-query fatigue. Not only make our CSS more maintainable, but they also improve the user experience. We can let CSS handle the available space. In this article, I will describe three layout implementations that can improve your (personal) website.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic centered layout
&lt;/h2&gt;

&lt;p&gt;We all know &lt;code&gt;margin: 0 auto&lt;/code&gt; to center a layout. Ideal for article pages, right? But what if you want elements like images to exceed the maximum width of the article? We can achieve this by working with negative margins. But this only works on big screens. On small screens, negative margins can break your website. Especially when you apply smaller side padding on mobile compared to tablets. So, we have to add many media-queries to ensure this effect works as intended, on all screen sizes. But now we have our cool effect as visualized below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkv803urnwuk8p9r5d3ke.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkv803urnwuk8p9r5d3ke.png" alt="Visualisation of a dynamic centered layout" width="800" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What happens when you want to change these ultra-wide elements? You go over several media-queries to determine if your change is applied on various screens. What if we could cut the media-queries and still achieve this effect? Recently I came across &lt;a href="https://mastery.games/post/article-grid-layout/" rel="noopener noreferrer"&gt;this post from Dave Geddes&lt;/a&gt;. It shows us how we can achieve this effect using CSS Grids. You create a grid of three columns. The center column is the actual content area, while the two outer columns act as padding, but also create the effect of &lt;code&gt;margin: 0 auto&lt;/code&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="nt"&gt;article&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="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2rem&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="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;65ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2rem&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="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* sets all children in the middle of the screen */&lt;/span&gt;
&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* overrides the above for images to be wider, but centered */&lt;/span&gt;
&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;justify-self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&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;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100ch&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;The paddings on the side should differ on various screen sizes. On smaller screens, you want to limit the wasted space, while on bigger screens more padding can improve the visual quality. But with the above solution you still need media-queries to use different side padding. You could mitigate this by adding &lt;a href="https://vycke.dev/blog/fluid-interfaces-using-css/" rel="noopener noreferrer"&gt;fluidity&lt;/a&gt; to your website. We can replace the &lt;code&gt;2rem&lt;/code&gt; with something like &lt;code&gt;calc(1rem + 1 * var(--ratio))&lt;/code&gt;. By doing so, the side padding changes automatically when the screen size changes, without media-queries. Now we have a dynamic and maintainable layout for our articles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Responsive multi-column grid system
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd2vxc9qxmqbw879zzfiq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd2vxc9qxmqbw879zzfiq.png" alt="CSS Grid tiles visualization when resizing the screen" width="800" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Who does not know the responsive multi-column layout? A layout that changes the number of columns with the screen size as illustrated above. This was often solved using something like the &lt;a href="https://getbootstrap.com/docs/4.0/layout/grid/" rel="noopener noreferrer"&gt;Bootstrap grid-system&lt;/a&gt;, or an own implementation. But, this restricts you to a fixed number of columns for each screen size. If you would have five columns, that would not be possible in a twelve column system. Besides, you have to determine for each element the column span on different screen sizes.&lt;/p&gt;

&lt;p&gt;If you have many grids, your CSS or HTML does not scale well. Luckily we have CSS grids these days. With CSS grids we do not define the column span for each element. Instead, we let the browser determine the number of columns on the screen. You can achieve the illustrated scalable layout with the code snippet below. Let's dissect it!&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;.grid&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="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="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto-fit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;20rem&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="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;With &lt;code&gt;repeat()&lt;/code&gt; we say to the browser that it needs to repeat its argument. For example, &lt;code&gt;repeat(3, 1fr)&lt;/code&gt; would create a layout of three equally sized columns that fill the entire screen. But, our elements almost always have a minimum width. With the &lt;code&gt;1fr&lt;/code&gt; we can break them. With &lt;code&gt;minmax(20rem, 1fr)&lt;/code&gt;, each column has a minimum width of &lt;code&gt;20rem&lt;/code&gt;, but scales on larger screens.&lt;/p&gt;

&lt;p&gt;The magic starts when replacing the fixed number with &lt;code&gt;auto-fit&lt;/code&gt; or &lt;code&gt;auto-fill&lt;/code&gt;. With both options, we let the browser determine the amount of available columns on the screen. When using &lt;code&gt;auto-fill&lt;/code&gt; and &lt;code&gt;minmax(20rem, 1fr)&lt;/code&gt; on a screen of &lt;code&gt;90rem&lt;/code&gt; the browser creates four columns. The &lt;code&gt;auto-fit&lt;/code&gt; option creates a maximum of four columns in this example. When there are only two elements to put in the grid &lt;code&gt;auto-fit&lt;/code&gt; reduces the number of columns to two. This gives you great flexibility in responsive layouts, without using media-queries.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did you know that you can set a &lt;code&gt;grid-column: span 2&lt;/code&gt; attribute on your elements? When doing so, they will span two columns. So not all elements have to be the same size. The downside is that there will always be at least two columns, and any potential gaps in the grid are not filled.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Two-way card layouts
&lt;/h2&gt;

&lt;p&gt;You often see big card layouts with an image and content next to each other, spanning a big horizontal space. Often they have a fixed ratio between them (e.g. 50%-50%). When reducing the screen size, you don't want these two next, but below each other. The ratio also changed to make better use of the available space. The height of the image is not 50% anymore. The wireframes below visualize this concept.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frcd405gue4ad6p5o3ij2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frcd405gue4ad6p5o3ij2.png" alt="CSS Grid for dynamic cards" width="800" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Does this not sound like a familiar problem? Well, it is. It is almost the same as the &lt;em&gt;auto-scaling grid-layout&lt;/em&gt; I already described. There is one small addition. We need to add &lt;code&gt;grid-template-rows: auto 1fr&lt;/code&gt; to the &lt;code&gt;grid&lt;/code&gt; class example. The &lt;code&gt;auto&lt;/code&gt; value accommodates the vertical orientation with a changed ratio. This assumes that the images have a landscape orientation. As there are only two child elements (the image and the content) CSS grids handle the rest.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In CSS grids, row and column definitions are ignored when there are not enough elements. In the above example, when there are only enough elements to fill the first row, the &lt;code&gt;1fr&lt;/code&gt; definition of the second row is ignored.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;CSS grids enable you to solve responsive layout issues. There are ways to achieve the above, also without using media-queries. But in most cases they need more CSS to work, making those solutions more difficult to maintain. Especially when combined with &lt;a href="https://dev.to/vycke/fluid-interfaces-using-css-3kc4"&gt;fluidity&lt;/a&gt; CSS grids (and flex boxes) enable you to create websites that flow with the screen size, and not worry about breakpoints. I mean, they are called break points for a reason, right?&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>html</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
