<?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: Matthew Dean</title>
    <description>The latest articles on DEV Community by Matthew Dean (@matthewdean).</description>
    <link>https://dev.to/matthewdean</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%2F660523%2F265ba873-238c-45bd-b160-b1f0ec0e404c.jpeg</url>
      <title>DEV Community: Matthew Dean</title>
      <link>https://dev.to/matthewdean</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/matthewdean"/>
    <language>en</language>
    <item>
      <title>CSS: the language with no syntax</title>
      <dc:creator>Matthew Dean</dc:creator>
      <pubDate>Fri, 08 Aug 2025 18:13:43 +0000</pubDate>
      <link>https://dev.to/matthewdean/css-the-language-with-no-syntax-oom</link>
      <guid>https://dev.to/matthewdean/css-the-language-with-no-syntax-oom</guid>
      <description>&lt;p&gt;Congratulations! You have fallen prey to my clever click-bait-y title, but before you dismiss this topic out-of-hand ("Because," you say, "of &lt;em&gt;course&lt;/em&gt; CSS has syntax"), or leave a smarmy comment, allow me to walk you through what CSS is, and how it's defined.&lt;/p&gt;

&lt;p&gt;Some context: I've been a maintainer of Less.js (the CSS pre-processor) for about 10 years, and the lead maintainer for most of that time. When I started contributing, I knew very little about not just CSS parsing, but about parsing in general.&lt;/p&gt;

&lt;p&gt;In the last 5 years, I've worked on not just Less but other CSS-related parsing projects, including one that re-imagines both Less and Sass parsing for the modern era (which has yet to be released). I've used a variety of parsing approaches, parsing generators, and parsing libraries.&lt;/p&gt;

&lt;p&gt;In some cases, I had to abandon the use of certain parsers or parsing approaches because they just weren't flexible for CSS, and the reason is that CSS has no single syntax.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do I mean by "single syntax"?
&lt;/h2&gt;

&lt;p&gt;You can think of CSS as kind of a collection of "micro-syntaxes". CSS has kind of a top-level syntax for how things are organized (okay, okay, yes you can say that at the &lt;em&gt;top level&lt;/em&gt;, there is a syntax), and then the way it works is that individual specifications have their own micro-syntax that defines the syntax within that location. On the whole, each micro-syntax has generally tried to mostly look consistent with other micro-syntaxes before it, but that doesn't mean that they actually &lt;em&gt;are&lt;/em&gt; consistent or that the same syntax has the same semantics, as you might find in other languages.&lt;/p&gt;

&lt;p&gt;You might be scratching your head at this, because, if you've never had to parse it, or have that parser actually &lt;em&gt;understand&lt;/em&gt; all its component pieces (as it does in a system like Less), CSS syntax looks the same everywhere.&lt;/p&gt;

&lt;p&gt;So, let's illustrate this with some examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Assignment or selector?
&lt;/h2&gt;

&lt;p&gt;What does the colon &lt;code&gt;:&lt;/code&gt; mean in CSS? You might be tempted to say assignment, because of this:&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;.box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* Look! There's an assignment `:` operator! */&lt;/span&gt;
  &lt;span class="nl"&gt;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;p&gt;Okay, then, what does this mean?&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="cm"&gt;/* Look! There's... oh... */&lt;/span&gt;
&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Not a problem!" you say. This is at the start of a ruleset (also called a qualified rule), and we know that pseudo-classes and pseudo-elements start with &lt;code&gt;:&lt;/code&gt; followed by an identifier. Easy peasy.&lt;/p&gt;

&lt;p&gt;Alright, so a pseudo-selector looks like &lt;code&gt;:ident&lt;/code&gt;, cool. Okay, how do we parse this?&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;.box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* Look There's a pseudo-... oh... */&lt;/span&gt;
  &lt;span class="nt"&gt;color&lt;/span&gt;&lt;span class="nd"&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;p&gt;Okay, never mind that, we say. We can just have two modes! When we're  at the "top-level" where we're expecting rulesets, we can have &lt;code&gt;:&lt;/code&gt; mean one thing, and then inside it, we can have it mean another.&lt;/p&gt;

&lt;p&gt;Welp, not so fast. One of the reasons Less and Sass were so popular for so long was the convenience of nesting rulesets and at-rules inside each other, and both engines support this:&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;.box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="nd"&gt;:hover&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;CSS Nesting has now been adopted by the core CSS language itself, and as of 2024, is &lt;a href="https://caniuse.com/css-nesting" rel="noopener noreferrer"&gt;now supported in browsers&lt;/a&gt;. So this form is valid in CSS now too.&lt;/p&gt;

&lt;p&gt;If you know anything about parsing, you may now start to recognize that we're looking at an example of "infinite lookahead" and backtracking. Some engines either don't support infinite lookahead, or don't support it without major performance penalties. The reason it's "infinite" is because of cases like:&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;.box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;foo&lt;/span&gt;&lt;span class="nd"&gt;:red&lt;/span&gt; &lt;span class="nt"&gt;blue&lt;/span&gt; &lt;span class="nt"&gt;green&lt;/span&gt; &lt;span class="nt"&gt;yellow&lt;/span&gt; &lt;span class="nt"&gt;purple&lt;/span&gt; &lt;span class="nt"&gt;brown&lt;/span&gt; &lt;span class="nt"&gt;black&lt;/span&gt; &lt;span class="nt"&gt;grey&lt;/span&gt;&lt;span class="nc"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we parse this, we have to ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;is this a property called "foo" with a value of &lt;code&gt;red blue green yellow purple brown black grey&lt;/code&gt; etc? or&lt;/li&gt;
&lt;li&gt;is this a selector selecting an element called "foo" with a pseudo-class of &lt;code&gt;:red&lt;/code&gt; and descendant elements of &lt;code&gt;blue green yellow purple brown black grey&lt;/code&gt; etc?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are ways to avoid infinite lookahead, of course, such as having a list of all known CSS properties, and/or having a list of all known valid HTML elements, but this is already a little too deep into parsing, so let's get back on track to syntax and how CSS is defined.&lt;/p&gt;

&lt;h2&gt;
  
  
  How CSS syntax is actually defined
&lt;/h2&gt;

&lt;p&gt;The way that CSS syntax is defined is that you can think of it as having a basic outer structure with "slots" where syntax definitions can go.&lt;/p&gt;

&lt;p&gt;These "slots" are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An at-rule's "prelude" (everything before outer &lt;code&gt;;&lt;/code&gt; or its &lt;code&gt;{}&lt;/code&gt; block)&lt;/li&gt;
&lt;li&gt;An at-rule's block (&lt;code&gt;{}&lt;/code&gt;) contents&lt;/li&gt;
&lt;li&gt;A property's value&lt;/li&gt;
&lt;li&gt;A pseudo-selector's &lt;code&gt;()&lt;/code&gt; block, if it exists&lt;/li&gt;
&lt;li&gt;A CSS function's &lt;code&gt;()&lt;/code&gt; block&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example 1: at-rules
&lt;/h3&gt;

&lt;p&gt;Instead of having general parsing rules, parsing is specified by the at-rule specification itself. For example: the &lt;code&gt;@supports&lt;/code&gt; at-rule parses (or can parse) property/value pairs, like:&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;@supports&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;transform-origin&lt;/span&gt;&lt;span class="nd"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;5&lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nt"&gt;5&lt;/span&gt;&lt;span class="nv"&gt;%&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...whereas the &lt;code&gt;@scope&lt;/code&gt; rule expects to be parsing selectors e.g.&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;@scope&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.card&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example 2: :nth-child() and dimensions
&lt;/h3&gt;

&lt;p&gt;In general, CSS considers units like &lt;code&gt;-1&lt;/code&gt; to be distinct tokens. If you have this, for example, this will be parsed as two values: &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;-1&lt;/code&gt;:&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="cm"&gt;/* This has a value of 1 -1 */&lt;/span&gt;
&lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, &lt;code&gt;:nth-&lt;/code&gt; functions define their own micro-syntax: &lt;code&gt;An+B&lt;/code&gt;. Instead of the argument to &lt;code&gt;:nth-child(n-1)&lt;/code&gt; being interpreted as two tokens, &lt;code&gt;n&lt;/code&gt; and &lt;code&gt;-1&lt;/code&gt;, it's interpreted as "n minus 1", which, confusingly, is different from the &lt;code&gt;calc()&lt;/code&gt; function because, again, &lt;code&gt;calc()&lt;/code&gt; has its own micro-syntax!&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS: What's a "list"?
&lt;/h2&gt;

&lt;p&gt;One of the most frustrating and inconsistent parts of CSS syntax is that it has no formal definition for "lists". Or, rather, it has a collection of syntaxes which all &lt;em&gt;can&lt;/em&gt; represent lists, but not all of them are consistent in describing what's &lt;em&gt;in&lt;/em&gt; the list and what isn't.&lt;/p&gt;

&lt;p&gt;That said, probably the most consistent right now in CSS syntax and micro-syntaxes is comma-separated and semi-colon-separated lists, which is generally defined like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// List members are ['1', '2', '3']
1, 2, 3

// List members are ['1 1', '2 2', '3 3']
1 1, 2 2, 3 3

// List members are ['a: 1', 'b: 2', 'c: 3']
a: 1; b: 2; c: 3;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is, &lt;em&gt;in general&lt;/em&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Each comma splits the value into distinct members of the list i.e. if you have two commas, you have 3 members of the list.&lt;/li&gt;
&lt;li&gt;A semi-colon-separated list "groups" other values that, themselves, can have comma-separated lists.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You may be scratching your head and saying, "What do you mean, 'in general'? Isn't this always true in CSS?"&lt;/p&gt;

&lt;p&gt;Sorry, but nope. Where this concept begins to fall apart is in CSS function calls. The reason it begins to fall apart is because of these ambiguities in CSS syntax:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CSS functions can receive arguments. Those arguments are CSS values.&lt;/li&gt;
&lt;li&gt;CSS function arguments are a comma-separated list, BUT (importantly),&lt;/li&gt;
&lt;li&gt;CSS values can &lt;em&gt;also&lt;/em&gt; be a comma-separated list.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With early CSS functions, this wasn't an issue. All functions received values that didn't themselves have commas. Eventually, though, use cases and CSS proposals emerged for functions that &lt;em&gt;could&lt;/em&gt; receive commas. And not just functions. There emerged use cases where other CSS values, which could be comma-separated, might &lt;strong&gt;&lt;em&gt;themselves&lt;/em&gt;&lt;/strong&gt; need sub-lists as individual parts of the value.&lt;/p&gt;

&lt;p&gt;So, now what were proposal authors to do? If your guess is, "Hopefully, something consistent?" then prepare to be horribly disappointed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Many Failed Attempts at Lists-of-Lists Syntax in CSS
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The &lt;code&gt;/&lt;/code&gt; separator
&lt;/h3&gt;

&lt;p&gt;You'll probably recognize this. In some CSS values, the list separator is a slash (&lt;code&gt;/&lt;/code&gt;) character. But it would be a mistake to consider it a list separator like &lt;code&gt;,&lt;/code&gt; or &lt;code&gt;;&lt;/code&gt;. I'll explain.&lt;/p&gt;

&lt;p&gt;Let's take border-radius as an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;border-radius: 10px 20px / 30px 40px;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the border-radius syntax, this syntax is used to figure out "radius pairs" for corners. I don't want to get into the minutia of the &lt;code&gt;border-radius&lt;/code&gt; syntax, but suffice to say that the &lt;code&gt;/&lt;/code&gt; separates a set of values preceding it from a set of values following it. In this case, it's a list like: ['10px 20px', '30px 40px'].&lt;/p&gt;

&lt;p&gt;You might be tempted, then, to think of the &lt;code&gt;/&lt;/code&gt; as just another list separator. But, of course, that isn't the case.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;calc()&lt;/code&gt; was introduced, it recognized that almost all programming languages use &lt;code&gt;/&lt;/code&gt; as a "division operator". It wasn't going to re-invent the wheel, so the &lt;code&gt;calc()&lt;/code&gt; micro-syntax uses it for division and not as a list separator:&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="cm"&gt;/** This means "20px divided by 2" and not
 * "a list containing '20px' and '2' */&lt;/span&gt;
&lt;span class="nt"&gt;calc&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;20px&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nt"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some property sets, like &lt;code&gt;background-*&lt;/code&gt; for example, use comma-separated lists for individual properties, and slash-separated lists for other properties. So, when they get put together, you may get a value like this:&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="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url(a.png)&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt; &lt;span class="nb"&gt;top&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;cover&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="sx"&gt;url(b.png)&lt;/span&gt; &lt;span class="nb"&gt;right&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;contain&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 syntax perspective, what does this value mean? If you're familiar with the &lt;code&gt;background&lt;/code&gt; property(s), you may instinctively be able to read this unambiguously. But let's look at this from purely a syntax perspective.&lt;/p&gt;

&lt;p&gt;Can you tell me what the "lists" or "lists of lists" are from these CSS values?&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="na"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;three&lt;/span&gt; &lt;span class="n"&gt;four&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="na"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="n"&gt;three&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;four&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="na"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="n"&gt;three&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;four&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your brain says, "The comma splits the value into list pairs, and the slash further splits THOSE values into list pairs," it's a good guess, but, in CSS, that's just not true. It's entirely dependent on the micro-syntax of the given property. You have to know the property name to know how to understand the syntax that follows.&lt;/p&gt;

&lt;p&gt;In the case of &lt;code&gt;background&lt;/code&gt;, this is how these lists are actually grouped semantically:&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="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url(a.png)&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt; &lt;span class="nb"&gt;top&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;cover&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="sx"&gt;url(b.png)&lt;/span&gt; &lt;span class="nb"&gt;right&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;contain&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
  background: [
    [
      'url(a.png)',
      'left top'
      'cover'
    ],
    [
      'url(b.png)',
      'right',
      'contain'
    ]
  ]
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the &lt;code&gt;/&lt;/code&gt; divided lists consistently across CSS, then the semantic division of this value would be:&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="nl"&gt;background&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="s1"&gt;'url(a.png) left top'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="s1"&gt;'cover'&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s1"&gt;'url(b.png) right'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="s1"&gt;'contain'&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;Even &lt;code&gt;url(a.png) left top&lt;/code&gt; requires you to understand the micro-syntax of &lt;code&gt;background&lt;/code&gt; to know that &lt;code&gt;url(a.png)&lt;/code&gt; is the background-image and &lt;code&gt;left top&lt;/code&gt; represents a single property &lt;code&gt;background-position&lt;/code&gt; and not two distinct properties. ✨ Micro-syntaxes! ✨&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Lists of lists in function (or "function-like") calls
&lt;/h3&gt;

&lt;p&gt;One of the first functions that needed a list of lists was &lt;code&gt;var()&lt;/code&gt;. You might think of it as having two values, and it does: the custom property name and the fallback value:&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="nl"&gt;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="n"&gt;theme-color&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, CSS authors had to resolve something: what about values that have commas? The solution, in this case? Just treat everything after the first comma as being absorbed into a single value.&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="nl"&gt;font-family&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;theme-font&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Helvetica'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Is the comma consistent here? Again, take the &lt;code&gt;var()&lt;/code&gt; out of this and just think of CSS functions as a general syntax. What does this mean?&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="na"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;new-css-function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;three&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Is that a function that is taking 3 value arguments? Or is it taking one comma-separated value argument?&lt;/p&gt;

&lt;p&gt;Well, in the case of &lt;code&gt;var()&lt;/code&gt;, delightfully, it's neither. It's taking 2 arguments, the second of which can be a comma-separated argument.&lt;/p&gt;

&lt;p&gt;From a language syntax perspective, that's kind of insane, but it gets better!&lt;/p&gt;

&lt;blockquote&gt;
&lt;h4&gt;
  
  
  A note about Less / Sass's handling of lists of lists
&lt;/h4&gt;

&lt;p&gt;Since both Less and Sass (the SCSS variant) are supersets of CSS, there are cases where each had to solve lists-of-lists from a wholistic syntax perspective since CSS offers no consistent guidance in this regard.&lt;br&gt;
Sass let's you wrap values in parentheses to pass lists to functions and mixins:&lt;/p&gt;


&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sass-function&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;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="o"&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;p&gt;Less prefers that you be more explicit, because parentheses may be part of a valid value (think media query syntax), so it asks you to use Less's escape &lt;code&gt;~&lt;/code&gt; character to more clearly denote that you want the final value to be without the parentheses:&lt;/p&gt;


&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;less-function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&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;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="o"&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;/blockquote&gt;

&lt;h3&gt;
  
  
  3. The CSS Functions and Mixins Module
&lt;/h3&gt;

&lt;p&gt;Probably the most bizarre and perverse twist on trying to come up with a solution for lists of lists is the new &lt;a href="https://www.w3.org/TR/css-mixins-1/" rel="noopener noreferrer"&gt;CSS functions and mixins module proposal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It uses NONE of the prior solutions, including Sass / Less prior art, to define lists of lists and comes up with yet another. So, if you're counting, CSS and CSS preprocessor syntax now have:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;comma-separated lists&lt;/li&gt;
&lt;li&gt;semi-colon separated lists&lt;/li&gt;
&lt;li&gt;slash-separated lists (inconsistent)&lt;/li&gt;
&lt;li&gt;parentheses-grouped lists (Less and Sass)&lt;/li&gt;
&lt;li&gt;...a brand new one defined by this module: curly-brace-grouped lists&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This syntax ends up looking like this:&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="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;--max-plus-x&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nt"&gt;1px&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;7px&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;2px&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;3px&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me be clear: it's not that I think this syntax is &lt;em&gt;bad&lt;/em&gt;, necessarily; it's just that it's Yet Another Micro-syntax. IMO it has these two flaws:&lt;/p&gt;

&lt;h4&gt;
  
  
  Flaw 1
&lt;/h4&gt;

&lt;p&gt;Until now, curly braces in CSS has actually been a mostly-consistent syntax, denoting a group of rules, like:&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="cm"&gt;/* We thought we understood curly braces in CSS... */&lt;/span&gt;
&lt;span class="nc"&gt;.box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&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 authors of this module proposal have decided to break that syntax convention, entirely, such that one of the few syntax "rules" will now be, again, removed from "reliable" syntax. (Not that CSS ever specified that curly braces should / would always contain rules; it's just been a consistent syntax convention until now.)&lt;/p&gt;

&lt;h4&gt;
  
  
  Flaw 2
&lt;/h4&gt;

&lt;p&gt;Instead of CSS authors saying, "You know what? Maybe we should make a formal 'list of lists' standard in CSS and start using it," the use of this format for this module has no general applicability, and there are no plans to migrate it anywhere else.&lt;/p&gt;

&lt;p&gt;In other words, if CSS &lt;strong&gt;were&lt;/strong&gt; a single syntax, a syntax proposal with this would come with certain expectations to update other syntaxes for function calls or values to be able to use it, such as:&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="cm"&gt;/* Supporting this moving forward: */&lt;/span&gt;
&lt;span class="nl"&gt;font-family&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;theme-font&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'Helvetica'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;sans-serif&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;);
/* &lt;/span&gt;&lt;span class="na"&gt;Instead&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="na"&gt;the&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="na"&gt;inconsistent&lt;/span&gt;&lt;span class="err"&gt; `&lt;/span&gt;&lt;span class="na"&gt;rgb&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;100&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="na"&gt;100&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="na"&gt;100&lt;/span&gt;&lt;span class="err"&gt; / &lt;/span&gt;&lt;span class="na"&gt;0&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="na"&gt;5&lt;/span&gt;&lt;span class="err"&gt;)` &lt;/span&gt;&lt;span class="na"&gt;syntax&lt;/span&gt;&lt;span class="err"&gt; */
&lt;/span&gt;&lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nt"&gt;100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;100&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;0&lt;/span&gt;&lt;span class="nc"&gt;.5&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's no such proposal here. It's just Yet Another Micro-syntax.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS - not one syntax, but a smorgasbord of micro-syntaxes
&lt;/h2&gt;

&lt;p&gt;Listen: I love CSS! Sure, from a language syntax perspective, it resembles something like Howl's Moving Castle. But, from a beginner perspective, its relatively-lean syntax means that it's easy to write and quite forgiving. In some ways, its weaknesses are also its strengths.&lt;/p&gt;

&lt;p&gt;Just... don't ever try to build a CSS parser. Become a tomato farmer instead.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Addendum: despite knowing better, I've currently building a new CSS parsing &amp;amp; processing framework anyway, to replace Less / Sass / CSS modules / Tailwind / Styled Components / other styling systems, so follow me on here and/or leave a comment if you want to hear about it!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>less</category>
      <category>sass</category>
    </item>
    <item>
      <title>Why, after 20 years as a JavaScript developer, I switched to semicolons</title>
      <dc:creator>Matthew Dean</dc:creator>
      <pubDate>Sun, 13 Jul 2025 20:07:46 +0000</pubDate>
      <link>https://dev.to/matthewdean/why-after-20-years-as-a-javascript-developer-i-switched-to-semicolons-2n1c</link>
      <guid>https://dev.to/matthewdean/why-after-20-years-as-a-javascript-developer-i-switched-to-semicolons-2n1c</guid>
      <description>&lt;p&gt;This is a first of a series I thought I'd start writing (and hopefully continue writing) about my experiences over 36 years as a programmer, and 20+ years as a professional web developer. (Am I old now? I think I'm old.)&lt;/p&gt;

&lt;p&gt;First, what are we talking about? If you're new to JavaScript, you may know that JavaScript is rather forgiving of statement terminations. JavaScript isn't alone in this. Go, Swift, Kotlin, Ruby, Python, Lua... they all make semicolons optional at the end of statements.&lt;/p&gt;

&lt;p&gt;In JavaScript, the spec calls this Automatic Semicolon Insertion or ASI. The simplified explanation is that if JS sees what &lt;em&gt;would&lt;/em&gt; be a syntax error, and it &lt;em&gt;thinks&lt;/em&gt; a semicolon might fix it, it inserts one automatically.&lt;/p&gt;

&lt;p&gt;Here's an example:&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;let&lt;/span&gt; &lt;span class="nx"&gt;one&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;two&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Early in the culture of JavaScript development, almost all code examples you would find online, though, always had semicolon terminators, like:&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;let&lt;/span&gt; &lt;span class="nx"&gt;one&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;two&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The semicolon-less era
&lt;/h2&gt;

&lt;p&gt;In the early 2010s, this started to shift. Web development, as a culture, was getting more and more sophisticated, which led to more subject-matter experts with in-depth knowledge, including of esoteric concepts like ASI.&lt;/p&gt;

&lt;p&gt;Many JavaScript developers began to say, "Look, semicolons are optional 99% of the time. Why not just omit them, as a standard?" For many, because semicolons seemed unnecessary, then they were just a form of visual noise.&lt;/p&gt;

&lt;p&gt;Around the same time, teams were promoting coding with the same style, for easier maintenance and for making fewer decisions. So this new "standard" began to be incorporated in linting tools so that semicolon terminators were now not just optional, they were actually forbidden in a given codebase.&lt;/p&gt;

&lt;p&gt;Anyway, this is a lot of probably unnecessary history, which many readers may already know. The point is, why did I, after adopting semicolon-less JavaScript for over ten years, decide to abandon this as of this year (2025)?&lt;/p&gt;

&lt;h2&gt;
  
  
  99% is not 100%
&lt;/h2&gt;

&lt;p&gt;JavaScript doesn't require semicolons &lt;em&gt;most&lt;/em&gt; of the time, but when it does, errors can suddenly become very unintuitive. Let's take this code example (demonstrating variable swapping via array destructuring), which I borrowed from &lt;a href="https://medium.com/@tolulope-malomo/the-javascript-bug-from-hell-01bb1670d7ae" rel="noopener noreferrer"&gt;this Medium post&lt;/a&gt;:&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;let&lt;/span&gt; &lt;span class="nx"&gt;varOne&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;varTwo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;varOne&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;varTwo&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;varTwo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;varOne&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JavaScript will actually parse that second statement as:&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;let&lt;/span&gt; &lt;span class="nx"&gt;varTwo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;varOne&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;varTwo&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;varTwo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;varOne&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I paste the above code example in VSCode, and let TypeScript try to explain the error to me, I don't get something like "semicolon missing between line two..." blah blah blah, instead I get these errors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;'varTwo' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Type 'any[]' is not assignable to type 'string'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Index signature in type 'String' only permits reading.&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Left side of comma operator is unused and has no side effects.&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sure, if you know ASI rules, after a bit of head-scratching, you may eventually realize a semicolon is necessary here. The reason is that JavaScript will &lt;em&gt;not&lt;/em&gt; insert a semicolon before &lt;code&gt;(&lt;/code&gt; or &lt;code&gt;[&lt;/code&gt; at the start of a line,&lt;/p&gt;

&lt;p&gt;You can, of course, just add in one of two ways: either the end of the second statement or the start of the third, like:&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="c1"&gt;// Option 1&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;varOne&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;varTwo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;varOne&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;varTwo&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;varTwo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;varOne&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;// Option 2&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;varOne&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;varTwo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="p"&gt;;[&lt;/span&gt;&lt;span class="nx"&gt;varOne&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;varTwo&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;varTwo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;varOne&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interestingly most "Ditch your Semicolon" advocates have recommended Option 2, because you're not altering the &lt;em&gt;second&lt;/em&gt; statement in order to resolve the &lt;em&gt;third&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code can start to look weird fast
&lt;/h2&gt;

&lt;p&gt;Despite many advocates insisting that the above example was rare, as I said, it can make errors unintuitive, but, also, if you're working in a team where someone needs to review your code and isn't as familiar with ASI quirks, the above solutions can easily look like a typo.&lt;/p&gt;

&lt;p&gt;Additionally, in the 2010s, destructuring patterns, including re-assignment via destructuring, were not as prevalent, as it only began to be supported in middle of 2016.&lt;/p&gt;

&lt;p&gt;For these reasons, over time, I found myself needing to pepper in semicolons, because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I began to use destructuring more in my own code, including re-assignment via destructuring.&lt;/li&gt;
&lt;li&gt;I began to use TypeScript almost exclusively.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  TypeScript: adding additional problems for ASI
&lt;/h2&gt;

&lt;p&gt;Why would TypeScript make this issue worse? Let's take the following code, in JS:&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;let&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input.url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works fine! But let's take this into TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input.url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// - errors: 'input' is possibly null&lt;/span&gt;
&lt;span class="c1"&gt;//           Property 'focus' does not exist on type 'Element'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, let's fix that by casting this to what we know this element actually is.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input.url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of the sudden, &lt;em&gt;both&lt;/em&gt; these lines are reporting errors, even though we only changed the second line. Why? Because TypeScript imports all the same ASI quirks as JavaScript, meaning a line that starts with &lt;code&gt;(&lt;/code&gt; continues the statement.&lt;/p&gt;

&lt;p&gt;This began to increasingly happen to me. I would fix a type problem, which would then require me to wrap something in parentheses, which then would create new errors, which then I'd grumble and insert an awkward-looking semicolon there at the start of the statement.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was the issue with semicolons in the first place?
&lt;/h2&gt;

&lt;p&gt;Eventually, I began to wonder what I was really gaining by leaning on ASI. As software developers, we're &lt;em&gt;used&lt;/em&gt; to looking at semicolons at the end of statements. In fact, if you're a web developer, you're used to putting them at the end of CSS declarations. They just aren't a big deal.&lt;/p&gt;

&lt;p&gt;And as to visual noise? Because they are so ubiquitous, they start to visually disappear anyway.&lt;/p&gt;

&lt;p&gt;They don't even arguably require more &lt;em&gt;typing&lt;/em&gt;. I have both ESLint and "Fix on save" enabled in VSCode, meaning every save will just quietly fix any missing semicolons.&lt;/p&gt;

&lt;p&gt;As a result, I've discovered that I actually think about semicolons &lt;em&gt;less by using them than by not using them&lt;/em&gt;. There's just less cognitive overhead. Statements end with semicolons, full stop. Same-line statements are separated with semicolons. (Almost) all statements have semicolon companions. I no longer have to think about semicolons &lt;em&gt;while&lt;/em&gt; destructuring or fixing type problems. My code is no longer confusing my C# colleagues who may be reviewing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving forward;
&lt;/h2&gt;

&lt;p&gt;Anyway, for me, while this is arguably not the largest issue or problem to have, I thought it would be an interesting dive into code style decisions. And I would imagine some of the same logic may apply to other code that uses optional semicolons, and I'd be interested to hear about that!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@shantk18?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Sudharshan TK&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/text-mM9vVJ2oDeI?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>codestyle</category>
    </item>
    <item>
      <title>Simplicity as a Feature</title>
      <dc:creator>Matthew Dean</dc:creator>
      <pubDate>Fri, 26 Nov 2021 23:55:06 +0000</pubDate>
      <link>https://dev.to/matthewdean/simplicity-as-a-feature-14be</link>
      <guid>https://dev.to/matthewdean/simplicity-as-a-feature-14be</guid>
      <description>&lt;p&gt;I recently came across the article "&lt;a href="https://www.infoworld.com/article/3639050/complexity-is-killing-software-developers.html" rel="noopener noreferrer"&gt;Complexity is killing software developers&lt;/a&gt;," and I've been thinking about it ever since.&lt;/p&gt;

&lt;p&gt;The article covers a broad spectrum around software development in general, but I've been thinking specifically around the domain of front-end web development, and the multiple layers of abstraction we often buy into as being zero-cost--essentially: all feature benefits, with no significant drawbacks.&lt;/p&gt;

&lt;p&gt;We write our components in JavaScript. Except it isn't. It's TypeScript. We write a function call to update the DOM. Except it isn't a function call. It's JSX (TSX). It'll be a function call later. The JSX contains markup of what HTML elements it will render. Except it doesn't. They're "styled components", all of which are abstracted from both the elements they render and the CSS that will eventually be read by a browser. We include this component in our HTML document, except we don't. Someone wrote a 200-line Webpack config file that will magically split this component and others, along with other assets and resources, and render a linked document, based on an abstracted template. Maybe Webpack itself is abstracted, behind a tool like Next.js or Vite.&lt;/p&gt;

&lt;p&gt;At my company, I started working on a site and just mentally tallying the layers of abstraction: styled components, TypeScript, React, Redux, route strings as typed enums, content as JSON...and I started to wonder: was all this necessary? Is it worth it?&lt;/p&gt;

&lt;p&gt;Or another way to ask it: what is this costing us?&lt;/p&gt;

&lt;p&gt;First of all, I have to acknowledge that this question is ironic coming from someone who's been one of the maintainers of Less (the CSS pre-processor) for the last few years. So, it should be said that I'm not &lt;em&gt;against&lt;/em&gt; any of these abstractions on their face. I may have strong opinions about this or that tool, but there's no question (to me) that the rise of reactive libraries were a net benefit to web development, or the adoption of component-based design. I've often advocated strongly for tools like TypeScript.&lt;/p&gt;

&lt;p&gt;That said, in the past little while, I've started to feel differently, and I've been thinking about this problem from a different perspective. What I've started to see is that, where we used to add these tools to solve a particular pain point where we had before, as a culture, we in web development have acclimated to complexity regardless of the costs. Why wouldn't we use Webpack? We used it before. Why wouldn't we use TypeScript? It's what we're comfortable with.&lt;/p&gt;

&lt;p&gt;I think what we've failed to recognize--and I will include myself in this--is that for each benefit it may provide, there is a maintenance and cognitive overhead cost (among other costs) in each additional abstraction that we add into our workflow.&lt;/p&gt;

&lt;p&gt;Our monorepo takes forever to run &lt;code&gt;yarn install&lt;/code&gt;, and no one knows exactly why. The complex nest of dependencies is not something we've been able to really dig into yet, as we're plowing through each sprint. Each app takes mountains of time to compile, and to run tests, and bundles seem unnecessarily large, but to decipher that just takes more time with each layer of abstraction.&lt;/p&gt;

&lt;p&gt;Recently, I switched our dev build compiler of some of our shared packages to &lt;a href="https://swc.rs/" rel="noopener noreferrer"&gt;SWC&lt;/a&gt; from TypeScript (along with removing other abstractions), which, on the one hand, is great! You definitely should explore doing that.&lt;/p&gt;

&lt;p&gt;But... on the other hand, I was solving a problem that we ourselves had created, and this sacrilegious thought also occurred to me: what if we weren't compiling / transpiling our code at all? How much faster would that be?&lt;/p&gt;

&lt;p&gt;Immediately after I had that thought, I looked around me to make sure the web development gods were not about to smite me. After all, we've lived in a world of, if not TypeScript, surely at least Babel-ified JavaScript, but there's a question if that's needed anymore.&lt;/p&gt;

&lt;p&gt;I'm not the first one to have this thought. Rich Harris, a prominent figure in web development, having developed Ractive, Rollup, and Svelte, had this to say about moving from TypeScript back to JavaScript (with JSDoc type annotations): "Among other things, the resulting code is generally smaller than transpiled code. Building, testing etc all become much less finicky. And .d.ts files are still generated from source code."&lt;/p&gt;

&lt;p&gt;I don't want to make this entirely about TypeScript; for many teams, TypeScript may be the best option! But I think there's an overlooked value in sincerely asking the question of just how complex any project needs to be, and recognizing that each layer of abstraction is &lt;em&gt;not&lt;/em&gt; zero-cost. It may increase development time, even as it decreases it in other areas. It may increase build time or deploy time. It may increase tech debt. It can increase cognitive overhead, or the time to onboard a new developer.&lt;/p&gt;

&lt;p&gt;Do you need React, or will Svelte do? Or maybe something even lighter?&lt;/p&gt;

&lt;p&gt;Do you need Less / Sass, or styled components, or is your design system simple enough that regular ol' CSS will work?&lt;/p&gt;

&lt;p&gt;Do you need Webpack? Or is there something simpler, maybe with fewer options, but with less cognitive overhead?&lt;/p&gt;

&lt;p&gt;Do you need Redux, or can you use Zustand? Do you even need a global state library?&lt;/p&gt;

&lt;p&gt;Do you need JSX? Do you need TypeScript?&lt;/p&gt;

&lt;p&gt;I've begun to think about this as Simplicity as a Feature. Just in the way that we may optimize for performance, and build for Performance as a Feature, I'm starting to think we should optimize our tools and codebases for simplicity. Not to use the &lt;em&gt;simplest&lt;/em&gt; tools but to simply use &lt;em&gt;only&lt;/em&gt; the tools with &lt;em&gt;only&lt;/em&gt; the features that we really need. And if we start to need that next abstraction, that's okay! Sometimes there are things that are trade-offs for performance, just like there are things that are trade-offs for simplicity.&lt;/p&gt;

&lt;p&gt;But the leaner you keep your tools and your code, in theory, the faster you and your team can iterate, build, and deploy.&lt;/p&gt;

&lt;p&gt;So stop using giant boilerplate-y project templates with every conceivable feature and tool you might ever need. If you use TypeScript, it's okay to not use it on some things! Heck, it's okay to manually write an &lt;code&gt;.html&lt;/code&gt; file! It doesn't make you a bad developer, I promise!&lt;/p&gt;

&lt;p&gt;And if you're new to web development, don't buy into web sites and apps needing to be necessarily complex, and you needing to learn and use myriad layers of abstraction.&lt;/p&gt;

&lt;p&gt;It's okay for things to be simple. That might even be best.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
