<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
	<channel>
		<title>dfkaye.com</title>
		<atom:link href="https://dfkaye.composts/" rel="self" type="application/rss+xml" />
		<link>https://dfkaye.com</link>
		<description>Thoughts on building &amp;amp; Testing JavaScript, CSS, HTML, et al…</description>
		<lastBuildDate>Wed, 01 Sep 2021 21:17:48 -0700
		</lastBuildDate>
		<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
		<generator>Hugo -- gohugo.io</generator>
		
    
		
		<item>
			<title>CSS Dangling Characters</title>
			<link>https://dfkaye.com/posts/2021/09/01/css-dangling-characters/</link>
			<pubDate>Wed, 01 Sep 2021 21:17:48 -0700</pubDate><dc:creator>David F. Kaye</dc:creator>
			<guid>https://dfkaye.com/posts/2021/09/01/css-dangling-characters/</guid>
			
			<description><![CDATA[ What happens when CSS rule sets contain dangling characters after the last rule.]]></description>
			<content:encoded><![CDATA[ <p>This post follows up my previous post on <a href="/posts/2021/08/25/pseudo-comments-in-css/">Pseudo-comments in CSS</a>. That post goes into intolerably delicious detail about the ways the CSS parser lets you use non-standard characters to comment out CSS rules and rule sets.</p>
<p>The current post addresses what happens when such characters appear, or &ldquo;dangle&rdquo;, after the last rule of a rule set. All the examples shown are mistakes that should be avoided.</p>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#grouping-characters">Grouping characters</a>
<ul>
<li><a href="#opening-characters">Opening characters</a></li>
<li><a href="#closing-brace">Closing brace</a></li>
<li><a href="#closing-bracket-or-parenthesis">Closing bracket or parenthesis</a></li>
</ul>
</li>
<li><a href="#quoting-characters-and-alpha-numeric-characters">Quoting characters and Alpha-numeric characters</a>
<ul>
<li><a href="#semi-colon">Semi-colon</a></li>
<li><a href="#no-semi-colon">No semi-colon</a></li>
</ul>
</li>
<li><a href="#across-multiple-stylesheets">Across multiple stylesheets</a></li>
<li><a href="#closing-thoughts">Closing thoughts</a></li>
</ul>








<h2 tabindex="-1" id="grouping-characters">Grouping characters</h2>
<p>The grouping characters, <code>{}, [], ()</code> have surprising results and differences. The <em>opening</em> characters have the same disastrous effect, while the <em>closing</em> characters differ in their effects.</p>








<h3 tabindex="-1" id="opening-characters">Opening characters</h3>
<p>When an opening grouping character, (i.e., <code>{</code>, <code>[</code>, or <code>(</code>), is placed after the last rule, the rule is applied, but <em>all</em> subsequent selectors are ignored.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css">  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;field:hint&#34;</span><span style="color:#666">]</span> {		
		<span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">green</span>

    <span style="">{</span> <span style="color:#408080;font-style:italic">/* A dangling opening grouping character invalidates the rest of the entire stylesheet. */</span>
  }

  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;field:error&#34;</span><span style="color:#666">]</span> {
    <span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">red</span>; <span style="color:#408080;font-style:italic">/* This is ignored. */</span>
  }

  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">]</span>:<span style="color:#a2f">focus</span> {
    <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">aqua</span>; <span style="color:#408080;font-style:italic">/* This is also ignored. */</span>
  }
</code></pre></div>







<h3 tabindex="-1" id="closing-brace">Closing brace</h3>
<p>When a closing brace, <code>}</code>, is placed after the last rule, the rule is applied, but the next selector is <em>ignored</em>, and the selector after <em>that</em> is applied.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css">  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;field:hint&#34;</span><span style="color:#666">]</span> {		
		<span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">green</span>  <span style="color:#408080;font-style:italic">/* This is applied... */</span>
    
   } <span style="color:#408080;font-style:italic">/* ...despite this dangling character. */</span>
  <span style="">}</span>
  
  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;field:error&#34;</span><span style="color:#666">]</span> {
    <span style="color:#408080;font-style:italic">/* Both rules below are ignored because of the previous dangling character. */</span>

    <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">white</span>; <span style="color:#408080;font-style:italic">/* This is ignored. */</span>
    <span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">red</span>; <span style="color:#408080;font-style:italic">/* This is also ignored. */</span>
  }
  
  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">]</span>:<span style="color:#a2f">focus</span> {
    <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">aqua</span>; <span style="color:#408080;font-style:italic">/* This is applied. */</span>
  }
</code></pre></div>







<h3 tabindex="-1" id="closing-bracket-or-parenthesis">Closing bracket or parenthesis</h3>
<p>When a closing bracket, <code>]</code>, or parenthesis, <code>)</code>, is placed after the last rule, the rule is applied, <em>and</em> the next selector is applied.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css">  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;field:hint&#34;</span><span style="color:#666">]</span> {		
		<span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">green</span>  <span style="color:#408080;font-style:italic">/* This is applied. */</span>
    
    ]
  }
  
  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;field:error&#34;</span><span style="color:#666">]</span> {
    <span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">red</span>; <span style="color:#408080;font-style:italic">/* This is also applied. */</span>
  }
</code></pre></div>







<h2 tabindex="-1" id="quoting-characters-and-alpha-numeric-characters">Quoting characters and Alpha-numeric characters</h2>
<p>The double and single quote characters as well as alpha-numeric characters affect rule processing only when the last rule does not terminate with a semi-colon.</p>








<h3 tabindex="-1" id="semi-colon">Semi-colon</h3>
<p>If a semi-colon appears before the quoting or alpha-numeric character, the rule applies.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css">  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;field:hint&#34;</span><span style="color:#666">]</span> {		
		<span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">green</span>; <span style="color:#408080;font-style:italic">/* This is applied. */</span>

		<span style="">&#34;</span> <span style="color:#408080;font-style:italic">/* Dangling quote. */</span>
  }

  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;field:error&#34;</span><span style="color:#666">]</span> {
    <span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">red</span>; <span style="color:#408080;font-style:italic">/* This is applied. */</span>
  }
</code></pre></div>







<h3 tabindex="-1" id="no-semi-colon">No semi-colon</h3>
<p>If no semi-colon appears on the last rule, and a quoting or alpha-numeric character appears after that, the rule is ignored, while the subsequent selector is applied.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css">  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;field:hint&#34;</span><span style="color:#666">]</span> {		
		<span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">green</span> <span style="color:#408080;font-style:italic">/* No semi-colon. */</span>

		<span style="color:#ba2121">&#34; /* Dangling quote, terminates the rule which the parser discards as invalid. */
</span><span style="color:#ba2121">  }
</span><span style="color:#ba2121">
</span><span style="color:#ba2121">  [data-namespace=&#34;</span>field<span style="color:#666">:</span>error<span style="">&#34;</span>] <span style="">{</span>
    <span style="color:#008000;font-weight:bold">color</span><span style="color:#666">:</span> <span style="color:#008000;font-weight:bold">red</span>; <span style="color:#408080;font-style:italic">/* This is applied. */</span>
  }
</code></pre></div><p><strong>Short explanation:</strong> Without the semi-colon, the parser includes the dangling quote or alpha-numeric character as part of the rule, and then discards it as invalid. This is explained at greater depth in the other post treating pseudo-comments as <a href="/posts/2021/08/25/pseudo-comments-in-css/#pseudo-comments-as-targeted-malformedness">targeted malformedness</a>.</p>








<h2 tabindex="-1" id="across-multiple-stylesheets">Across multiple stylesheets</h2>
<p><em>This section added on 

<time datetime="2021-09-09">September 9, 2021</time>.
</em></p>
<p>CSS parsers in browsers process each stylesheet one at a time. As a result, a failure in one does not affect processing of any subsequent stylesheets, whether referenced by <code>&lt;link&gt;</code> elements or defined inline with <code>&lt;style&gt;</code> elements.</p>
<p>The following example uses three <code>&lt;style&gt;</code> elements. The second definition should fail due to the dangling open brace, <code>{</code>.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-html" data-lang="html"><span style="color:#408080;font-style:italic">&lt;!-- The following three rules run in separate stylesheets. --&gt;</span>

&lt;<span style="color:#008000;font-weight:bold">style</span>&gt;
  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;field:hint&#34;</span><span style="color:#666">]</span> {		
		<span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">green</span>  <span style="color:#408080;font-style:italic">/* This is applied. */</span>
    
    } <span style="color:#408080;font-style:italic">/* ...despite this dangling character. */</span>
  <span style="">}</span>
&lt;/<span style="color:#008000;font-weight:bold">style</span>&gt;

&lt;<span style="color:#008000;font-weight:bold">style</span>&gt;
  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;field:hint&#34;</span><span style="color:#666">]</span> {
    <span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">red</span>  <span style="color:#408080;font-style:italic">/* This is ignored... */</span>
    
    <span style="">{</span> <span style="color:#408080;font-style:italic">/* ...because of this dangling character. */</span>
  }
&lt;/<span style="color:#008000;font-weight:bold">style</span>&gt;

&lt;<span style="color:#008000;font-weight:bold">style</span>&gt;
  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;field:hint&#34;</span><span style="color:#666">]</span> {
    <span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">aqua</span>; <span style="color:#408080;font-style:italic">/* This is applied. */</span>
  }
&lt;/<span style="color:#008000;font-weight:bold">style</span>&gt;
</code></pre></div><p>Since each separate rule set only defines color, the last one, <code>aqua</code>, will be applied.</p>
<p>That will not be the case if we join the second and third rule sets into the same stylesheet, in which case only the first color, <code>green</code>, is applied.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-html" data-lang="html"><span style="color:#408080;font-style:italic">&lt;!-- The first rule runs in its own stylesheet. --&gt;</span>

&lt;<span style="color:#008000;font-weight:bold">style</span>&gt;
  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;field:hint&#34;</span><span style="color:#666">]</span> {		
		<span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">green</span>  <span style="color:#408080;font-style:italic">/* This is applied. */</span>
  }
&lt;/<span style="color:#008000;font-weight:bold">style</span>&gt;

<span style="color:#408080;font-style:italic">&lt;!-- The next two rules run in the same stylesheet. --&gt;</span>

&lt;<span style="color:#008000;font-weight:bold">style</span>&gt;
  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;field:hint&#34;</span><span style="color:#666">]</span> {
    <span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">red</span>  <span style="color:#408080;font-style:italic">/* This is ignored... */</span>
    
    <span style="">{</span> <span style="color:#408080;font-style:italic">/* ...because of this dangling character. */</span>
  }

  <span style="color:#666">[</span><span style="color:#008000;font-weight:bold">data-namespace</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;field:hint&#34;</span><span style="color:#666">]</span> {
    <span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">aqua</span>; <span style="color:#408080;font-style:italic">/* This is also ignored, because of the previous dangling character. */</span>
  }
&lt;/<span style="color:#008000;font-weight:bold">style</span>&gt;
</code></pre></div>







<h2 tabindex="-1" id="closing-thoughts">Closing thoughts</h2>
<p>Clearly, I like exploring strange behavior around the edges.</p>
<p>That said, this is not a post recommending how to turn rules off with dangling characters. That is unambiguously a mistake.</p>]]></content:encoded>
		</item>
		
		<item>
			<title>Pseudo-Comments in CSS</title>
			<link>https://dfkaye.com/posts/2021/08/25/pseudo-comments-in-css/</link>
			<pubDate>Wed, 25 Aug 2021 11:38:21 -0700</pubDate><dc:creator>David F. Kaye</dc:creator>
			<guid>https://dfkaye.com/posts/2021/08/25/pseudo-comments-in-css/</guid>
			
			<description><![CDATA[ How browsers parse CSS styles, and how to work against convention to turn off rules and rule sets when debugging CSS. Re-post of my October 2015 Sitepoint.com article.]]></description>
			<content:encoded><![CDATA[ <p><em>Thanks to <a href="https://twitter.com/impressivewebs">Louis Lazaris</a> and <a href="http://webtoolsweekly.com/">Web Tools Weekly</a>, this post was originally published on Sitepoint.com, 

<time datetime="2015-10-21">October 21, 2015</time>
, at <a href="http://www.sitepoint.com/pseudo-comments-in-css-or-how-browsers-parse-styles/">Pseudo-comments in CSS (Or, How Browsers Parse Styles)</a>. It is actually a follow-up (slightly modified) to my earlier post on CSS line rule comments.</em></p>
<h2 id="preamble">Preamble</h2>
<p>The CSS spec does not mention it, but you can mimic C-style and/or Unix-style line comments in CSS files (with some caveats). Others have written about them before (see in particular, SitePoint&rsquo;s Web Foundations post covering <a href="https://www.sitepoint.com/web-foundations/css-comments/">CSS Comments</a>). The present post examines them in further detail.</p>
<p><em>I have a follow-up post to this one that covers <a href="/posts/2021/09/01/css-dangling-characters/">dangling characters</a>.</em></p>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#css-comments">CSS comments</a></li>
<li><a href="#pseudo-comments">Pseudo-comments</a></li>
<li><a href="#semi-colons">Semi-colons</a></li>
<li><a href="#inline-vs-next-line-placement">Inline vs. Next-line placement</a></li>
<li><a href="#selectors">Selectors</a></li>
<li><a href="#pseudo-comments-as-targeted-malformedness">Pseudo-comments as targeted malformedness</a>
<ul>
<li><a href="#unknown-values">Unknown values</a></li>
<li><a href="#illegal-values">Illegal values</a></li>
<li><a href="#malformed-declarations-and-statements">Malformed declarations and statements</a></li>
<li><a href="#quoting-characters">Quoting characters</a></li>
<li><a href="#grouping-characters">Grouping characters</a></li>
</ul>
</li>
<li><a href="#at-rules">At-rules</a>
<ul>
<li><a href="#pseudo-comments-applied-to-at-rules-with-body-blocks">Pseudo-comments applied to at-rules with body blocks</a></li>
<li><a href="#pseudo-comments-applied-to-at-rules-without-body-blocks">Pseudo-comments applied to at-rules <em>without</em> body blocks</a></li>
<li><a href="#at-rules-and-unknown-at-keywords">At-rules and Unknown at-keywords</a></li>
</ul>
</li>
<li><a href="#pre-processors">Pre-processors</a>
<ul>
<li><a href="#sass">Sass</a></li>
<li><a href="#less">Less</a></li>
<li><a href="#stylus">Stylus</a></li>
</ul>
</li>
<li><a href="#best-practice">Best practice</a>
<ul>
<li><a href="#when-to-use-pseudo-comments">When to use pseudo-comments</a></li>
<li><a href="#when-to-avoid-pseudo-comments">When to avoid pseudo-comments</a></li>
</ul>
</li>
</ul>








<h2 tabindex="-1" id="css-comments">CSS comments</h2>
<p>CSS parsers, <a href="https://www.w3.org/TR/CSS2/syndata.html">per the spec</a>, officially bless one style for comments, the multi-line comment from C-style languages, which uses a start token, <code>/*</code>, and an end token, <code>*/</code>, as follows:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#408080;font-style:italic">/*
</span><span style="color:#408080;font-style:italic">  Characters between, and including, the start and end tokens are ignored by the parser.
</span><span style="color:#408080;font-style:italic">*/</span>
</code></pre></div><p>And so a rule declaration in comments will be ignored:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">red</span>;
  <span style="color:#408080;font-style:italic">/*
</span><span style="color:#408080;font-style:italic">  background: white;
</span><span style="color:#408080;font-style:italic">  */</span>
}
</code></pre></div><p>A block declaration in comments will be ignored:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#408080;font-style:italic">/*
</span><span style="color:#408080;font-style:italic">body {
</span><span style="color:#408080;font-style:italic">  background: red;
</span><span style="color:#408080;font-style:italic">}
</span><span style="color:#408080;font-style:italic">*/</span>
</code></pre></div><p>In each of those examples, we are using the comment syntax intentionally to instruct the parser to ignore the content.</p>
<p>However, we can do that by accident, as with malformed declarations, such as</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">red</span>  <span style="color:#408080;font-style:italic">/* missing semi-colon */</span>
  <span style="color:#008000;font-weight:bold">background</span><span style="color:#666">:</span> <span style="color:#008000;font-weight:bold">blue</span>;      
}
</code></pre></div><p>In this example, <em>neither</em> background declaration is applied because of the missing semi-colon. The parser scans for the <em>next</em> semi-colon, determines the entire two-line statement is malformed, and so ignores the entire lexed content. The same thing happens if we leave out the property value altogether:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>:
  <span style="color:#008000;font-weight:bold">background</span><span style="color:#666">:</span> <span style="color:#008000;font-weight:bold">blue</span>; <span style="color:#408080;font-style:italic">/* this declaration is not applied */</span>
}
</code></pre></div><p>And <em>that</em> shows that we can use malformed declarations as…</p>








<h2 tabindex="-1" id="pseudo-comments">Pseudo-comments</h2>
<p>We&rsquo;ll refer to these as &ldquo;pseudo-comments&rdquo; because, properly speaking, these are not comments that terminate at an end-of-line character. Instead they work by malforming the input that follows them, even on subsequent lines. And this is due to the error handling process for <a href="https://www.w3.org/TR/CSS2/syndata.html#rule-sets">Rule sets, declaration blocks, and selectors</a>:</p>
<blockquote>
<p>the whole statement should be ignored if there is an error anywhere in the selector, even though the rest of the selector may look reasonable in CSS 2.1.</p>
</blockquote>
<p>In the following example, taken from the spec, the second rule set is ignored due to the presence of the invalid <code>&amp;</code> character in the selector:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">h1</span><span style="color:#666">,</span> <span style="color:#008000;font-weight:bold">h2</span> {<span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">green</span> }
<span style="color:#008000;font-weight:bold">h3</span><span style="color:#666">,</span> <span style="color:#008000;font-weight:bold">h4</span> <span style="color:#666">&amp;</span> <span style="color:#008000;font-weight:bold">h5</span> {<span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">red</span> } <span style="color:#408080;font-style:italic">/* &lt;= ignored */</span>
<span style="color:#008000;font-weight:bold">h6</span> {<span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">black</span> }
</code></pre></div><p>Again, in the following, the second and third declarations are ignored due to the presence of extra characters in the background property name:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">red</span>;
  xbackground: <span style="color:#008000;font-weight:bold">white</span>; <span style="color:#408080;font-style:italic">/* property name is not recognized */</span>
  <span style="">y</span> <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">blue</span>; <span style="color:#408080;font-style:italic">/* property name is not well-formed */</span>
}
</code></pre></div><p>A quick tour around the English language keyboard shows the following special characters will act as single-line declaration comments:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">selector</span> {
  <span style="">~</span> property-name: ignored;
  <span style="">`</span> property-name: ignored;
  <span style="">!</span> property-name: ignored;
  <span style="">@</span> property-name: ignored;
  <span style="">#</span> property-name: ignored;
  <span style="">$</span> property-name: ignored;
  <span style="">%</span> property-name: ignored;
  <span style="">^</span> property-name: ignored;
  <span style="">&amp;</span> property-name: ignored;
  <span style="">*</span> property-name: ignored;
  <span style="">_</span> property-name: ignored;
  <span style="">-</span> property-name: ignored;
  <span style="">+</span> property-name: ignored;
  <span style="">=</span> property-name: ignored;
  <span style="">|</span> property-name: ignored;
  <span style="">\</span> property-name: ignored;
  <span style="">:</span> property-name: ignored;
  <span style="">&lt;</span> property-name: ignored;
  <span style="">.</span> property-name: ignored;
  <span style="">&gt;</span> property-name: ignored;
  <span style="">,</span> property-name: ignored;
  <span style="">?</span> property-name: ignored;
  <span style="">/</span> property-name: ignored;
}
</code></pre></div><p>Rather than use just any character, though, stick with C and Unix convention, and use either <code>#</code> or <code>//</code>:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#666">//</span> <span style="color:#008000;font-weight:bold">background</span><span style="color:#666">:</span> <span style="color:#008000;font-weight:bold">ignored</span><span style="color:#666">;</span>
<span style="">#</span> <span style="color:#008000;font-weight:bold">background</span><span style="color:#666">:</span> <span style="color:#008000;font-weight:bold">ignored</span><span style="color:#666">;</span>
</code></pre></div>







<h2 tabindex="-1" id="semi-colons">Semi-colons</h2>
<p>Semi-colons are the end tokens of rule declarations. Thus, they cannot &ldquo;comment&rdquo; text that follows them. In spec-speak, the parser treats a dangling semi-colon as a <em>malformed declaration</em> (a declaration missing a name, colon, or value).</p>
<p>As shown earlier, when regular multi-line comments are malformed, that is, when start and end tokens are not balanced around a rule set or declaration, the subsequent declaration or rule set is ignored by the parser. The following will in effect &ldquo;comment&rdquo; out both background declarations because the parser will search for the next end-of-declaration token (the semi-colon) for the affected declaration:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>:
  <span style="color:#008000;font-weight:bold">background</span><span style="color:#666">:</span> <span style="color:#008000;font-weight:bold">blue</span>; <span style="color:#408080;font-style:italic">/* both lines ignored */</span>
}
</code></pre></div><p>That&rsquo;s fixed by adding a semi-colon after the comment, before the next declaration (thus the background blue declaration will be applied):</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
<span style="color:#008000;font-weight:bold">background</span>: ;     <span style="color:#408080;font-style:italic">/* ignored */</span>
<span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">blue</span>; <span style="color:#408080;font-style:italic">/* processed */</span>
}
</code></pre></div><p>The effect is the same with a pseudo-comment on a line missing its semi-colon:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>: <span style="">#</span> <span style="color:#008000;font-weight:bold">red</span> <span style="color:#408080;font-style:italic">/* ignored */</span>
  <span style="color:#008000;font-weight:bold">background</span><span style="color:#666">:</span> <span style="color:#008000;font-weight:bold">blue</span>; <span style="color:#408080;font-style:italic">/* also ignored */</span>
}
</code></pre></div><p>and corrected by restoring the semi-colon:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>: <span style="">#</span> <span style="color:#008000;font-weight:bold">red</span>;  <span style="color:#408080;font-style:italic">/* ignored */</span>
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">blue</span>;   <span style="color:#408080;font-style:italic">/* processed */</span>
}
</code></pre></div><p>One interesting thing about semi-colons is that they are optional for the last rule in a rule set. If the rule set contains only one rule, the semi-colon is optional.</p>








<h2 tabindex="-1" id="inline-vs-next-line-placement">Inline vs. Next-line placement</h2>
<p>This is where the &ldquo;pseudo&rdquo; enters into the term &ldquo;pseudo-comment.&rdquo; It may be reason enough not to call these &ldquo;comments&rdquo; at all as they break from the end-of-line convention of C or Unix-style line comments.</p>
<p>A pseudo-comment placed on its own line will suppress a declaration on the next line. In the following, the background will be blue:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> { 
  <span style="">//</span>
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">white</span> <span style="color:#bc7a00">!important</span>; <span style="color:#408080;font-style:italic">/* ignored */</span>
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">blue</span>; <span style="color:#408080;font-style:italic">/* processed */</span>
}
</code></pre></div><p>A pseudo-comment placed after a valid declaration on the same line will suppress a declaration on the next line. In the following, the background will be white rather than blue:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">white</span>; <span style="">//</span> <span style="">next</span> <span style="">line</span> <span style="">is</span> <span style="">ignored...</span> 
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">blue</span> <span style="color:#bc7a00">!important</span>;
}
</code></pre></div><p>Even a &ldquo;minified&rdquo; version of a CSS selector with an inline pseudo-comment will behave as a single-declaration comment. In the following, the first background declaration is ignored due to the presence of the comment token, <code>#</code>, recognized by the parser as terminating at the next semi-colon, and the second background declaration is recognized as well-formed and therefore applied (in this case, blue will be applied to the body background):</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> { <span style="">//</span> <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">red</span> <span style="color:#bc7a00">!important</span>; <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">blue</span>; }
</code></pre></div>







<h2 tabindex="-1" id="selectors">Selectors</h2>
<p>The same rule-based behavior applies to selectors.</p>
<p>An entire selector rule set is ignored when the selector is preceded by a pseudo-comment, whether inline,</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#408080;font-style:italic">/* body is ignored */</span>
<span style="color:#666">//</span> <span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">white</span> <span style="color:#bc7a00">!important</span>;
}
</code></pre></div><p>or next-line:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#408080;font-style:italic">/* body is ignored */</span>
<span style="color:#666">//</span>
<span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">white</span> <span style="color:#bc7a00">!important</span>;
}
</code></pre></div>







<h2 tabindex="-1" id="pseudo-comments-as-targeted-malformedness">Pseudo-comments as targeted malformedness</h2>
<p>Pseudo-comments work by taking advantage of the spec&rsquo;s <a href="https://www.w3.org/TR/CSS2/syndata.html#parsing-errors">Rules for handling parsing errors</a>. In effect, they work by exploiting their malformedness.</p>








<h3 tabindex="-1" id="unknown-values">Unknown values</h3>
<blockquote>
<p>User agents must ignore a declaration with an unknown property.</p>
</blockquote>
<p>A declaration containing an unrecognized property name will not be evaluated, as, for example, the <code>comment</code> property in the following <code>body</code> rule set:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  comment: <span style="color:#ba2121">&#39;could be text or a value&#39;</span>;  <span style="color:#408080;font-style:italic">/* ignored */</span>
}
</code></pre></div>







<h3 tabindex="-1" id="illegal-values">Illegal values</h3>
<blockquote>
<p>User agents must ignore a declaration with an illegal value.</p>
</blockquote>
<p>The second <code>color</code> property defined below is ignored because the value is a <em>string</em> rather than a value or color keyword, so the color applied will be gold, not red:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">gold</span>;
  <span style="color:#008000;font-weight:bold">color</span>: <span style="color:#ba2121">&#34;red&#34;</span>; <span style="color:#408080;font-style:italic">/* ignored */</span>
}
</code></pre></div>







<h3 tabindex="-1" id="malformed-declarations-and-statements">Malformed declarations and statements</h3>
<blockquote>
<p>User agents must handle unexpected tokens encountered while parsing a declaration [or statement] by reading until the end of the declaration [or statement], while observing the rules for matching pairs of (), [], {}, &ldquo;&quot;, and &lsquo;', and correctly handling escapes.</p>
</blockquote>
<p>The second <code>color</code> rule that follows is malformed by the leading hyphen, <code>-</code>, in the property name, &ldquo;color&rdquo;, and so the rule is ignored, and the applied color will be green, not red:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">green</span>;
  <span style="">-</span><span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">red</span>;  <span style="color:#408080;font-style:italic">/* ignored */</span>
}
</code></pre></div><p>Declarations malformed by unmatched pairs of <code>()</code>, <code>[]</code>, <code>{}</code>, <code>&quot;&quot;</code>, and <code>''</code> are more comprehensively ignored (and therefore more dangerous) than others. And the quoting characters <code>&quot;&quot;</code>, and <code>''</code> are processed differently than the grouping characters <code>()</code>, <code>[]</code>, <code>{}</code>.</p>








<h3 tabindex="-1" id="quoting-characters">Quoting characters</h3>
<p>The <em>unpaired</em> apostrophe in the second declaration below will prevent the <em>subsequent</em> declaration in the rule set from being processed (thus, the background will be red):</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">red</span>;
  <span style="">&#39;</span><span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">white</span>; <span style="color:#408080;font-style:italic">/* ignored */</span>
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">blue</span>;   <span style="color:#408080;font-style:italic">/* also ignored */</span>
}
</code></pre></div><p>However, a third declaration after the apostrophe <em>will</em> be processed (thus the background will be gold):</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">red</span>;
  <span style="">&#39;</span><span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">white</span>; <span style="color:#408080;font-style:italic">/* ignored */</span>
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">blue</span>;   <span style="color:#408080;font-style:italic">/* also ignored */</span>
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">gold</span>;   <span style="color:#408080;font-style:italic">/* processed */</span>
}
</code></pre></div><p>In sum, you can&rsquo;t terminate a single quoting character on its own line.</p>








<h3 tabindex="-1" id="grouping-characters">Grouping characters</h3>
<p>In general, grouping characters <code>()</code>, <code>[]</code>, <code>{}</code> should be <em>avoided</em> as pseudo-comments because they have more drastic effects in that they interfere more extensively with the parser&rsquo;s block recognition rules, and so will &ldquo;comment&rdquo; out more than single declarations. For the sake of completeness, we&rsquo;ll examine a few of these.</p>
<p>For example, the appearance of <em>unmatched</em> starting group characters suppresses <em>all</em> subsequent declarations to the end of the <em>stylesheet</em> (not just the rule set). This is true of commas, brackets, and braces.</p>
<p>In the following, only the <code>background: red;</code> declaration is processed; all declarations and selectors after that <em>in the entire stylesheet</em> will be ignored:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">red</span>;

  <span style="color:#408080;font-style:italic">/*
</span><span style="color:#408080;font-style:italic">    Every declaration that follows will be ignored,
</span><span style="color:#408080;font-style:italic">    including all subsequent selectors,
</span><span style="color:#408080;font-style:italic">    to the end of the stylesheet.
</span><span style="color:#408080;font-style:italic">   */</span>

  <span style="">{</span>

  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">white</span>;
  <span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">aqua</span>;
  <span style="color:#008000;font-weight:bold">margin</span>: <span style="color:#666">5</span><span style="color:#b00040">px</span>;
}
</code></pre></div><p>When grouping characters are <em>matched</em>, the grouped and subsequent ungrouped declarations in the <em>rule set</em> will be suppressed. In the following, the background will be red, not gold:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">red</span>;

  <span style="color:#408080;font-style:italic">/*
</span><span style="color:#408080;font-style:italic">    Every declaration that follows will be ignored
</span><span style="color:#408080;font-style:italic">    to the end of the rule set.
</span><span style="color:#408080;font-style:italic">   */</span>

  <span style="">(</span>
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">white</span>;
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">blue</span>;
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">fuchsia</span>;
  <span style="">)</span>

  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">gold</span>;
}
</code></pre></div><p>A closing comma or bracket will suppress only the next declaration that appears. In the following, the background will be 

<del>gold</del> <ins>blue</ins>
:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">red</span>;

  <span style="">]</span>
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">white</span>;  <span style="color:#408080;font-style:italic">/* ignored */</span>
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">blue</span>;   <span style="color:#408080;font-style:italic">/* processed */</span>
}
</code></pre></div><p>A closing <em>brace</em>, <code>}</code>, however, will suppress all declarations to the end of the <em>rule set</em>. In the following, the background will be red:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
  <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">red</span>;

  }
  <span style="color:#008000;font-weight:bold">background</span><span style="color:#666">:</span> <span style="color:#008000;font-weight:bold">white</span><span style="color:#666">;</span>  <span style="color:#408080;font-style:italic">/* ignored */</span>
  <span style="color:#008000;font-weight:bold">background</span><span style="color:#666">:</span> <span style="color:#008000;font-weight:bold">blue</span><span style="color:#666">;</span>   <span style="color:#408080;font-style:italic">/* also ignored */</span>
<span style="">}</span>
</code></pre></div>







<h2 tabindex="-1" id="at-rules">At-rules</h2>
<p>At-rules (denoted by <code>@&lt;rulename&gt;</code>) have two forms:</p>
<ul>
<li>a body declaration denoted by braces, <code>{ ... }</code> (such as <code>@media</code>),</li>
<li>a rule declaration closed with a semi-colon, <code>;</code> (such as <code>@charset</code>).</li>
</ul>
<p>Pseudo-comments on body-block at-rules behave the same as for selectors (i.e., the entire at-rule is ignored).</p>








<h3 tabindex="-1" id="pseudo-comments-applied-to-at-rules-with-body-blocks">Pseudo-comments applied to at-rules with body blocks</h3>
<p>For at-rules containing body blocks, such as <code>@keyframes</code>, <code>@media</code>, <code>@page</code>, and <code>@font-face</code>, the entire at-rule rule set is ignored when the at-rule is preceded by a pseudo-comment, whether inline,</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#408080;font-style:italic">/* @media is ignored */</span>
<span style="color:#666">//</span> @<span style="color:#008000;font-weight:bold">media</span> <span style="color:#666">(</span><span style="color:#008000;font-weight:bold">min-width</span><span style="color:#666">:</span> <span style="color:#008000;font-weight:bold">0</span><span style="color:#666">)</span> {
  <span style="color:#008000;font-weight:bold">body</span> {
    <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">white</span> <span style="color:#bc7a00">!important</span>;
  }
}
</code></pre></div><p>or next-line:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#408080;font-style:italic">/* @media is ignored */</span>
<span style="color:#666">//</span>
@<span style="color:#008000;font-weight:bold">media</span> <span style="color:#666">(</span><span style="color:#008000;font-weight:bold">min-width</span><span style="color:#666">:</span> <span style="color:#008000;font-weight:bold">0</span><span style="color:#666">)</span> {
  <span style="color:#008000;font-weight:bold">body</span> {
    <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">white</span> <span style="color:#bc7a00">!important</span>;
  }
}
</code></pre></div>







<h3 tabindex="-1" id="pseudo-comments-applied-to-at-rules-_without_-body-blocks">Pseudo-comments applied to at-rules _without_ body blocks</h3>
<p>At-rules without blocks, such as <code>@charset</code> and <code>@import</code>, provide a fascinating exception to inline pseudo-comment behavior.</p>
<p>An at-rule with a pseudo-comment <em>after</em> the keyword will be ignored:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#408080;font-style:italic">/* The pseudo-comment before url() suppresses the entire @import statement. */</span>
@<span style="color:#008000;font-weight:bold">import</span> <span style="color:#666">//</span> <span style="color:#008000;font-weight:bold">url</span><span style="color:#666">(</span><span style="color:#ba2121">&#39;libs/normalize.css&#39;</span><span style="color:#666">)</span>;
</code></pre></div><p>But a pseudo-comment that <em>precedes</em> an at-rule suppresses both the import <em>and</em> the first rule or selector after the import. This is because the parser treats a pseudo-commented <code>@import</code> as a malformed statement, and looks for the next matching braces in order to complete the next rule set.</p>
<p>Thus, a pseudo-comment before one <code>@import</code> in a series of <code>@import</code> rules will suppress <em>all</em> subsequent <code>@import</code> rules <em>and</em> the first declaration or selector after the last import:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#408080;font-style:italic">/*
</span><span style="color:#408080;font-style:italic">  None of these loads because the first import is processed as a malformed statement,
</span><span style="color:#408080;font-style:italic">  and the parser looks for the next matching pair of braces, {...}.
</span><span style="color:#408080;font-style:italic"> */</span>

<span style="color:#666">//</span> @<span style="color:#008000;font-weight:bold">import</span> <span style="color:#008000;font-weight:bold">url</span><span style="color:#666">(</span><span style="color:#ba2121">&#39;libs/normalize.css&#39;</span><span style="color:#666">)</span>;
@<span style="color:#008000;font-weight:bold">import</span> <span style="color:#008000;font-weight:bold">url</span><span style="color:#666">(</span><span style="color:#ba2121">&#39;libs/normalize.css&#39;</span><span style="color:#666">)</span>;
@<span style="color:#008000;font-weight:bold">import</span> <span style="color:#008000;font-weight:bold">url</span><span style="color:#666">(</span><span style="color:#ba2121">&#39;libs/example.css&#39;</span><span style="color:#666">)</span>;
@<span style="color:#008000;font-weight:bold">import</span> <span style="color:#008000;font-weight:bold">url</span><span style="color:#666">(</span><span style="color:#ba2121">&#39;libs/other.css&#39;</span><span style="color:#666">)</span>;
@<span style="color:#008000;font-weight:bold">import</span> <span style="color:#008000;font-weight:bold">url</span><span style="color:#666">(</span><span style="color:#ba2121">&#39;libs/more.css&#39;</span><span style="color:#666">)</span>;
@<span style="color:#008000;font-weight:bold">import</span> <span style="color:#008000;font-weight:bold">url</span><span style="color:#666">(</span><span style="color:#ba2121">&#39;libs/another.css&#39;</span><span style="color:#666">)</span>;
@<span style="color:#008000;font-weight:bold">import</span> <span style="color:#008000;font-weight:bold">url</span><span style="color:#666">(</span><span style="color:#ba2121">&#39;libs/yetmore.css&#39;</span><span style="color:#666">)</span>;
</code></pre></div><p>The fix for this is surprisingly simple: 

<del>just</del>
 add an empty body block after the commented <code>@import</code></p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#408080;font-style:italic">/* Suppress loading of normalize. */</span>
<span style="color:#666">//</span> @<span style="color:#008000;font-weight:bold">import</span> <span style="color:#008000;font-weight:bold">url</span><span style="color:#666">(</span><span style="color:#ba2121">&#39;libs/normalize.css&#39;</span><span style="color:#666">)</span>;

<span style="color:#408080;font-style:italic">/* Un-suppress any remaining imports by adding a pari of braces. */</span>
{}

<span style="color:#408080;font-style:italic">/* Now, the next import will load. */</span>
@<span style="color:#008000;font-weight:bold">import</span> <span style="color:#008000;font-weight:bold">url</span><span style="color:#666">(</span><span style="color:#ba2121">&#39;libs/normalize.css&#39;</span><span style="color:#666">)</span>;
</code></pre></div><p>This is fun for debugging, but that behavior is peculiar enough that you should avoid the pseudo-comments approach to at-rules without body blocks, and use the multi-line syntax instead.</p>








<h3 tabindex="-1" id="at-rules-and-unknown-at-keywords">At-rules and Unknown at-keywords</h3>
<blockquote>
<p>User agents must ignore an invalid at-keyword together with everything following it, up to the end of the block that contains the invalid at-keyword, or up to and including the next semicolon (<code>;</code>), or up to and including the next block (<code>{…}</code>), whichever comes first.</p>
</blockquote>
<p>We can illustrate all that by using an unknown at-keyword, <code>@comment</code>, as a custom at-rule alternative to the multi-line syntax. For example, the following at-rule is parsed to the closing brace, <code>}</code>, determined to be malformed, and then ignored:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css">@<span style="color:#008000;font-weight:bold">comment</span> { 
  <span style="color:#008000;font-weight:bold">I</span><span style="">&#39;</span><span style="color:#008000;font-weight:bold">m</span> <span style="color:#008000;font-weight:bold">not</span> <span style="color:#008000;font-weight:bold">processed</span> <span style="color:#008000;font-weight:bold">in</span> <span style="color:#008000;font-weight:bold">any</span> <span style="color:#008000;font-weight:bold">way</span><span style="color:#666">.</span>
}
</code></pre></div><p>That looks harmless and readable at first, but due to the presence of the apostrophe in <code>I'm</code>, we&rsquo;ve reintroduced the quoting character problem (i.e., you can&rsquo;t terminate the single quoting character on its own line). That means, a subsequent at-rule or selector will also be ignored if our custom <code>@comment</code>'s body is closed on its own line, because the rule&rsquo;s <em>declaration</em> is malformed by the presence of the apostrophe in <code>I'm</code>:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css">@<span style="color:#008000;font-weight:bold">comment</span> { 
  <span style="color:#008000;font-weight:bold">I</span><span style="">&#39;</span><span style="color:#008000;font-weight:bold">m</span> <span style="color:#008000;font-weight:bold">not</span> <span style="color:#008000;font-weight:bold">processed</span> <span style="color:#008000;font-weight:bold">in</span> <span style="color:#008000;font-weight:bold">any</span> <span style="color:#008000;font-weight:bold">way</span><span style="color:#666">.</span> }

<span style="color:#408080;font-style:italic">/* This whole block will not be processed either! */</span>
<span style="color:#008000;font-weight:bold">body</span> { <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">blue</span>; }
</code></pre></div><p>That can be rescued with outer quotes, either inside the braces,</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css">@<span style="color:#008000;font-weight:bold">comment</span> { 
  <span style="color:#ba2121">&#34;I&#39;m not processed in any way.&#34;</span>  }  <span style="color:#408080;font-style:italic">/* Fixed. */</span>

<span style="color:#008000;font-weight:bold">body</span> { <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">blue</span>; }   <span style="color:#408080;font-style:italic">/* This block will work. */</span>
</code></pre></div><p>or by leaving off the braces and instead terminating the pseudo-comment with a semi-colon, either inline,</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css">@<span style="color:#008000;font-weight:bold">comment</span> <span style="color:#ba2121">&#34;I&#39;m not processed in any way.&#34;</span>;

<span style="color:#008000;font-weight:bold">body</span> { <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">blue</span>; }   <span style="color:#408080;font-style:italic">/* This works. */</span>
</code></pre></div><p>or next-line:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css">@<span style="color:#008000;font-weight:bold">comment</span> 
<span style="color:#ba2121">&#34;I&#39;m not processed in any way.&#34;</span>;

<span style="color:#008000;font-weight:bold">body</span> { <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">blue</span>; }   <span style="color:#408080;font-style:italic">/* This workss */</span>
</code></pre></div>







<h2 tabindex="-1" id="pre-processors">Pre-processors</h2>
<p>The various CSS pre-processors support similar multiline and single-line comments.</p>








<h3 tabindex="-1" id="sass">Sass</h3>



<blockquote>
<p>Sass supports standard multiline CSS comments with `/* */`, as well as single-line comments with `//`. The multiline comments are preserved in the CSS output where possible, while the single-line comments are removed.</p>
<cite>
&mdash; <a href="https://sass-lang.com/documentation/file.SASS_REFERENCE.html#comments">Sass-lang reference</a>.
</cite>
</blockquote>


<p>Compressed mode will normally strip out all comments, unless the comment is preceded by <code>/*!</code>.</p>
<p>However, you can use a single-character pseudo-comment, such as <code>#</code> and the output will contain the commented line.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#008000;font-weight:bold">body</span> {
   <span style="">#</span> <span style="color:#008000;font-weight:bold">background</span>: <span style="color:#008000;font-weight:bold">red</span>; 
}
</code></pre></div>







<h3 tabindex="-1" id="less">Less</h3>



<blockquote>
<p>Both block-style and inline comments may be used.</p>
<cite>
&mdash; <a href="https://lesscss.org/#comments">Less.js CSS features overview</a>.
</cite>
</blockquote>


<p>It is not clear (to me, at least) whether Less will suppress these comments or print them to the output. From StackOverflow posts, it appears Less will aggregate line-comments at block level.</p>








<h3 tabindex="-1" id="stylus">Stylus</h3>
<p>Stylus also supports multiline <code>/* */</code> and single-line comments <code>//</code>, but suppresses these from the output if the <code>compress</code> directive is enabled. If you always want multiline comments to print to the output, use Multi-line buffered comments.</p>



<blockquote>
<p>Multi-line comments which are not suppressed start with `/*!`. This tells Stylus to output the comment regardless of compression.</p>
<cite>
&mdash; <a href="https://stylus-lang.com/docs/comments.html">Stylus CSS documentation</a>.
</cite>
</blockquote>


<p>Hence,</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-css" data-lang="css"><span style="color:#408080;font-style:italic">/*!
</span><span style="color:#408080;font-style:italic"> * This will appear in the output.
</span><span style="color:#408080;font-style:italic"> */</span>
</code></pre></div>







<h2 tabindex="-1" id="best-practice">Best practice</h2>



<blockquote>
<p>Readability counts.</p>
<cite>
&mdash; <a href="https://www.python.org/dev/peps/pep-0020/#id2">The Zen of Python</a>.
</cite>
</blockquote>


<p>Comments can make obscure code more readable, but readability depends on more than one convention. Pseudo-comments in CSS are less about readability than about playing against convention (aka, the parser).</p>
<p>If you find you need to use pseudo-comments,</p>
<ul>
<li>Stick to the C and Unix convention and use either <code>//</code> or <code>#</code> for the pseudo-comment delimiter.</li>
<li>Place pseudo-comments on the same line before the item to be ignored.</li>
<li>Use whitespace to separate the pseudo-comment delimiter from the intended rule, e.g., <code># background: ignored;</code>.</li>
</ul>








<h3 tabindex="-1" id="when-to-use-pseudo-comments">When to use pseudo-comments</h3>
<ul>
<li>Use pseudo-comments for <strong>debugging</strong>, notably when using an interactive CSS edit panel, such as Chris Pederick&rsquo;s <a href="https://chrispederick.com/work/web-developer/">Web Developer extension</a> (Chrome, Firefox, Opera).</li>
<li>Use pseudo-comments to prevent <strong>individual</strong> declarations, selectors, or at-rules with bodies from being processed.</li>
</ul>








<h3 tabindex="-1" id="when-to-avoid-pseudo-comments">When to avoid pseudo-comments</h3>
<ul>
<li>Avoid pseudo-comments for use with textual descriptions and at-rules without bodies (e.g., <code>@import</code>), and use multi-line <code>/* ... */</code> comments instead.</li>
<li>Avoid the quoting characters <code>''</code>, <code>&quot;&quot;</code> as they are hard for human eyes to scan and cannot be terminated on their own line.</li>
<li>Avoid the grouping characters <code>()</code>, <code>[]</code>, <code>{}</code> as they introduce more complicated scanning (and cannot be terminated on their own line).</li>
<li>Avoid pseudo-comments in production code. Although not &ldquo;harmful&rdquo;, they are merely extra bytes at that point.</li>
</ul>]]></content:encoded>
		</item>
		
		<item>
			<title>Always Take the Promotion</title>
			<link>https://dfkaye.com/posts/2021/08/12/always-take-the-promotion/</link>
			<pubDate>Thu, 12 Aug 2021 11:51:23 -0700</pubDate><dc:creator>David F. Kaye</dc:creator>
			<guid>https://dfkaye.com/posts/2021/08/12/always-take-the-promotion/</guid>
			
			<description><![CDATA[ My half-baked career advice on whether to take the promotion with a raise, or just take the raise.]]></description>
			<content:encoded><![CDATA[ <p><a href="https://twitter.com/TapaiBalazs">

Bal&aacute;zs T&aacute;pai
</a> asked me to elaborate on my answer to this tweet from <a href="https://twitter.com/jamonholmgren">Jamon Holmgren</a>.</p>



<blockquote class="twitter-tweet"><p lang="en" dir="ltr">If you could be promoted with a raise, OR you could just get that raise without being promoted, which would you prefer?</p>&mdash; Jamon 🚜 (@jamonholmgren) <a href="https://twitter.com/jamonholmgren/status/1425505676739047426?ref_src=twsrc%5Etfw">August 11, 2021</a></blockquote>
<!--<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>-->


<h2 id="tldr">TL;DR</h2>
<p>Taking that promotion is your chance to make <em>lasting</em> improvements to anything.</p>
<h2 id="your-time-is-limited-and-so-is-your-credibility">Your time is limited and so is your credibility</h2>
<p>You may not feel ready to leave your current responsibilities or focus. You may believe a that promotion means more responsibilities, less time to do what you really want, more stress and headache.</p>
<p>That seems logical, and I once thought so, too.</p>
<p>Until I was promoted and discovered the truth: With every promotion you gain credibility and more freedom to set the agenda and improve things.</p>
<p>That won&rsquo;t always happen, but if you don&rsquo;t take the chance, then it will never happen.</p>
<p>So take it. Use that freedom. Things may not be perfect, there may be tension or politics, but they really do want you to use that freedom.</p>
<h2 id="dont-undersell-yourself">Don&rsquo;t undersell yourself</h2>
<p>You&rsquo;ve probably heard that too many times, but it&rsquo;s true. If they offer you the promotion and you don&rsquo;t take it, your career stalls. You may be happy doing what you do now for a long time, but the time comes when…</p>
<h2 id="your-perspective-will-change">Your perspective will change</h2>
<p>You&rsquo;ve probably hit that moment when you had the next good idea that was vetoed for whatever reason, but you&rsquo;re convinced you&rsquo;re on to something. How do you convince them?</p>
<p>You&rsquo;ll be tempted to carve out time from either more pressing tasks or your time away from work. We know where that leads: burnout. And you&rsquo;re not the only one on the team who has that moment.</p>
<p>Taking the promotion means you can now let your teammates take the time they need to prove or falsify their ideas. You can even give them your great next idea to work out, if they are willing.</p>
<p>And that means you are improving things already because you are reducing Fear, Uncertainty, and Doubt, allowing everyone else to grow along with you.</p>
<h2 id="youre-already-growing">You&rsquo;re already growing</h2>
<p>You&rsquo;ll soon notice how some people struggle with tasks or issues that seem simple or straightforward but they can&rsquo;t find their way out of the paper bag. You may have noticed that already and been called on to help out.</p>
<p>Guess what! You&rsquo;re already performing at the next level. So take the promotion.</p>
<h2 id="you-can-reduce-stress-by-just-listening">You can reduce stress by just listening</h2>
<p>Everyone should feel comfortable speaking their minds (in an appropriate manner, of course), trying new things (which may or may not work), following their interests (which will change with experience).</p>
<p>Anything that gets in the way of that is deferred decision-making, or <em>stress</em>. The more acute, the worse it gets, so anything that increases stress should be addressed immediately.</p>
<p>If you take that promotion, you can make that effort or delegate it to the team to address however they think best, because ultimately, <em>reducing stress <strong>is</strong> delivering</em>.</p>
<h2 id="my-experiences-some-details-omitted">My experiences (some details omitted)</h2>
<p>That&rsquo;s how it worked for me when I was a director of volunteers in San Francisco&rsquo;s Tenderloin district (a position for which I had infinitesimal training, back in the 1990s). I asked the volunteers how they wanted to improve things, they came up with their own ideas, and we agreed to them. Things improved and they became even more engaged.</p>
<p>That&rsquo;s how it worked for me when I became lead of a small distributed team building a JavaScript application for our clients (2018-19). I relied on the other members to work on things they preferred to work on and I took the &ldquo;how do I make things safer for them so they can do their work&rdquo; stuff and ran it by them and if we agreed we did it. Things improved repeatedly and we delivered.</p>
<h2 id="concluding-unscientific-summary">Concluding Unscientific Summary</h2>
<p>Ultimately, it is not your responsibilities that increase but your horizons. Your responsibilities don&rsquo;t grow, they change. As your perspective increases, so will your empathy. As your empathy increases, your team will trust you. And because you understand them better, you will trust them.</p>
<h2 id="closing">Closing</h2>
<p>Whatever your doubts or ambitions, once you gain that perspective, you can take action.</p>
<p>So take it. It is your best chance at improving anything.</p>
]]></content:encoded>
		</item>
		
		<item>
			<title>Alert-Dialog Generator</title>
			<link>https://dfkaye.com/posts/2021/08/10/alert-dialog-generator/</link>
			<pubDate>Tue, 10 Aug 2021 11:27:18 -0700</pubDate><dc:creator>David F. Kaye</dc:creator>
			<guid>https://dfkaye.com/posts/2021/08/10/alert-dialog-generator/</guid>
			
			<description><![CDATA[ A vanilla JavaScript polyfill for the browser dialog methods alert(), confirm(), prompt(), in case Google really decides to remove them all and break the web.]]></description>
			<content:encoded><![CDATA[ <h2 id="demo">Demo?</h2>
<p><a href="/demos/alert-dialog-generator/">This way&hellip;</a></p>
<h2 id="background">Background</h2>
<p>Last week (circa August 3, 2021), several people worried over the Google Chrome team&rsquo;s attempt to remove the <code>alert()</code>, <code>confirm()</code>, and <code>prompt()</code> methods from embedded <code>&lt;iframe&gt;</code> elements. Fear, Uncertainty, and Doubt ensued.</p>
<p><strong>Update</strong>: Rich Harris posted an overview of the matter as I was writing this post. Read it <a href="https://dev.to/richharris/stay-alert-d">here</a>.</p>
<p>I figured creating a polyfill couldn&rsquo;t be <em>that</em> hard, but allowed that it <em>might</em> turn out to be impossible. It&rsquo;s somewhere in between, depending on what you want.</p>
<h2 id="first-problem-emulating-synchronous-blocking-behavior">First problem: Emulating synchronous blocking behavior</h2>
<p>I tried several approaches that would block execution. What follows is the most successful approach so far.</p>
<p>All three native methods are synchronous, meaning they block other processing while displaying the modal dialogs. (There may an exception to this for certain methods in some browsers.)</p>
<p>So, after getting the dialog open-and-display logic working, I started by looking at how to make the following into a blocking call.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js"><span style="color:#008000;font-weight:bold">var</span> answer <span style="color:#666">=</span> <span style="color:#008000">window</span>.confirm(<span style="color:#ba2121">&#34;Yes?&#34;</span>);

console.log(answer); <span style="color:#408080;font-style:italic">// true or false
</span></code></pre></div><p>To do that, we have to use <code>async/await</code> functions that <code>await</code> a <code>Promise</code> field called &ldquo;wait&rdquo; in the response returned by the dialog opener (named <code>Modal</code> in this example).</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js">async <span style="color:#008000;font-weight:bold">function</span> prompt(title, defaultValue <span style="color:#666">=</span> <span style="color:#ba2121">&#34;&#34;</span>) {
  <span style="color:#008000;font-weight:bold">var</span> { wait, response } <span style="color:#666">=</span> Modal({ type<span style="color:#666">:</span> <span style="color:#ba2121">&#34;prompt&#34;</span>, message<span style="color:#666">:</span> title, defaultValue });

  await wait;

  <span style="color:#008000;font-weight:bold">return</span> response.value;
}
</code></pre></div><p>But to get the value from the Promise, we have to return it <em>unfulfilled</em> from the dialog opener (we&rsquo;ll find out why in the next section), along with the response object that we update when a user&rsquo;s response value is determined.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js"><span style="color:#008000;font-weight:bold">var</span> response <span style="color:#666">=</span> { done<span style="color:#666">:</span> <span style="color:#008000;font-weight:bold">false</span> };

<span style="color:#408080;font-style:italic">// ... code omitted for brevity
</span><span style="color:#408080;font-style:italic"></span>
<span style="color:#008000;font-weight:bold">return</span> {
  response,
  wait<span style="color:#666">:</span> <span style="color:#008000;font-weight:bold">new</span> <span style="color:#008000">Promise</span>(init)
};
</code></pre></div><p>In the dialog opener, the <code>wait</code> Promise is initialized by a function that attaches a reference to the <code>resolve</code> function that a Promise calls on itself to finish processing.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js"><span style="color:#008000;font-weight:bold">function</span> init(resolve, reject) {
  response.resolve <span style="color:#666">=</span> resolve;
}

<span style="color:#008000;font-weight:bold">var</span> wait <span style="color:#666">=</span> <span style="color:#008000;font-weight:bold">new</span> <span style="color:#008000">Promise</span>(init);
</code></pre></div><h2 id="second-problem-detecting-the-response-update">Second problem: Detecting the response update</h2>
<p>I tried two approaches to solve this problem.</p>
<p>First, I used polling with <code>setTimeout()</code> that repeated every 500ms to detect whether the response object&rsquo;s <code>done</code> field had been set. It worked; however, I realized that could waste battery energy on long-lived (open) dialogs.</p>
<p>I then tried using a <code>generator function</code> because generators use a <em>suspend-and-resume</em> mechanism. When they <code>yield</code>, they are suspended, and so do not consume any resources, They are resumed by another caller using <code>generator.next([value])</code> passing an optional value.</p>
<p>So, rather then checking on the state of the response, I let the dialog&rsquo;s action event handler call the generator and pass the response to it when the user has decided to close the dialog.</p>
<p>In the following snippet, I used a <code>co()</code> function (not my own as you&rsquo;ll read in the code comment) that accepts a generator, initializes it, advances it once with <code>gen.next()</code>, then returns a function <code>send</code> that allows the <code>keyup</code> and <code>click</code> event handler inside the dialog to update the <code>response</code> object, then call the <code>resolve()</code> function directly.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js"><span style="color:#408080;font-style:italic">// A coroutine generator, from http://syzygy.st/javascript-coroutines/,
</span><span style="color:#408080;font-style:italic">// which sadly no longer exists. This version is modified from Adam Boduch,
</span><span style="color:#408080;font-style:italic">// &#34;JavaScript Concurrency&#34;, Packt Publishing, 2015, p. 86.
</span><span style="color:#408080;font-style:italic"></span><span style="color:#008000;font-weight:bold">function</span> co(G, options) {
  <span style="color:#008000;font-weight:bold">var</span> g <span style="color:#666">=</span> G(options);
  g.next();
  <span style="color:#008000;font-weight:bold">return</span> (data) =&gt; g.next(data);
}

<span style="color:#008000;font-weight:bold">var</span> send <span style="color:#666">=</span> co(<span style="color:#008000;font-weight:bold">function</span><span style="color:#666">*</span> G(response, data) {
  <span style="color:#008000;font-weight:bold">while</span> (<span style="color:#008000;font-weight:bold">true</span>) {
    data <span style="color:#666">=</span> <span style="color:#008000;font-weight:bold">yield</span>; <span style="color:#408080;font-style:italic">// This is invoked by calling g.next(data).
</span><span style="color:#408080;font-style:italic"></span>    <span style="color:#008000">Object</span>.assign(response, data);
    <span style="color:#008000;font-weight:bold">if</span> (<span style="color:#008000">Object</span>(response).done) { <span style="color:#408080;font-style:italic">// Make sure the response is an object.
</span><span style="color:#408080;font-style:italic"></span>      <span style="color:#008000;font-weight:bold">return</span> response.resolve(response);
    }
  }
}, response);
</code></pre></div><p>Inside the dialog we listen for <code>keyup</code> and <code>click</code> events on various elements. The event handler checks whether the event <code>type</code> and <code>target</code> or key <code>code</code> are valid, then determines what value should be set in the response, and then removes the dialog and its event handlers from the DOM.</p>
<p>I&rsquo;ve omitted a lot of detail in the following snippet that shows this logic.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js"><span style="color:#008000;font-weight:bold">function</span> handler(e) {
  <span style="color:#008000;font-weight:bold">var</span> config <span style="color:#666">=</span> shouldClose(e);

  <span style="color:#008000;font-weight:bold">if</span> (<span style="color:#666">!</span>config.done) {
    <span style="color:#008000;font-weight:bold">return</span>;
  }

  <span style="color:#008000">Object</span>.assign(config, { input, prompt, confirm });

  send({ done<span style="color:#666">:</span> <span style="color:#008000;font-weight:bold">true</span>, value<span style="color:#666">:</span> getValue(config) });

  remove({ dialog, underlay, ok, cancel, handler });
}

ok.addEventListener(<span style="color:#ba2121">&#34;click&#34;</span>, handler);
cancel <span style="color:#666">&amp;&amp;</span> (cancel.addEventListener(<span style="color:#ba2121">&#34;click&#34;</span>, handler));
<span style="color:#008000">document</span>.body.addEventListener(<span style="color:#ba2121">&#34;keyup&#34;</span>, handler);
</code></pre></div><h2 id="results">Results</h2>
<p>Pretty close!</p>
<p>Even chained dialog calls in succesion (such as <code>alert( await confirm(&quot;OK&quot;) );</code>) seem to work.</p>
<p>To do that, you have to capture the return value.</p>
<p>And to do that, you have to add the <code>await</code> keyword in front of <code>confirm()</code> and <code>prompt()</code> calls.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js"><span style="color:#008000;font-weight:bold">var</span> answer <span style="color:#666">=</span> await <span style="color:#008000">window</span>.confirm(<span style="color:#ba2121">&#34;Yes?&#34;</span>);

console.log(answer); <span style="color:#408080;font-style:italic">// true or false
</span></code></pre></div><p>Luckily we don&rsquo;t need to use <code>await</code> if we don&rsquo;t need to capture that value, so <code>alert() and window.alert()</code> should just work.</p>
<p>And luckily, this solution is <em>only needed in the evergreen browsers</em> that may remove the modal methods.</p>
<p>However, the result is <em>not truly blocking behavior</em>. I used this function the console and found that while a native alert pauses the entire thread (<code>setTimeout</code> is not called), the polyfill does not. Try it:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js">setInterval(() =&gt; console.log(<span style="color:#008000">Date</span>.now()), <span style="color:#666">1000</span>);
alert(<span style="color:#ba2121">&#34;stop&#34;</span>);
</code></pre></div><h2 id="aesthetics">Aesthetics</h2>
<p>Could do better.</p>
<ul>
<li>All the styles are defined on inline <code>style</code> attributes.</li>
<li>Styles may be affected by (i.e., inherit from) rules in this site&rsquo;s own CSS file.</li>
<li>The dialog width is percentage-based, rather than fixed unit, so the dialog will expand its width as the viewport width increases.</li>
<li>The JavaScript itself is a single execution that does not export anything. That could be added when the time comes for modular re-use.</li>
</ul>
<h2 id="tests">Tests</h2>
<p>In a break from habit, I did <em>not</em> use test-driven development for this as I:</p>
<ul>
<li>did not know what I did not know,</li>
<li>only wanted to arrive at a working solution rather than a bullet-proof one,</li>
<li>don&rsquo;t intend to publish the solution to NPM.</li>
</ul>
<h2 id="bugs">Bugs</h2>
<ul>
<li><del>A press on the 

<kbd>Space</kbd>
 key still scrolls the document body behind the dialog and underlay elements.</del> <em>17 October 2022: <strong>This bug is fixed</strong> by adding a &ldquo;focusout&rdquo; event listener on the dialog adding an <code>overflow: hidden;</code> CSS rule to the <code>&lt;body&gt;</code> element and removing it when the dialog is closed.</em></li>
<li>Opening a dialog from an 

<kbd>Enter</kbd>
 key press on a button may result in closing the dialog immediately after opening.  <em>17 Octobeer 2022: __Suspect this is due to listening to <code>click</code> events rather than <code>mouseup</code> events and <code>keyup</code> events separately.</em></li>
</ul>
<p>These are fixes I leave to the reader (or myself at a later time).</p>
<h2 id="accessibility">Accessibility</h2>
<p>OK, but may need improvement.</p>
<ul>
<li>Reasonably accessible on screen readers (Navigator and Jaws) that I&rsquo;ve tested so far.</li>
<li>Works on Chrome, Edge, Firefox, and Falkon on a Windows 10 laptop.</li>
<li>Works on iOS Safari. (Note: top-level <code>await</code> is not supported by iOS Safari as of 

<time datetime="2021-08-10">10 August 2021</time>
).</li>
</ul>
<h2 id="try-it-out">Try it out</h2>
<p>There are some code samples on the demo page, where you may <a href="/demos/alert-dialog-generator/">judge for yourself</a>.</p>
]]></content:encoded>
		</item>
		
		<item>
			<title>Units Are Wholes, Not Parts</title>
			<link>https://dfkaye.com/posts/2021/07/19/units-are-wholes-not-parts/</link>
			<pubDate>Mon, 19 Jul 2021 11:15:30 -0700</pubDate><dc:creator>David F. Kaye</dc:creator>
			<guid>https://dfkaye.com/posts/2021/07/19/units-are-wholes-not-parts/</guid>
			
			<description><![CDATA[ Unit testing is not about making parts to be fitted together, but making wholes that work together. Re-post of my August 19, 2015 Wordpress blog.]]></description>
			<content:encoded><![CDATA[ <p><em>First published on wordpress, 

<time datetime="2015-08-19">August 19, 2015</time>
.</em></p>
<h2 id="unit-testers-be-likehellip">&ldquo;Unit testers be like…&rdquo;</h2>
<p>The following joke pokes fun at developers who de-couple things arbitrarily or incoherently.</p>



<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Still love this one. Unit testers be like: &quot;Looks like it&#39;s working&quot; <a href="http://t.co/KiNT4wXP4a">pic.twitter.com/KiNT4wXP4a</a></p>&mdash; Kent C. Dodds (@kentcdodds) <a href="https://twitter.com/kentcdodds/status/628658648001048577?ref_src=twsrc%5Etfw"><time datetime="2015-08-04">August 4, 2015</time></a></blockquote>
<!--script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script -->


<p>One of the follow-up jokes points to QA’s saving role in the process, i.e., <em>we need integration tests</em>.</p>
<p>If we take the joke’s underlying metaphor literally, we’ll see that it also confuses the practice of “unit testing” with testing only “parts” in isolation rather than their interaction.</p>
<p>Instead of thinking about units as parts to be fitted together, think about them as wholes that should work together. That encourages you to think from the start about how these will communicate with each other.</p>
<p>The following JavaScript function “works” but modifies nothing and returns nothing:</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js"><span style="color:#008000;font-weight:bold">function</span> A(a, b) {
    <span style="color:#ba2121">&#34;secret inner workings&#34;</span>;
}
</code></pre></div><p>That is an apt metaphor of the severed head in the joke animation. It can take input and hold a thought, but from just this design you cannot tell how it would work with anything else.</p>
<p>Once we start feeding the head some real input, what do we expect as a result? A spoken word may elicit a spoken response, in which case we need a communication strategy (vocalization, facial features, etc.). An input of food requires a different strategy (is this poison? does it taste good? what do I do with it now?).</p>
<p>Once it’s clear we need to support the head with other behavior, we can also see the need for the torso. However, it does not follow that we would then develop the torso independently of the head, since the torso would now depend on the head for information.</p>
<p>*Update, 

<time datetime="2021-07-19">July 19, 2021</time>

: I no longer agree with the tenor of this next paragraph.*

Things that necessarily depend on each other cannot be tested in isolation without mocking those dependencies. The dependencies in this case are not the separated body parts, but several other undefined systems (the circulatory, respiratory, digestive, and nervous systems, for starters). An integration test of the head, torso and legs together is actually meaningless if those dependent systems have not been identified.

When testing our programs, we are not testing the parts of the program such as variables, keywords, expressions, statements or functions independently, we are testing that they work together.

Unit testing is not about making parts to be fitted together, but making wholes that work together.


</p>]]></content:encoded>
		</item>
		
		<item>
			<title>The Plus and Minus of TDD</title>
			<link>https://dfkaye.com/posts/2021/07/19/the-plus-and-minus-of-tdd/</link>
			<pubDate>Mon, 19 Jul 2021 10:30:55 -0700</pubDate><dc:creator>David F. Kaye</dc:creator>
			<guid>https://dfkaye.com/posts/2021/07/19/the-plus-and-minus-of-tdd/</guid>
			
			<description><![CDATA[ One commenter’s great response to Cedric Beust on the pro's and cons of test-driven development. I posted this previously on the Wordpress blog in 2015 (and in a gist in 2013).]]></description>
			<content:encoded><![CDATA[ <p>The test below is not my own; it is copied from a comment by <a href="https://talbottcrowell.wordpress.com">Talbott Crowell</a> on Cedric Beust’s blog. (Cedric is the creator of <a href="https://testng.org/">TestNG</a>.)</p>
<p>Cedric&rsquo;s post, <a href="https://www.beust.com/weblog/agile-people-still-dont-get-it/">Agile people still don’t get it</a>, dates back to 

<time datetime="2006-06-07">June 7, 2006</time>
, and contains hard words for Agilists pushing TDD without acknowledging any associated costs.</p>
<p><a href="https://www.beust.com/weblog/agile-people-still-dont-get-it/#comment-5569">Talbott&rsquo;s comment</a> dates to 

<time datetime="2010-08-23">August 23, 2010</time>
, two days after the post was picked up on reddit.com. Talbott lists some advantages and disadvantages of TDD.</p>
<p><strong>Begin quote</strong></p>
<h2 id="here-are-some-things-i-like-about-tdd">Here are some things I like about TDD.</h2>
<blockquote>
<ol>
<li><strong>Interruptability</strong>: if you write a test first, and you get pulled away to a dreaded meeting, you can get back to work faster because you simply rebuild and
run your tests to remind you of what is next and exactly what problem you were
trying to solve before you were pulled away, since you wrote the code that would
fail until you implemented the solution.</li>
</ol>
</blockquote>
<blockquote>
<ol start="2">
<li><strong>Less fragility</strong>: I’m less concerned about fixing and refactoring code when I
can rerun the tests before checking in. Sometimes in large complex enterprise
projects, a small change can break some distant dependency. We’ve all been there
where we are afraid to make a change to someone else’s code because the app is
so fragile. TDD reduces stress and makes programming more enjoyable.</li>
</ol>
</blockquote>
<blockquote>
<ol start="3">
<li><strong>Refactoring</strong>: a benefit from #2 is that you can keep a clean house. Nothing
worse than code that “smells” and is not fun to debug or navigate. TDD allows
developers to constantly refactor and delete dead code so you don’t have an
increasingly growing pile of dung. It is much more fun to maintain a codebase
that is 25% of the size and clean.</li>
</ol>
</blockquote>
<blockquote>
<ol start="4">
<li><strong>Less time wasted</strong>: when a test can pinpoint a bug in seconds that can take
hours without test coverage, you realize that TDD can often reduce the time to
develop software over the course of the project.</li>
</ol>
</blockquote>
<h2 id="disadvantagesrisks">Disadvantages/Risks:</h2>
<blockquote>
<ol>
<li><strong>No buy in by developers or management</strong>: this is the biggest risk to TDD. If
you don’t have people who realize the benefits, it will never work for your team.</li>
</ol>
</blockquote>
<blockquote>
<ol start="2">
<li><strong>Dependencies</strong>: TDD should be implemented in a way that has minimal dependencies. Depending on a database connection, network connection, web services, etc.. can lead to fragile tests. There has been a ton of work in this area, especially mocking frameworks, to get around this issue. Done right, your tests should test only your logic, not external components.</li>
</ol>
</blockquote>
<blockquote>
<ol start="3">
<li><strong>Hard to add TDD later</strong>: TDD is best to have in place before you start coding. It is very difficult to add TDD to an existing project. Often the application architecture will evolve in a “testable” way when you are using TDD. You will write your code and use application frameworks like ASP.NET MVC instead of
ASP.NET WebForms for example to make testing easier and more natural.</li>
</ol>
</blockquote>
<p><strong>End quote</strong></p>]]></content:encoded>
		</item>
		
		<item>
			<title>Fixing Number.toFixed()</title>
			<link>https://dfkaye.com/posts/2021/07/17/fixing-number.tofixed/</link>
			<pubDate>Sat, 17 Jul 2021 16:57:27 -0700</pubDate><dc:creator>David F. Kaye</dc:creator>
			<guid>https://dfkaye.com/posts/2021/07/17/fixing-number.tofixed/</guid>
			
			<description><![CDATA[ I found a rounding bug in Number.toFixed() in every JavaScript environment I've tried (Chrome, Firefox, Internet Explorer, Brave, and Node.js). The fix is surprisingly simple. Read on…]]></description>
			<content:encoded><![CDATA[ <h2 id="whats-in-this-post">What&rsquo;s in this post?</h2>
<p>We create a test function to exercise JavaScript&rsquo;s <code>Number.toFixed()</code> method with several series to identify the pattern that results in the rounding bug. We also include a polyfill that fixes this issue.</p>
<p>This post first appeared in 2017 previously in a gist at <a href="https://gist.github.com/dfkaye/e977af36e668aa134c0ce55bab5bb15f">https://gist.github.com/dfkaye/e977af36e668aa134c0ce55bab5bb15f</a> and on my old wordpress blog.</p>
<p>This post is also a bit long. If you&rsquo;re not interested in the testing approach, you may skip to the addendum with my <a href="#better-solution">latest thoughts</a>.</p>
<h2 id="first-things-first">First things first</h2>
<p>I&rsquo;m aware that this is part of the whole integer-to-binary bug set introduced in the 1960s. I am still surprised that it has been tolerated for over 50 years.</p>
<h2 id="acknowledgement">Acknowledgement</h2>
<p>

<time datetime="2020-05-28">May 28, 2020</time>
, the original polyfill created in this post was updated with a fix from reader <strong>A. Shah</strong>, to account for the padding case, so that <code>(1.005).toFixed(4)</code> produces &ldquo;1.0050&rdquo; and not &ldquo;1.0051&rdquo;.</p>
<h2 id="warm-up">Warm up</h2>
<p>I found this version of the rounding bug in <code>toFixed()</code> while revising a number-formatting function that performs the same kind of thing as <code>Intl.NumberFormat.format()</code>.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js">(<span style="color:#666">1.015</span>).toFixed(<span style="color:#666">2</span>)
</code></pre></div><p>That returns &ldquo;1.01&rdquo; instead of &ldquo;1.02&rdquo;.</p>
<p>The failing test is on line 42 here: <a href="https://gist.github.com/dfkaye/0d84b88a965c5fae7719d941e7b99e2e#file-number-format-js-L42">https://gist.github.com/dfkaye/0d84b88a965c5fae7719d941e7b99e2e#file-number-format-js-L42</a>.</p>
<p>I had missed that result until yesterday (4 Dec 2017), and that spurred me to check for other problems.</p>
<h2 id="bug-reports">Bug reports</h2>
<p>There is a long history of bug reports with respect to rounding errors using <code>toFixed()</code>.</p>
<ul>
<li>Chrome <a href="https://forums.asp.net/t/1966237.aspx?toFixed+not+working+in+Chrome">https://forums.asp.net/t/1966237.aspx?toFixed+not+working+in+Chrome</a></li>
<li>Firefox <a href="http://forums.mozillazine.org/viewtopic.php?f=9&amp;t=999945">http://forums.mozillazine.org/viewtopic.php?f=9&amp;t=999945</a>
<ul>
<li>see also <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=186563">https://bugzilla.mozilla.org/show_bug.cgi?id=186563</a></li>
</ul>
</li>
<li>Internet Explorer <a href="https://stackoverflow.com/questions/10470810/javascript-tofixed-bug-in-ie6">https://stackoverflow.com/questions/10470810/javascript-tofixed-bug-in-ie6</a></li>
</ul>
<p>Here is a short sample of StackOverflow questions about this problem:</p>
<ul>
<li>

<time datetime="2012-08-24">August 24, 2012</time>
, <a href="https://stackoverflow.com/questions/12105787/tofixed-javascript-function-giving-strange-results">toFixed javascript function giving strange results?</a></li>
<li>

<time datetime="2011-03-11">March 11, 2011</time>
, <a href="https://stackoverflow.com/questions/5490687/broken-tofixed-implementation">broken toFixed implementation</a>.</li>
</ul>
<p>In general, these point out <em>a</em> bug for <em>a</em> value, but none reports a range or pattern of values returning erroneous results (at least none that I have found, I may have missed something). That leaves the programmers to focus on the small without seeing a larger pattern. I don&rsquo;t blame them for that.</p>
<h2 id="finding-the-pattern">Finding the pattern</h2>
<p>Unexpected results based on input must arise from a shared pattern in the input. So, rather than review the <a href="https://262.ecma-international.org/6.0/#sec-number.prototype.tofixed">specification for <code>Number().toFixed()</code></a>, I focused on testing with a series of values to determine where the bug shows up in each series.</p>
<h2 id="test-function">Test function</h2>
<p>I created the following test function to exercise <code>toFixed()</code> over a series of integers ranging from 1 to a <code>maxValue</code>, adding the <code>fraction</code> such as .005 to each integer. The <code>fixed</code> (number of digits) argument to <code>toFixed()</code> is calculated from the length of the <code>fraction</code> value.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js"><span style="color:#008000;font-weight:bold">function</span> test({fraction, maxValue}) {
  <span style="color:#408080;font-style:italic">// Happy side-effect: `toString()` removes trailing zeroes.
</span><span style="color:#408080;font-style:italic"></span>  fraction <span style="color:#666">=</span> fraction.toString()

<span style="color:#408080;font-style:italic">// Use this in toFixed() calls in in the filter and map functions below.
</span><span style="color:#408080;font-style:italic"></span>  <span style="color:#008000;font-weight:bold">var</span> fixLength <span style="color:#666">=</span> fraction.split(<span style="color:#ba2121">&#39;.&#39;</span>)[<span style="color:#666">1</span>].length <span style="color:#666">-</span> <span style="color:#666">1</span>
  
  <span style="color:#408080;font-style:italic">// All this to create the expectedFraction message...
</span><span style="color:#408080;font-style:italic"></span>  <span style="color:#008000;font-weight:bold">var</span> last <span style="color:#666">=</span> <span style="color:#008000">Number</span>(fraction.charAt(fraction.length <span style="color:#666">-</span> <span style="color:#666">1</span>))
  <span style="color:#008000;font-weight:bold">var</span> fixDigit <span style="color:#666">=</span> <span style="color:#008000">Number</span>(fraction.charAt(fraction.length <span style="color:#666">-</span> <span style="color:#666">2</span>))
  last <span style="color:#666">&gt;=</span> <span style="color:#666">5</span> <span style="color:#666">&amp;&amp;</span> (fixDigit <span style="color:#666">=</span> fixDigit <span style="color:#666">+</span> <span style="color:#666">1</span>)
  
  <span style="color:#408080;font-style:italic">// Replace last two digits with single `fixDigit`
</span><span style="color:#408080;font-style:italic"></span>  <span style="color:#008000;font-weight:bold">var</span> expectedFraction <span style="color:#666">=</span> fraction.replace(<span style="color:#b68">/[\d]{2,2}$/</span>, fixDigit)
  
  <span style="color:#008000;font-weight:bold">return</span> <span style="color:#008000">Array</span>(maxValue).fill(<span style="color:#666">0</span>)
    .map(<span style="color:#008000;font-weight:bold">function</span>(ignoreValue, index) { <span style="color:#008000;font-weight:bold">return</span> index <span style="color:#666">+</span> <span style="color:#666">1</span> })
    .filter(<span style="color:#008000;font-weight:bold">function</span>(integer) {
      <span style="color:#408080;font-style:italic">// Compares 1.015 to 1.0151 b/c fixing by more than one decimal place rounds correctly.
</span><span style="color:#408080;font-style:italic"></span>      
      <span style="color:#008000;font-weight:bold">var</span> number <span style="color:#666">=</span> integer <span style="color:#666">+</span> <span style="color:#008000">Number</span>(fraction) <span style="color:#408080;font-style:italic">// number 1.015
</span><span style="color:#408080;font-style:italic"></span>      <span style="color:#008000;font-weight:bold">var</span> actual <span style="color:#666">=</span> number.toFixed(fixLength) <span style="color:#408080;font-style:italic">// string &#34;1.015&#34;
</span><span style="color:#408080;font-style:italic"></span>      <span style="color:#008000;font-weight:bold">var</span> expected <span style="color:#666">=</span> <span style="color:#008000">Number</span>(number <span style="color:#666">+</span> <span style="color:#ba2121">&#39;1&#39;</span>).toFixed(fixLength) <span style="color:#408080;font-style:italic">// string &#34;1.0151&#34;
</span><span style="color:#408080;font-style:italic"></span>      
      <span style="color:#408080;font-style:italic">// Report failures
</span><span style="color:#408080;font-style:italic"></span>      <span style="color:#008000;font-weight:bold">return</span> expected <span style="color:#666">!=</span> actual
    })
    .map(<span style="color:#008000;font-weight:bold">function</span>(integer) {
      <span style="color:#408080;font-style:italic">// Format reported failures
</span><span style="color:#408080;font-style:italic"></span>      <span style="color:#008000;font-weight:bold">var</span> number <span style="color:#666">=</span> <span style="color:#008000">Number</span>(integer) <span style="color:#666">+</span> <span style="color:#008000">Number</span>(fraction)
      
      <span style="color:#008000;font-weight:bold">return</span> {
        given<span style="color:#666">:</span> number.toString(),
        expected<span style="color:#666">:</span> (<span style="color:#008000">Number</span>(integer.toFixed(<span style="color:#666">0</span>)) <span style="color:#666">+</span> <span style="color:#008000">Number</span>(expectedFraction)).toString(), actual<span style="color:#666">:</span> number.toFixed(fixLength)
      }
    })
}
</code></pre></div><h2 id="usage">Usage</h2>
<p>The following example executes on integers 1 through 128, adding the fraction .015 to each, and returns an array of &ldquo;unexpected&rdquo; results. Each result contains a <code>given</code>, <code>expected</code>, and <code>actual</code> field. Here we consume the array and print each item.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js">test({ fraction<span style="color:#666">:</span> <span style="color:#666">.015</span>, maxValue<span style="color:#666">:</span> <span style="color:#666">128</span> })
  .forEach(<span style="color:#008000;font-weight:bold">function</span>(item) {
    console.log(item)
  })
</code></pre></div><h2 id="output">Output</h2>
<p>For this case, there are 6 unexpected results.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js">{given<span style="color:#666">:</span> <span style="color:#ba2121">&#34;1.015&#34;</span>, expected<span style="color:#666">:</span> <span style="color:#ba2121">&#34;1.02&#34;</span>, actual<span style="color:#666">:</span> <span style="color:#ba2121">&#34;1.01&#34;</span>}
{given<span style="color:#666">:</span> <span style="color:#ba2121">&#34;4.015&#34;</span>, expected<span style="color:#666">:</span> <span style="color:#ba2121">&#34;4.02&#34;</span>, actual<span style="color:#666">:</span> <span style="color:#ba2121">&#34;4.01&#34;</span>}
{given<span style="color:#666">:</span> <span style="color:#ba2121">&#34;5.015&#34;</span>, expected<span style="color:#666">:</span> <span style="color:#ba2121">&#34;5.02&#34;</span>, actual<span style="color:#666">:</span> <span style="color:#ba2121">&#34;5.01&#34;</span>}
{given<span style="color:#666">:</span> <span style="color:#ba2121">&#34;6.015&#34;</span>, expected<span style="color:#666">:</span> <span style="color:#ba2121">&#34;6.02&#34;</span>, actual<span style="color:#666">:</span> <span style="color:#ba2121">&#34;6.01&#34;</span>}
{given<span style="color:#666">:</span> <span style="color:#ba2121">&#34;7.015&#34;</span>, expected<span style="color:#666">:</span> <span style="color:#ba2121">&#34;7.02&#34;</span>, actual<span style="color:#666">:</span> <span style="color:#ba2121">&#34;7.01&#34;</span>}
{given<span style="color:#666">:</span> <span style="color:#ba2121">&#34;128.015&#34;</span>, expected<span style="color:#666">:</span> <span style="color:#ba2121">&#34;128.02&#34;</span>, actual<span style="color:#666">:</span> <span style="color:#ba2121">&#34;128.01&#34;</span>}
</code></pre></div><h2 id="findings">Findings</h2>
<p>I found the bug consists of three parts:</p>
<ol>
<li>The last significant digit in the fraction must be 5 (.015 and .01500 produce the same result).</li>
<li>The fixing length must shorten the fraction by only one digit.</li>
<li>The bug appears inconsistently as different integer values are applied.</li>
</ol>
<h2 id="inconsistently">Inconsistently?</h2>
<p>Yes. For example, <code>(value).toFixed(2)</code> with different 3-digit fractions ending in 5, for integers 1 though 128, produces these results:</p>
<ul>
<li>fixing numbers ending with .005 <strong>always</strong> fails (!!)</li>
<li>fixing numbers ending with .015 fails for 1, then 4 through 7, then 128</li>
<li>fixing numbers ending with .025 fails 1, 2, 3, then 16 through 63</li>
<li>fixing numbers ending with .035 fails for 1, then 32 through 128</li>
<li>fixing numbers ending with .045 fails for 1 through 15, then 128</li>
<li>fixing numbers ending with .055 fails for 1, then 4 through 63</li>
<li>fixing numbers ending with .065 fails for 1, 2, 3, then 8 through 15, then 32 through 128</li>
<li>fixing numbers ending with .075 fails for 1, then 8 through 31, then 128</li>
<li>fixing numbers ending with .085 fails for 1 through 7, then 64 through 127 (!!)</li>
<li>fixing numbers ending with .095 fails for 1, then 4 through 7, then 16 through 128</li>
</ul>
<p>Those of you with more binary and floating-point math knowledge than I have can probably reason out the underlying cause. I leave that as an exercise for the reader.</p>
<h2 id="fixing-tofixed">Fixing <code>toFixed()</code></h2>
<p>Fixing a value <em>by more than one decimal place</em> always rounds correctly.</p>
<p>Recall earlier that we tested various 3-digit fractions against a fixing length of 2. The rounding error disappears if we add another digit to the fraction, so that, for example, <code>(1.0151).toFixed(2)</code> returns &ldquo;1.02&rdquo; as expected. (Both the test and polyfill use that knowledge for their correctness checks.)</p>
<p>That means there&rsquo;s a simple fix for all implementations of <code>toFixed()</code>: If the value contains a decimal, append &ldquo;1&rdquo; to the end of the string version of the value to be modified. That may not be &ldquo;to spec,&rdquo; but it means we will get the results we expect without having to revisit lower-level binary or floating-point operations.</p>
<h2 id="polyfill">Polyfill</h2>
<p>Until all implementations are modified, you can use the following polyfill to overwrite <code>toFixed()</code>, if you&rsquo;re comfortable doing that (not everyone is).</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js">(<span style="color:#666">1.005</span>).toFixed(<span style="color:#666">2</span>) <span style="color:#666">==</span> <span style="color:#ba2121">&#34;1.01&#34;</span> <span style="color:#666">||</span> (<span style="color:#008000;font-weight:bold">function</span> (prototype) {
  <span style="color:#008000;font-weight:bold">var</span> toFixed <span style="color:#666">=</span> prototype.toFixed;

  prototype.toFixed <span style="color:#666">=</span> <span style="color:#008000;font-weight:bold">function</span>(fractionDigits) {
    <span style="color:#008000;font-weight:bold">var</span> split <span style="color:#666">=</span> <span style="color:#008000;font-weight:bold">this</span>.toString().split(<span style="color:#ba2121">&#39;.&#39;</span>);
    <span style="color:#008000;font-weight:bold">var</span> string <span style="color:#666">=</span> <span style="color:#666">!</span>split[<span style="color:#666">1</span>]
      <span style="color:#666">?</span> split[<span style="color:#666">0</span>]
      <span style="color:#666">:</span> split[<span style="color:#666">1</span>].length <span style="color:#666">&gt;=</span> fractionDigits
          <span style="color:#666">?</span> split.join(<span style="color:#ba2121">&#39;.&#39;</span>) <span style="color:#666">+</span> <span style="color:#ba2121">&#39;1&#39;</span>
          <span style="color:#666">:</span> split.join(<span style="color:#ba2121">&#39;.&#39;</span>);
    <span style="color:#008000;font-weight:bold">var</span> number <span style="color:#666">=</span> <span style="color:#008000">Number</span>(string);

    <span style="color:#008000;font-weight:bold">return</span> toFixed.call(number, fractionDigits);
  }
}(<span style="color:#008000">Number</span>.prototype));
</code></pre></div><p>Then run the test again and check that the length of the results is zero.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js">test({ fraction<span style="color:#666">:</span> <span style="color:#666">.0015</span>, maxValue<span style="color:#666">:</span> <span style="color:#666">516</span> }) <span style="color:#408080;font-style:italic">// Array []
</span><span style="color:#408080;font-style:italic"></span>test({ fraction<span style="color:#666">:</span> <span style="color:#666">.0015</span>, maxValue<span style="color:#666">:</span> <span style="color:#666">516</span> }).length <span style="color:#408080;font-style:italic">// 0
</span></code></pre></div><p>Or just run the initial conversion that started off this post.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js">(<span style="color:#666">1.015</span>).toFixed(<span style="color:#666">2</span>) <span style="color:#408080;font-style:italic">// returns &#34;1.02&#34; as expected
</span></code></pre></div><h2 id="better-solution">Better solution</h2>
<p>Meanwhile, in February 2020 on StackOverflow, I found <a href="https://stackoverflow.com/questions/1726630/formatting-a-number-with-exactly-two-decimals-in-javascript/1726662#1726662">another solution</a> that uses the built-in <code>Number.toLocaleString()</code> method without string hacking.</p>
<div class="highlight"><pre style=";-moz-tab-size:2;-o-tab-size:2;tab-size:2"><code class="language-js" data-lang="js">(<span style="color:#666">1.005</span>).toFixed(<span style="color:#666">2</span>) <span style="color:#666">==</span> <span style="color:#ba2121">&#34;1.01&#34;</span> <span style="color:#666">||</span> (<span style="color:#008000;font-weight:bold">function</span>() {
  <span style="color:#008000">Number</span>.prototype.toFixed <span style="color:#666">=</span> <span style="color:#008000;font-weight:bold">function</span>(fractionDigits) {
    <span style="color:#008000;font-weight:bold">return</span> <span style="color:#008000;font-weight:bold">this</span>.toLocaleString(<span style="color:#008000;font-weight:bold">undefined</span>, {
      minimumFractionDigits<span style="color:#666">:</span> fractionDigits,
      maximumFractionDigits<span style="color:#666">:</span> fractionDigits
    });
  };
}());
</code></pre></div><p>Thanks go to <a href="https://stackoverflow.com/users/5445/christian-c-salvad%c3%b3">

Christian Salvad&oacute;
</a>. That&rsquo;s definitely more elegant.</p>
]]></content:encoded>
		</item>
		
	</channel>
</rss>
