<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by: http://www.phpclasses.org/rsswriter $Revision: 1.12 $ -->
<rss version="2.0">
 <channel>
  <title>AlanHogan.com</title>
  <link>https://alanhogan.com/</link>
  <description>Alan Hogan&apos;s website - Web development, Mac user tips, etc.</description>
  <pubDate>Thu, 29 Jan 2026 17:04:10 -0800</pubDate>
  <ttl>5</ttl>
  <language>en-US</language>
  <copyright>Copyright 2026, AlanHogan.com</copyright>
  <image>
   <url>http://pan.alanhogan.com/ribbon/images/ribbonlogo2.gif</url>
   <title>AlanHogan.com</title>
   <link>https://alanhogan.com/</link>
  </image>
  <item>
   <description>&lt;p&gt;It began when my domain registrar contacted me. A domain I bought years ago and never really used, they informed me, was currently being used for phishing, which is against my registrar&apos;s terms of service.&lt;/p&gt;&#10;&#10;&lt;p&gt;Hmm. I’m not a black hat, so what was going on?&lt;/p&gt;&#10;&#10;&lt;p&gt;Logging in to my registrar (NameCheap) I was able to see that my domain&apos;s DNS was pointing at DreamHost, a shared web host I use for some websites. However, when logged into DreamHost, the domain in question was not listed.&lt;/p&gt;&#10;&#10;&lt;p&gt;I figured that the most likely way this came about was this:&lt;/p&gt;&#10;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;p&gt;I pointed my domain name at my web host, intending to show a parking page.&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;I never set it up at my web host, by accidental oversight.&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Someone else noticed the default DreamHost parking page and successfully convinced DreamHost to add the domain to &lt;em&gt;their&lt;/em&gt; account.&lt;/p&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&#10;&lt;p&gt;What to do? The most obvious course of action was to reach out to my host. However, their support was unreachable! The contact form required me to select the domain in question, but the domain wasn’t in my account, it was in a scammer&apos;s. Then, I tried to use a different contact method for security and abuse, but this contact form was literally broken and could not be submitted.&lt;/p&gt;&#10;&#10;&lt;p&gt;I worked around my inability to resolve the situation with my host by using CloudFlare&apos;s free static site hosting instead, changing the DNS records at the registrar to bypass DreamHost entirely.&lt;/p&gt;&#10;&#10;&lt;p&gt;(Later I heard back from DreamHost after guessing at abuse-related email addresses in order to contact their abuse team, who told me they were already on it and had shut down the account used for phishing.)&lt;/p&gt;&#10;&#10;&lt;p&gt;My registrar was then satisfied, and I had done my part to reduce phishing on the Internet.&lt;/p&gt;&#10;</description>
   <guid>https://alanhogan.com/phishing-on-my-domain</guid>
   <link>https://alanhogan.com/phishing-on-my-domain</link>
   <category/>
   <title>How I Lent Scammers a Domain</title>
   <pubDate>Tue, 26 Nov 2024 12:42:48 -0800</pubDate>
  </item>
  <item>
   <description>&lt;p&gt;Copy-paste this minimal, modern template to start a new HTML5 web page with automatic use of system fonts, preference-respecting color themes, and mobile-friendly responsive sizing. Alternatively, just use the CSS for a quick entry into a modern look with dark mode support.&lt;/p&gt;&#10;&#10;&lt;p&gt;&lt;strong&gt;I recommend starting here when you are working on a proof of concept, spinning up a new website, or authoring a one-off web page. You’ll be effortlessly opting into good reading experiences on desktop and mobile, banishing that default &lt;span style=&quot;font-family: &apos;Times New Roman&apos;, Times, serif;&quot;&gt;Times New Roman&lt;/span&gt; look, and saving your eyes with dark mode for those late-night hacking sessions.&lt;/strong&gt;&lt;/p&gt;&#10;&#10;&lt;p&gt;The CSS in particular is good to drop into a new&#10;&lt;a href=&quot;https://codepen.io/pen?template=BaJbjQb&quot;&gt;CodePen&lt;/a&gt;,&#10;&lt;a href=&quot;https://jsfiddle.net/alanhogan/rn4v67yx/&quot;&gt;JSFiddle&lt;/a&gt;,&#10;&lt;a href=&quot;https://jsbin.com/rahicis/edit?html,output&quot;&gt;JSBin&lt;/a&gt;,&#10;or other playground. I do it all the time! The links in this paragraph will take you to a template you can easily fork for your next experiment or demo.&lt;/p&gt;&#10;&#10;&lt;h3&gt;HTML&lt;/h3&gt;&#10;&#10;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&#10;&amp;lt;html lang=&quot;en&quot;&amp;gt;&#10;  &amp;lt;head&amp;gt;&#10;    &amp;lt;meta charset=&quot;utf-8&quot; /&amp;gt;&#10;    &amp;lt;title&amp;gt;Untitled&amp;lt;/title&amp;gt;&#10;    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&amp;gt;&#10;    &amp;lt;!-- &amp;lt;meta name=&quot;description&quot; content=&quot;TODO&quot; /&amp;gt; --&amp;gt;&#10;    &amp;lt;!-- &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;TODO&quot; /&amp;gt; --&amp;gt;&#10;  &amp;lt;/head&amp;gt;&#10;  &amp;lt;body&amp;gt;&#10;    &amp;lt;h1&amp;gt;Untitled&amp;lt;/h1&amp;gt;&#10;&#10;    &amp;lt;p&amp;gt;A nearly-blank page beginning with &amp;lt;code&amp;gt;&amp;amp;lt;!doctype html&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&#10;&#10;    &amp;lt;p&amp;gt;&#10;      &amp;lt;a href=&quot;https://alanhogan.com/code/modern-html-template&quot;&#10;        &amp;gt;Based on the modern HTML template&amp;lt;/a&#10;      &amp;gt;&#10;      by &amp;lt;a href=&quot;https://alanhogan.com/&quot;&amp;gt;Alan Hogan&amp;lt;/a&amp;gt;&#10;    &amp;lt;/p&amp;gt;&#10;  &amp;lt;/body&amp;gt;&#10;&amp;lt;/html&amp;gt;&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&#10;&lt;h3&gt;CSS&lt;/h3&gt;&#10;&#10;&lt;pre&gt;&lt;code class=&quot;css&quot;&gt;/* Automatic dark mode, system fonts, and readable max-width&#10; * via https://ajh.us/template */&#10;&#10;:root {&#10;  --page-bg-color: white;&#10;  --text-color: #222;&#10;  --link-color: #06d;&#10;  --visited-link-color: #91e;&#10;  --code-color: #456658;&#10;&#10;  color-scheme: light;&#10;}&#10;&#10;@media (prefers-color-scheme: dark) {&#10;  :root {&#10;    --page-bg-color: #141414;&#10;    --text-color: #eee;&#10;    --link-color: #2af;&#10;    --visited-link-color: #c5f;&#10;    --code-color: #c5eddc;&#10;&#10;    /* Ask browser to render elements like inputs &amp;amp; scrollbars per dark theme */&#10;    color-scheme: dark;&#10;  }&#10;}&#10;&#10;* {&#10;  box-sizing: border-box;&#10;}&#10;html {&#10;  margin: 0;&#10;  padding: 0;&#10;  -webkit-text-size-adjust: 100%;&#10;  -moz-text-size-adjust: 100%;&#10;  text-size-adjust: 100%;&#10;}&#10;html,&#10;body,&#10;input,&#10;button,&#10;select,&#10;textarea {&#10;  font-family: system-ui, sans-serif;&#10;}&#10;body {&#10;  padding: calc(0.5em + 0.5vmin);&#10;  margin: 0 auto;&#10;  max-width: 40em;&#10;  background-color: var(--page-bg-color);&#10;  color: var(--text-color);&#10;&#10;  /* Good defaults for handling too-long words; won&apos;t help in most tables */&#10;  overflow-wrap: break-word;&#10;}&#10;&#10;:link {&#10;  color: var(--link-color);&#10;}&#10;:visited {&#10;  color: var(--visited-link-color);&#10;}&#10;&#10;code,&#10;tt,&#10;kbd,&#10;pre {&#10;  font-family: &quot;JetBrains Mono&quot;, &quot;IBM Plex Mono&quot;, &quot;Source Code Pro&quot;,&#10;    &quot;Cascadia Code&quot;, ui-monospace, Menlo, &quot;Ubuntu Monospace&quot;, &quot;Inconsolata&quot;,&#10;    &quot;Fira Code&quot;, &quot;Deja Vu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, Monaco,&#10;    &quot;Segoe UI Mono&quot;, &quot;Roboto Mono&quot;, &quot;Oxygen Mono&quot;, Consolas, monospace;&#10;  /* Fight famous &apos;code too big&apos; problem */&#10;  font-size: 90%;&#10;  color: var(--code-color);&#10;}&#10;pre code,&#10;pre tt,&#10;pre kbd {&#10;  /* We don&apos;t want 90% of 90% for &amp;lt;pre&amp;gt;&amp;lt;code&amp;gt; */&#10;  font-size: 100%;&#10;}&#10;&#10;/* End automatic dark mode, system fonts, and readable max-width */&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&#10;&lt;h3&gt;Preview&lt;/h3&gt;&#10;&#10;&lt;p&gt;This is an &lt;code&gt;iframe&lt;/code&gt; showing the above snippets in action.&lt;/p&gt;&#10;&#10;&lt;div class=&quot;bottom-spaced js-iframe-wrap&quot;&gt;&#10;  &lt;div id=&quot;iframe-holder&quot;&gt;&#10;    &lt;noscript&gt;&lt;b&gt;A preview will appear here if JavaScript is enabled.&lt;/b&gt;&lt;/noscript&gt;&#10;  &lt;/div&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;h3&gt;Notes&lt;/h3&gt;&#10;&#10;&lt;ul&gt;&#10;&lt;li&gt;This template indicates that content will be in English (&lt;code&gt;en&lt;/code&gt;). HTML documents without a &lt;code&gt;lang&lt;/code&gt; attribute aren’t valid.&lt;/li&gt;&#10;&lt;li&gt;It declares a UTF-8 charset, which you should probably be using anyway.&lt;/li&gt;&#10;&lt;li&gt;The &lt;code&gt;body&lt;/code&gt; is set to a default maximum width of 40 em, a great default for readable line widths. If this is limiting, move the relevant &lt;code&gt;max-width&lt;/code&gt; line so that it applies to some sort of wrapping container instead.&lt;/li&gt;&#10;&lt;li&gt;A responsive viewport is declared, meaning no side-scrolling should be necessary on mobile. Users can still pinch to zoom if desired. Notably, if you drop in big elements such as a large image, they will still cause side-scrolling without additional code.&lt;/li&gt;&#10;&lt;li&gt;Using &lt;code&gt;text-size-adjust&lt;/code&gt;, we opt out of mobile browsers mucking with font sizes. These algorithms often result in unsightly, inconsistent scaling, and we don’t need them, because we are responsive out of the gate.&lt;/li&gt;&#10;&lt;li&gt;Dark mode is supported out of the box using CSS variables and the &lt;code&gt;prefers-color-scheme&lt;/code&gt; media query. Natively drawn UI such as input elements and scrollbars will render in a dark-mode-friendly manner thanks to the &lt;code&gt;color-scheme&lt;/code&gt; property.&lt;/li&gt;&#10;&lt;li&gt;Minimal base CSS styles are provided, including body background and text colors and unvisited and visited link colors. Most elements will display per browser default styles.&lt;/li&gt;&#10;&lt;li&gt;All elements are initialized to use border-box sizing.&lt;/li&gt;&#10;&lt;li&gt;All colors are set using CSS variables, which will fail to apply in Internet Explorer, Edge &amp;lt; 15, Android Browser &amp;lt; 5, and Opera Mini (where browser defaults will apply instead). The &lt;a href=&quot;https://caniuse.com/css-variables&quot;&gt;vast majority&lt;/a&gt; of Internet users are now in browsers that support CSS variables.&lt;/li&gt;&#10;&lt;li&gt;I provided a commented-out &lt;code&gt;meta&lt;/code&gt; description tag in the &lt;code&gt;head&lt;/code&gt;. Use it to &lt;a href=&quot;/html-myths#meta-desc&quot; title=&quot;My HTML myths page on meta descriptions&quot;&gt;suggest content&lt;/a&gt; for search engine results pages.&lt;/li&gt;&#10;&lt;li&gt;This HTML (&lt;a href=&quot;https://validator.w3.org/#validate_by_input&quot; title=&quot;HTML validator&quot;&gt;check&lt;/a&gt;) and CSS (&lt;a href=&quot;https://jigsaw.w3.org/css-validator/#validate_by_input&quot; title=&quot;CSS validator&quot;&gt;check&lt;/a&gt;) pass validation.&lt;/li&gt;&#10;&lt;li&gt;In early drafts of this post, I had included a &lt;code&gt;no-js&lt;/code&gt; utility class on &lt;code&gt;html&lt;/code&gt; and then removed it with JavaScript. However, in keeping with this template’s goals of being modern, minimal, and best-practice oriented, I am no longer including this code. Instead of using a class on HTML in order to show/hide content based on the availability of JavaScript, I would encourage the use of &lt;em&gt;progressive enhancement&lt;/em&gt; (adding or changing the UI with JS, when enabled, and gracefully handling the no-JS experience when possible) and &lt;code&gt;noscript&lt;/code&gt; tags (a built-in way to provide content for browsers without JS enabled or supported).&lt;sup id=&quot;fnref:no-js&quot;&gt;&lt;a href=&quot;#fn:no-js&quot; class=&quot;footnote-ref&quot; role=&quot;doc-noteref&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10;&lt;h3&gt;Modern means slim&lt;/h3&gt;&#10;&#10;&lt;p&gt;Here are some things that you might have seen here if I created this template a decade or so earlier:&lt;/p&gt;&#10;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;p&gt;A directive opting into the latest MSIE rendering engine.&lt;sup id=&quot;fnref:x-ua&quot;&gt;&lt;a href=&quot;#fn:x-ua&quot; class=&quot;footnote-ref&quot; role=&quot;doc-noteref&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; You don’t need this anymore:&lt;br /&gt;&#10;&lt;code&gt;&amp;lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge,chrome=1&quot;&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;An XML namespace and/or XHTML doctypes&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;MIME types in &lt;code&gt;&amp;lt;link rel=&quot;stylesheet&quot;&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;An “HTML5 reset” to help old browsers play more nicely with new HTML tags&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Any sort of polyfill or feature detection&lt;/p&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10;&lt;p&gt;Are you familiar with &lt;a href=&quot;https://html5boilerplate.com/&quot;&gt;the HTML5 Boilerplate project&lt;/a&gt;? In many senses it is a direct competitor to my much slimmer template, which is like an HTML5 boilerplate without the boilerplate. You might still want to check out that project if you are embarking on a big project, because it comes with a lot more. (But maybe you don&apos;t want or need more.) It used to come with jQuery until 2020. It still ships with Modernizr (feature detection), an NPM package.json file, an iconset, and a lot more that you may or may not actually want. My humble offering is a fraction of the size and complexity — more focused on table stakes, not the whole menu.&lt;/p&gt;&#10;&#10;&lt;h3&gt;What you might want to add&lt;/h3&gt;&#10;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;p&gt;&lt;strong&gt;OpenGraph meta tags for richer link previews in social media:&lt;/strong&gt;&#10;I’m not an expert here, but I think &lt;a href=&quot;https://www.opengraph.xyz/&quot;&gt;this&lt;/a&gt; is a good place to get started.&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Manual dark/light mode switching:&lt;/strong&gt;&#10;See &lt;a href=&quot;https://codepen.io/alanhogan/pen/PoEgwxL&quot;&gt;this codepen&lt;/a&gt; for a working example that doesn&apos;t require JavaScript, or &lt;a href=&quot;https://codepen.io/alanhogan/pen/OJvNPpL&quot;&gt;this one&lt;/a&gt; for a JavaScript-based solution that detects the user&apos;s system preference and allows persistent overrides with &lt;code&gt;localStorage&lt;/code&gt; (I really like this one!).&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Feature detection-based warnings, errors, or redirections for users of incapable browsers:&lt;/strong&gt;&#10;This is a topic for another day, but I strongly recommend using the technique of &apos;feature detection&apos; for required web platform features and &apos;progressive enhancement&apos; and/or &apos;graceful degradation&apos; for features that &apos;merely&apos; improve the experience.&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;&lt;strong&gt;More typographical love:&lt;/strong&gt; Web typography is an enormous topic, but if you have any narrow columns in your layout, you may want to consider applying &lt;code&gt;hyphens: auto;&lt;/code&gt; (and &lt;code&gt;-webkit-hyphens: auto&lt;/code&gt;) to them, to allow long words to break gracefully with hyphenation, newspaper-style.&lt;/p&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10;&lt;h3&gt;Final thoughts&lt;/h3&gt;&#10;&#10;&lt;p&gt;Web development has, in many ways, gotten incredibly complex over the last 20 years or so, with long chains of technologies used for development and deployment of web apps. But the simple meat and potatoes of web technologies — “vanilla” HTML, CSS, and JS — these have gotten simpler and easier in the years since the HTML5 project was undertaken (and since Microsoft abandoned Trident). Why? Because HTML5 was a huge success. As I view it, HTML5 was an effort to (1) pave the cowpaths of how people actually write HTML instead of insisting on theory-based adherence to specifications, and (2) standardize all the different browsers in terms of how they handle edge cases, malformed code, and web standards in general. In these aims HTML5 has been hugely effective. It means you really can start making beautiful, performant websites that meet users on their preferred devices (and with their preferred color scheme!) using incredibly few lines of code. For that, I am grateful.&lt;/p&gt;&#10;&#10;&lt;p&gt;&lt;em&gt;Thanks to Matthew Chavez, Louis Cruz, and Greg Hogan for feedback on a draft of this post.&lt;/em&gt;&lt;/p&gt;&#10;&#10;&lt;script&gt;&#10;const preEls = document.querySelectorAll(&quot;#content pre&quot;);&#10;const html = preEls[0].innerText;&#10;const css = preEls[1].innerText;&#10;&#10;// SHOW IFRAME&#10;const cssComment = /&lt;!--[^\n]+stylesheet[^\n]+--&gt;/;&#10;const replaced = html.replace(cssComment, &quot;\u003Cstyle&gt;&quot; + css + &quot;\u003C/style&gt;&quot;);&#10;const iframeHolderEl = document.getElementById(&apos;iframe-holder&apos;);&#10;const iframe = document.createElement(&apos;iframe&apos;);&#10;iframeHolderEl.replaceChildren(iframe);&#10;const frameDoc =&#10;  iframe.contentWindow ? iframe.contentWindow.document : iframe.contentDocument;&#10;frameDoc.write(replaced);&#10;frameDoc.close();&#10;iframe.style = &quot;width: 100%; border: 1px solid #888; min-height: 12em;&quot;;&#10;&#10;// ADD BUTTON TO EXPAND/SHRINK IFRAME&#10;const widenText = &apos;← Widen iframe (desktop only) →&apos;;&#10;const shrinkText = &apos;→ Narrow iframe (desktop only) ←&apos;;&#10;const sizeToggleButtonEl = document.createElement(&apos;button&apos;);&#10;sizeToggleButtonEl.classList.add(&apos;button&apos;, &apos;button--skinny&apos;);&#10;sizeToggleButtonEl.innerText = widenText;&#10;const sizeToggleWrapEl = document.createElement(&apos;p&apos;);&#10;sizeToggleWrapEl.appendChild(sizeToggleButtonEl);&#10;const iframeWrap = document.querySelector(&apos;.js-iframe-wrap&apos;);&#10;iframeWrap.parentNode.insertBefore(sizeToggleWrapEl, iframeWrap);&#10;sizeToggleButtonEl.addEventListener(&apos;click&apos;, (e) =&gt; {&#10;  if (iframeWrap.classList.contains(&apos;large-picture-wrap&apos;)) {&#10;    iframeWrap.classList.remove(&apos;large-picture-wrap&apos;);&#10;    sizeToggleButtonEl.innerText = widenText;&#10;  } else {&#10;    iframeWrap.classList.add(&apos;large-picture-wrap&apos;);&#10;    sizeToggleButtonEl.innerText = shrinkText;&#10;  }&#10;})&#10;&#10;// ENHANCE DISPLAY AND ADD COPY BUTTON&#10;preEls.forEach((el) =&gt; {&#10;  // reasonable heights for any screen&#10;  el.style.maxHeight = &apos;55vh&apos;;&#10;  el.style.height = &apos;24em&apos;;&#10;  el.style.minHeight = &apos;8em&apos;;&#10;  el.style.overflowY = &apos;auto&apos;;&#10;&#10;  // Add copy buttons&#10;  const newDivEl = document.createElement(&apos;div&apos;);&#10;  newDivEl.style = `text-align: right; padding-bottom: 0.4em`;&#10;  const newButtonEl = document.createElement(&apos;button&apos;);&#10;  const normalButtonText = &apos;Copy to Clipboard&apos;;&#10;  newButtonEl.classList.add(&apos;button&apos;, &apos;button--skinny&apos;);&#10;  newButtonEl.style.minWidth = &apos;12em&apos;; // avoid jitter when text changes&#10;  newButtonEl.innerText = normalButtonText;&#10;  newButtonEl.addEventListener(&apos;click&apos;, (e) =&gt; {&#10;    if (navigator.clipboard) {&#10;      navigator.clipboard.writeText(el.innerText).then(() =&gt; {&#10;        newButtonEl.innerText = &apos;Copied!&apos;;&#10;        setTimeout(() =&gt; {&#10;          newButtonEl.innerText = normalButtonText;&#10;        }, 2000);&#10;      });&#10;    } else {&#10;      newButtonEl.innerText = &apos;Failed&apos;;&#10;      newButtonEl.disabled = true;&#10;      setTimeout(() =&gt; {&#10;        newButtonEl.innerText = normalButtonText;&#10;        newButtonEl.disabled = false;&#10;      }, 2000);      &#10;    }&#10;  });&#10;  newDivEl.appendChild(newButtonEl);&#10;  el.parentNode.insertBefore(newDivEl, el);&#10;});&#10;&lt;/script&gt;&#10;&#10;&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;&#10;&lt;div class=&quot;hr&quot;&gt;&lt;hr /&gt;&lt;/div&gt;&#10;&lt;ol&gt;&#10;&#10;&lt;li id=&quot;fn:no-js&quot; role=&quot;doc-endnote&quot;&gt;&#10;&lt;p&gt;If you really want the &lt;code&gt;.no-js&lt;/code&gt; class, &lt;a href=&quot;/contact?from=modern-html-template&amp;amp;reason=why%20you%20want%20.no-js&quot;&gt;let me know why&lt;/a&gt;, would you? You can do it by adding &lt;code&gt;class=&quot;no-js&quot;&lt;/code&gt; to &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; and adding these lines within the &lt;code&gt;head&lt;/code&gt;:&lt;/p&gt;&#10;&#10;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;script&amp;gt;&#10;  document.documentElement.classList.remove(&quot;no-js&quot;);&#10;&amp;lt;/script&amp;gt;&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&#10;&lt;p&gt;&lt;a href=&quot;#fnref:no-js&quot; class=&quot;footnote-backref&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&amp;#xFE0E;&lt;/a&gt;&lt;/p&gt;&#10;&lt;/li&gt;&#10;&#10;&lt;li id=&quot;fn:x-ua&quot; role=&quot;doc-endnote&quot;&gt;&#10;&lt;p&gt;&lt;a href=&quot;/x-ua-compatible-rejoicing&quot; title=&quot;2008 piece chronicling the Microsoft-generated drama about this tag&quot;&gt;Previously on AlanHogan.com&lt;/a&gt;&amp;#160;&lt;a href=&quot;#fnref:x-ua&quot; class=&quot;footnote-backref&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&amp;#xFE0E;&lt;/a&gt;&lt;/p&gt;&#10;&lt;/li&gt;&#10;&#10;&lt;/ol&gt;&#10;&lt;/div&gt;&#10;</description>
   <guid>https://alanhogan.com/code/modern-html-template</guid>
   <link>https://alanhogan.com/code/modern-html-template</link>
   <category/>
   <title>A Modern HTML Template (2022)</title>
   <pubDate>Thu, 08 Dec 2022 10:48:01 -0800</pubDate>
  </item>
  <item>
   <description>&#10;&#10;&lt;p&gt;Now that we can rely on browsers to support CSS variables, we can define and use color themes by simply defining role-based color name variables. (For example, that is what powers this &lt;a href=&quot;https://codepen.io/alanhogan/pen/OJvNPpL?editors=0111&quot;&gt;dark mode demo&lt;/a&gt;, although the naming scheme here isn&apos;t used.)&lt;/p&gt;&#10;&#10;&lt;p&gt;My humble suggestion is to use the following conventions. They attempt to maximize terseness, consistency, and predictability. &lt;abbr title=&quot;your mileage may vary&quot;&gt;YMMV&lt;/abbr&gt;&lt;/p&gt;&#10;&#10;&lt;table class=&quot;text formLayout&quot;&gt;&#10;&lt;thead&gt;&#10;  &lt;tr&gt;&#10;    &lt;th&gt;Abbreviation&lt;/th&gt;&#10;    &lt;th&gt;Meaning&lt;/th&gt;&#10;    &lt;th&gt;Example&lt;/th&gt;&#10;  &lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;  &lt;tr&gt;&#10;    &lt;td&gt;&lt;code&gt;txt&lt;/code&gt;&lt;/td&gt;&#10;    &lt;td&gt;text color (&lt;code&gt;color&lt;/code&gt; in CSS)&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;--btn-txt&lt;/code&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;td&gt;&lt;code&gt;bg&lt;/code&gt;&lt;/td&gt;&#10;    &lt;td&gt;background color&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;--inp-bg&lt;/code&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;td&gt;&lt;code&gt;bdr&lt;/code&gt;&lt;/td&gt;&#10;    &lt;td&gt;border color&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;--inp-fcs-bdr&lt;/code&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;td&gt;&lt;code&gt;rds&lt;/code&gt;&lt;/td&gt;&#10;    &lt;td&gt;border radius&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;--inp-rds&lt;/code&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;td&gt;&lt;code&gt;hvr&lt;/td&gt;&#10;    &lt;td&gt;:hover&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;--btn-hvr-txt&lt;/code&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;td&gt;&lt;code&gt;fcs&lt;/td&gt;&#10;    &lt;td&gt;:focus or :focus-visible&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;--inp-fcs-bdr&lt;/code&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;td&gt;&lt;code&gt;actv&lt;/td&gt;&#10;    &lt;td&gt;:active&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;--btn-actv-txt&lt;/code&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;td&gt;&lt;code&gt;err&lt;/td&gt;&#10;    &lt;td&gt;error state&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;--inp-err-hvr-bdr&lt;/code&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;td&gt;&lt;code&gt;inp&lt;/td&gt;&#10;    &lt;td&gt;(text) input&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;--inp-hvr-bg&lt;/code&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;td&gt;&lt;code&gt;btn&lt;/td&gt;&#10;    &lt;td&gt;button&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;--btn-actv-bg&lt;/code&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&#10;&lt;p&gt;I also suggest consistently naming variables in the following order:&lt;/p&gt;&#10;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;p&gt;Specific module targeted, if applicable (&lt;code&gt;inp&lt;/code&gt;, &lt;code&gt;btn&lt;/code&gt;), or skip this for a global default (page background color is just &lt;code&gt;--bg&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Variant of the module being targeted (small, secondary, dangerous), if applicable&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Long-term state modifiers, if applicable (&lt;code&gt;err&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Short-term state modifiers, often tied to CSS pseudoclasses, if any (&lt;code&gt;hvr&lt;/code&gt;, &lt;code&gt;fcs&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Property being set (&lt;code&gt;txt&lt;/code&gt;, &lt;code&gt;bdr&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&#10;&lt;p&gt;This ordering is demonstrated in every example in the table above.&lt;/p&gt;&#10;&#10;&lt;h3&gt;History&lt;/h3&gt;&#10;&#10;&lt;p&gt;Shortly after publication, &lt;code&gt;bg-clr&lt;/code&gt;, &lt;code&gt;txt-clr&lt;/code&gt;, &lt;code&gt;bdr-clr&lt;/code&gt;, and &lt;code&gt;bdr-rds&lt;/code&gt; were simplified to &lt;code&gt;bg&lt;/code&gt;, &lt;code&gt;txt&lt;/code&gt;, &lt;code&gt;bdr&lt;/code&gt;, and &lt;code&gt;rds&lt;/code&gt;, given the color-focused nature of these variables overall and the redundancy of the &lt;code&gt;clr&lt;/code&gt; portion. Yes, a border can include more than color, but need that be captured in a variable? Not really for theming, right? If you do need to capture an entire &lt;code&gt;background&lt;/code&gt; or &lt;code&gt;border&lt;/code&gt; value in a variable, you can simply use the non-abbreviated spelling.&lt;/p&gt;&#10;&#10;&lt;h3&gt;Feedback&lt;/h3&gt;&#10;&#10;&lt;p&gt;Your thoughts are welcome! Was this useful? Is there something you would change? Use my contact form.&lt;/p&gt;&#10;&#10;&lt;h3&gt;Share&lt;/h3&gt;&#10;&#10;&lt;p&gt;Try introducing this to your teammates or sharing it with someone else who works with CSS!&lt;/p&gt;&#10;</description>
   <guid>https://alanhogan.com/code/css/color-variable-names</guid>
   <link>https://alanhogan.com/code/css/color-variable-names</link>
   <category/>
   <title>Abbreviations in Color Variable Names</title>
   <pubDate>Thu, 17 Nov 2022 10:51:08 -0800</pubDate>
  </item>
  <item>
   <description>&#10;&#10;&lt;p&gt;&lt;a href=&quot;/bookmarklets&quot;&gt;Bookmarklets&lt;/a&gt;, as I say on my main bookmarklet page, “are scripts that affect the current page you are viewing” and are saved in your browser as if they were bookmarks — although bookmarklets don’t take you to another page.&lt;/p&gt;&#10;&#10;&lt;p&gt;I published my &lt;a href=&quot;/bookmarklets&quot;&gt;bookmarklets collection&lt;/a&gt; back in 2009, and have added and updated them over the years. Some are quite useful; some are rather niche. Regardless, the collection has &lt;strong&gt;grown considerably&lt;/strong&gt; so I just wanted to publish a quick note calling attention to them.&lt;/p&gt;&#10;&#10;&lt;p&gt;&lt;a href=&quot;/bookmarklets&quot;&gt;Take a look.&lt;/a&gt; Newer bookmarklets are at the bottom. The source code for all of them &lt;a href=&quot;https://github.com/alanhogan/bookmarklets&quot; title=&quot;Bookmarklets source code&quot;&gt;is on GitHub&lt;/a&gt;.&lt;/p&gt;&#10;</description>
   <guid>https://alanhogan.com/conversations/bookmarklets-2022</guid>
   <link>https://alanhogan.com/conversations/bookmarklets-2022</link>
   <category/>
   <title>New Bookmarklets Available</title>
   <pubDate>Fri, 27 May 2022 16:56:28 -0700</pubDate>
  </item>
  <item>
   <description>&#10;&#10;&lt;p&gt;I just spent a little too long chasing down the answer to this question: When using an element’s JavaScript styles interface, the &lt;a href=&quot;http://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style&quot;&gt;&lt;code&gt;.style&lt;/code&gt; property&lt;/a&gt;, &lt;strong&gt;should vendor-prefixed property names start with a capital letter or not?&lt;/strong&gt; E.g., is it &lt;code&gt;button.style.webkitFilter&lt;/code&gt; or &lt;code&gt;button.style.WebkitFilter&lt;/code&gt;?&lt;/p&gt;&#10;&#10;&lt;h2&gt;The Short Answer&lt;/h2&gt;&#10;&#10;&lt;p&gt;&lt;strong&gt;Capitalize them.&lt;/strong&gt;&lt;sup id=&quot;fnref:ms&quot;&gt;&lt;a href=&quot;#fn:ms&quot; class=&quot;footnote-ref&quot; role=&quot;doc-noteref&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#10;&#10;&lt;p&gt;However, if the prefix is &lt;code&gt;Webkit&lt;/code&gt;, case does not matter.&lt;/p&gt;&#10;&#10;&lt;p&gt;Case matters for &lt;code&gt;Moz&lt;/code&gt;.&lt;/p&gt;&#10;&#10;&lt;p&gt;(No other vendor prefix besides these two really matters anymore.)&lt;/p&gt;&#10;&#10;&lt;h2&gt;The Long Answer&lt;/h2&gt;&#10;&#10;&lt;p&gt;Here is more information for the curious. Note that I expect the reader to be familiar with the general history of the major web browsers and their rendering engines.&lt;/p&gt;&#10;&#10;&lt;p&gt;At some point, it seems that the thinking (which I would tend to share) is that they should start with a capital letter.&lt;/p&gt;&#10;&#10;&lt;p&gt;You can find &lt;a href=&quot;https://www.developerdrive.com/coding-vendor-prefixes-with-javascript/&quot;&gt;old blog posts&lt;/a&gt; and &lt;a href=&quot;https://stackoverflow.com/a/32547147&quot;&gt;StackOverflow answers&lt;/a&gt; that carefully recommend prefixes (when needed) that follow the table below:&lt;/p&gt;&#10;&#10;&lt;table class=&quot;text formLayout&quot;&gt;&#10;&lt;thead&gt;&#10;  &lt;tr&gt;&#10;    &lt;th&gt;Vendor prefix&lt;/th&gt;&#10;    &lt;th&gt;CSS&lt;/th&gt;&#10;    &lt;th&gt;JS&lt;/th&gt;&#10;  &lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;  &lt;tr&gt;&#10;    &lt;th&gt;Microsoft&lt;/th&gt;&#10;    &lt;td&gt;&lt;code&gt;-ms-&lt;/code&gt;&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;ms&lt;/code&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;th&gt;Mozilla&lt;/th&gt;&#10;    &lt;td&gt;&lt;code&gt;-moz-&lt;/code&gt;&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;Moz&lt;/code&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;th&gt;Opera&lt;/th&gt;&#10;    &lt;td&gt;&lt;code&gt;-o-&lt;/code&gt;&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;O&lt;/code&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;th&gt;Webkit&lt;/th&gt;&#10;    &lt;td&gt;&lt;code&gt;-webkit-&lt;/code&gt;&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;Webkit&lt;/code&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&#10;&lt;p&gt;And, to a large degree, this was and is correct.&lt;/p&gt;&#10;&#10;&lt;p&gt;However, things have changed.&lt;/p&gt;&#10;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;p&gt;Mozilla and &lt;a href=&quot;https://dev.opera.com/articles/opera-mobile-emulator-webkit-prefix-support/&quot;&gt;Opera announced&lt;/a&gt;, all the way back in 2012, that they were going to start supporting some Webkit-prefixed properties.&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Non-Webkit browsers&lt;sup id=&quot;fnref:blink&quot;&gt;&lt;a href=&quot;#fn:blink&quot; class=&quot;footnote-ref&quot; role=&quot;doc-noteref&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; realized that a lot of web developers were only using Webkit prefixes even when they introduced their own prefixes. In 2016, for example, &lt;a href=&quot;https://hacks.mozilla.org/2016/09/firefox-49-fixes-sites-designed-with-webkit-in-mind-and-more/&quot;&gt;Mozilla announced&lt;/a&gt; they had released a version of Firefox that added support for a bunch of Webkit-prefixed properties.&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Generally speaking there’s been a big recognition that vendor prefixes in general should be minimized and the unprefixed version should be supported as soon as there’s a consensus around the syntax.&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;A lot of the non-Webkit browsers are now… Webkit browsers. Microsoft Edge is now a Chromium browser, not Trident. Opera’s full browser is now Chromium browser.&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;At some point — right away? After a year? I have no idea — browsers began treating &lt;code&gt;style.WebkitX&lt;/code&gt; and &lt;code&gt;style.webkitX&lt;/code&gt; as synonyms.&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Last but not least, Apple seems to have deleted a lot of old Safari documentation from its website, leaving me unable to find a definitive source from the company that &lt;em&gt;invented&lt;/em&gt; the &lt;code&gt;-webkit-&lt;/code&gt; prefix!&lt;/p&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&#10;&lt;p&gt;All of this leads us to a point where, in virtually any browser, you if you are going to set a vendor-prefixed CSS property using JavaScript, it’s going to respond to both &lt;code&gt;webkit&lt;/code&gt; and &lt;code&gt;Webkit&lt;/code&gt; prefixes.&lt;/p&gt;&#10;&#10;&lt;p&gt;Yes. Even in Firefox.&lt;/p&gt;&#10;&#10;&lt;p&gt;For example, in Firefox, you can run the following lines of JavaScript; the result is commented:&lt;/p&gt;&#10;&#10;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;var button = document.querySelector(&quot;button&quot;);&#10;button.WebkitFilter = &quot;blur(1px)&quot;; // It blurs it a little&#10;button.webkitFilter = &quot;blur(2px)&quot;; // It blurs it more&#10;button.WebkitFilter = &quot;blur(3px)&quot;; // It blurs it even more&#10;button.filter = &quot;blur(4px)&quot;; // It blurs it even more&#10;button.WebkitFilter = &quot;blur(0)&quot;; // No more blur!&#10;button.MozFilter = &quot;blur(1px)&quot;; // No effect!&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&#10;&lt;p&gt;Here we have three supported synonyms for the same property. Changing one changes them all. Notably there is not even support for the Moz prefix, presumably because Firefox never supported &lt;code&gt;filter&lt;/code&gt; until it was far along enough in standardization to be supported unprefixed, and virtually nobody authored CSS with a Mozilla-specific prefix but not the unprefixed property.&lt;/p&gt;&#10;&#10;&lt;p&gt;Now there &lt;em&gt;are&lt;/em&gt; still CSS properties that are &lt;em&gt;only&lt;/em&gt; supported in Firefox/Gecko &lt;em&gt;with&lt;/em&gt; a vendor prefix and &lt;em&gt;only&lt;/em&gt; with the &lt;code&gt;-moz-&lt;/code&gt; prefix. &lt;strong&gt;In JavaScript, you must use the &lt;code&gt;Moz&lt;/code&gt; prefix.&lt;/strong&gt; Example, as of Firefox 99 (April 2022):&lt;/p&gt;&#10;&#10;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;btn.style.MozBorderEnd = &quot;2px solid yellow&quot;; // Right border is yellow&#10;btn.style.mozBorderEnd = &quot;1px solid blue&quot;; // No effect&#10;btn.style.borderEnd = &quot;1px solid orange&quot;; // No effect&#10;btn.style.WebkitBorderEnd = &quot;1px solid red&quot;; // No effect&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&#10;&lt;p&gt;So in summary, this is where we stand today:&lt;/p&gt;&#10;&#10;&lt;table class=&quot;text formLayout&quot;&gt;&#10;&lt;thead&gt;&#10;  &lt;tr&gt;&#10;    &lt;th&gt;Vendor prefix&lt;/th&gt;&#10;    &lt;th&gt;CSS&lt;/th&gt;&#10;    &lt;th&gt;JS&lt;/th&gt;&#10;  &lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;  &lt;tr&gt;&#10;    &lt;th&gt;Microsoft&lt;/th&gt;&#10;    &lt;td colspan=2&gt;&lt;i&gt;Defunct; now Chromium (Webkit)&lt;/i&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;th&gt;Mozilla&lt;/th&gt;&#10;    &lt;td&gt;&lt;code&gt;-moz-&lt;/code&gt;&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;Moz&lt;/code&gt; (case matters)&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;th&gt;Opera&lt;/th&gt;&#10;    &lt;td colspan=2&gt;&lt;i&gt;Defunct; now Chromium (Webkit)&lt;/i&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;th&gt;Webkit&lt;/th&gt;&#10;    &lt;td&gt;&lt;code&gt;-webkit-&lt;/code&gt;&lt;/td&gt;&#10;    &lt;td&gt;&lt;code&gt;Webkit&lt;/code&gt;, but &lt;code&gt;webkit&lt;/code&gt; works too, even in Firefox&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&#10;&lt;p&gt;Please &lt;a href=&quot;/contact?reason=vendor%20prefixes%20in%20JavaScript&quot;&gt;let me know&lt;/a&gt;&#10;if I’ve overlooked something important, or if you’ve arrived from the future and the sitation has&#10;changed further from when I wrote this in 2022. Thanks!&lt;/p&gt;&#10;&#10;&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;&#10;&lt;div class=&quot;hr&quot;&gt;&lt;hr /&gt;&lt;/div&gt;&#10;&lt;ol&gt;&#10;&#10;&lt;li id=&quot;fn:ms&quot; role=&quot;doc-endnote&quot;&gt;&#10;&lt;p&gt;The exception was Microsoft (see table). Note the past tense in that sentence. No current Microsoft browser uses Microsoft vendor prefixes, so this is only relevant if you are, for whatever reason, supporting ancient, specific, rarely used versions of Microsoft browsers.&amp;#160;&lt;a href=&quot;#fnref:ms&quot; class=&quot;footnote-backref&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&amp;#xFE0E;&lt;/a&gt;&lt;/p&gt;&#10;&lt;/li&gt;&#10;&#10;&lt;li id=&quot;fn:blink&quot; role=&quot;doc-endnote&quot;&gt;&#10;&lt;p&gt;Blink is the Webkit fork at the heart of Chromium browsers. Technically it is not Webkit anymore, but it still uses the same &lt;code&gt;-webkit-&lt;/code&gt; prefix that Webkit does, so for our purposes Blink counts as Webkit. When I say “non-Webkit” browsers, I mean browsers that did not share a history with Webkit.&amp;#160;&lt;a href=&quot;#fnref:blink&quot; class=&quot;footnote-backref&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&amp;#xFE0E;&lt;/a&gt;&lt;/p&gt;&#10;&lt;/li&gt;&#10;&#10;&lt;/ol&gt;&#10;&lt;/div&gt;&#10;</description>
   <guid>https://alanhogan.com/code/vendor-prefixed-css-property-names-in-javascript</guid>
   <link>https://alanhogan.com/code/vendor-prefixed-css-property-names-in-javascript</link>
   <category/>
   <title>Capitalization of Vendor-Prefixed CSS Property Names in JavaScript</title>
   <pubDate>Mon, 02 May 2022 11:45:12 -0700</pubDate>
  </item>
  <item>
   <description>&#10;&#10;&lt;!-- Markdown formatting note:&#10;     This file is authored against PHP Markdown Extra,&#10;     not GitHub-Flavored Markdown. --&gt;&#10;&#10;&lt;div class=toc&gt;&#10;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a href=&quot;#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href=&quot;#base&quot;&gt;Base Styles&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href=&quot;#modules&quot;&gt;Modules&lt;/a&gt;&#10;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a href=&quot;#parts&quot;&gt;Parts&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href=&quot;#variants&quot;&gt;Variants&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href=&quot;#layout-modules&quot;&gt;Layout modules&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href=&quot;#content-oriented-modules&quot;&gt;Content-oriented modules&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href=&quot;#dont-dos&quot;&gt;Don’t-Do’s&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href=&quot;#non-styling&quot;&gt;Non-Styling Class Names&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href=&quot;#thanks&quot;&gt;Thanks&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href=&quot;#license&quot;&gt;License&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10;&lt;/div&gt;&#10;&#10;&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;&#10;&#10;&lt;p&gt;In this document I hope to define a CSS methodology using a small set of unambigous rules. This methodology has these aims:&lt;/p&gt;&#10;&#10;&lt;ul&gt;&#10;&lt;li&gt;extreme maintainability&#10;&#10;&lt;ul&gt;&#10;&lt;li&gt;high readability&lt;/li&gt;&#10;&lt;li&gt;guided writability&lt;/li&gt;&#10;&lt;li&gt;low barrier to adding collaborators&lt;/li&gt;&#10;&lt;/ul&gt;&lt;/li&gt;&#10;&lt;li&gt;broad compatibility&#10;&#10;&lt;ul&gt;&#10;&lt;li&gt;with mobile-first patterns&lt;/li&gt;&#10;&lt;li&gt;with responsive designs&lt;/li&gt;&#10;&lt;li&gt;with pre-processors and build tools&lt;/li&gt;&#10;&lt;li&gt;with modern web standards&lt;/li&gt;&#10;&lt;li&gt;with backwards compatibility&lt;/li&gt;&#10;&lt;li&gt;with legacy codebases as well as green-field projects&lt;/li&gt;&#10;&lt;/ul&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10;&lt;p&gt;The first major goal is maintainability — important whether your project involves one person or ten. For any sort of styling you want to do, under ZASM, there should be one clear, “right’ way to write the selector for it; this makes the CSS easy to author. Class names written under ZASM are designed to be instantly identifiable as belonging to one of the categories defined in the methodology. This provides readability and helps communicate author intention. By keeping the methodology small and tightly defined, new collaborators won’t face a large uphill climb to productivity — at least, assuming they have already learned enough CSS, an admittedly complicated pre-requisite!&lt;/p&gt;&#10;&#10;&lt;p&gt;The second top-level goal is broad compatibility. That means that ZASM should be able to be the one methodology you can reach for in all your projects, both shared and personal. To do this, we carefully establish rules that are strict enough to provide some built in ‘defenses’ as well as flexible enough to adapt to any specific project.&lt;/p&gt;&#10;&#10;&lt;h3 id=&quot;base&quot;&gt;Base Styles&lt;/h3&gt;&#10;&#10;&lt;p&gt;In as little CSS as possible, and by writing selectors without any class names at all (&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes&quot;&gt;pseudo-classes&lt;/a&gt; are OK), set base element styles including your preferred font stack.&lt;/p&gt;&#10;&#10;&lt;p&gt;It is &lt;em&gt;recommended&lt;/em&gt; to set a good base line height. It is up to you whether that is a ratio (1.2, 1.6, etc) or an absolute measurement (24px).&lt;/p&gt;&#10;&#10;&lt;p&gt;If desired, style links and form controls (input elements). This is not necessary because you can instead ensure every link and control is styled by a module; it is up to your preference.&lt;/p&gt;&#10;&#10;&lt;p&gt;In your base styles, fix dumb browser default styling issues. Optionally set sane defaults for &lt;code&gt;box-sizing&lt;/code&gt; and &lt;code&gt;overflow-wrap&lt;/code&gt; on everything.&lt;/p&gt;&#10;&#10;&lt;p&gt;&lt;em&gt;If&lt;/em&gt; using &lt;a href=&quot;http://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties&quot;&gt;CSS variables&lt;/a&gt;, set globally applicable variables, or even all variables, here. Your color palette is the most obvious thing to define here. Optionally modify these using media queries and/or classes applied to &lt;code&gt;html&lt;/code&gt; (aka &lt;code&gt;:root&lt;/code&gt;). It is &lt;em&gt;recommended&lt;/em&gt; that any such class names start with &lt;code&gt;theme-&lt;/code&gt;: &lt;code&gt;theme-dark&lt;/code&gt;.&lt;/p&gt;&#10;&#10;&lt;p&gt;Notably, it is &lt;em&gt;perfectly okay&lt;/em&gt; under ZASM if you avoid CSS variables altogether. You do not need to support multiple themes at all. Or you can ship a hundred different themes all compiled as different &lt;code&gt;.css&lt;/code&gt; files using Sass. It doesn’t affect the rest of the methodology at all.&lt;/p&gt;&#10;&#10;&lt;p&gt;ZASM recommends writing &lt;em&gt;fewer&lt;/em&gt; base styles and &lt;em&gt;more&lt;/em&gt; modules.&lt;/p&gt;&#10;&#10;&lt;pre&gt;&lt;code class=&quot;css&quot;&gt;:root {&#10;  --page-bg-color: #def;&#10;  --text-color: #222;&#10;}&#10;&#10;/* Automatically use dark mode if the user prefers it */&#10;@media (prefers-color-scheme: dark) {&#10;  :root {&#10;    --page-bg-color: #123;&#10;    --text-color: #eee;&#10;  }&#10;}&#10;&#10;/* Note, redundant variables to automatic dark mode for when&#10; * dark mode is manually applied to &amp;lt;html&amp;gt; by class */&#10;:root.theme-dark {&#10;  --page-bg-color: #123;&#10;  --text-color: #eee;&#10;}&#10;&#10;:root.theme-halloween {&#10;  --page-bg-color: black;&#10;  --text-color: orangered;&#10;}&#10;&#10;:root, body, input, textarea, button {&#10;  font: 16px/1.4 &quot;Brand Font&quot;, system-ui, sans-serif;&#10;}  &#10;&#10;* {&#10;  box-sizing: border-box;&#10;  overflow-wrap: break-word;&#10;}&#10;&#10;:link { color: blue; }&#10;:visited { color: rebeccapurple; }&#10;:link:active, :visited:active { color: var(--text-color);&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&#10;&lt;h3 id=&quot;modules&quot;&gt;Modules&lt;/h3&gt;&#10;&#10;&lt;p&gt;Modules are things — just about anything. They are composable and can be placed within each other (when it makes sense). They can be very complicated. They can have parts and variants.&lt;/p&gt;&#10;&#10;&lt;p&gt;The naming rule for a module&apos;s class name (or &quot;base class&quot;) is: &lt;strong&gt;any three-letter class name.&lt;/strong&gt;&lt;/p&gt;&#10;&#10;&lt;p&gt;However, you should add a prefix such as &lt;code&gt;m-&lt;/code&gt; for all module names when introducing ZASM to codebases with existing HTML that uses unprefixed class names: &lt;code&gt;.m-mdl&lt;/code&gt; instead of &lt;code&gt;.mdl&lt;/code&gt; and &lt;code&gt;.m-mdl__header&lt;/code&gt; instead of &lt;code&gt;.mdl__header&lt;/code&gt;.&lt;/p&gt;&#10;&#10;&lt;p&gt;If your organization is adopting ZASM, there may be cases where you may not desire or be able to follow the three-letter naming rule. That is an acceptable deviation; just remember to make your module naming rule clear enough that it is readily understood to be a module when it is seen in use. And try to avoid long module names as it makes naming parts and variants very clunky.&lt;/p&gt;&#10;&#10;&lt;pre&gt;&lt;code class=&quot;css&quot;&gt;.mdl { /* Base class for a &quot;Modal&quot; module */ }&#10;.mdl__header { /* A part called &quot;header&quot; within an &quot;mdl&quot; modal */ }&#10;.mdl--alert { /* Variant of &quot;mdl&quot; fulfilling &quot;alert&quot; purpose */ }&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&#10;&lt;h4 id=&quot;parts&quot;&gt;Parts&lt;/h4&gt;&#10;&#10;&lt;p&gt;In ZASM, a &quot;part&quot; is what &lt;a href=&quot;http://getbem.com/&quot; title=&quot;Block, Element, Modifier&quot;&gt;BEM&lt;/a&gt; calls an &quot;element&quot;: It&apos;s something that belongs within its module. I call them &quot;parts&quot; because &quot;element&quot; already has a different meaning in CSS and HTML.&lt;/p&gt;&#10;&#10;&lt;p&gt;Parts are always named like this: &lt;strong&gt;base module name + two underscores + kebab-cased part name.&lt;/strong&gt;&lt;/p&gt;&#10;&#10;&lt;p&gt;Example: Module &lt;code&gt;foo&lt;/code&gt; could have parts &lt;code&gt;foo__intro&lt;/code&gt; and &lt;code&gt;foo__author-signature&lt;/code&gt;.&lt;/p&gt;&#10;&#10;&lt;p&gt;A module can have unlimited parts. Parts can be within other parts — for example you might have a close button &lt;code&gt;.mdl__close&lt;/code&gt; within the modal header &lt;code&gt;.mdl__header&lt;/code&gt;. Whether the parts of the module are required or optional is up to you.&lt;/p&gt;&#10;&#10;&lt;h4 id=&quot;variants&quot;&gt;Variants&lt;/h4&gt;&#10;&#10;&lt;p&gt;&quot;Variants&quot; are variations of a module. They are what &lt;a href=&quot;http://getbem.com/&quot; title=&quot;Block, Element, Modifier&quot;&gt;BEM&lt;/a&gt; calls &quot;modifiers&quot; and what &lt;a href=&quot;http://smacss.com/&quot; title=&quot;Scalable and Modular Approach to CSS&quot;&gt;SMACSS&lt;/a&gt; calls &quot;subclassed modules.&quot;&lt;/p&gt;&#10;&#10;&lt;p&gt;The class name for a variant is: &lt;strong&gt;base module name + two hyphens + kebab-cased variant name.&lt;/strong&gt;&lt;/p&gt;&#10;&#10;&lt;p&gt;Example: Module &lt;code&gt;foo&lt;/code&gt; could have a variant &lt;code&gt;in-progress&lt;/code&gt;, so the class name would be &lt;code&gt;foo--in-progress&lt;/code&gt; (assuming you are not prefixing module names with &lt;code&gt;m-&lt;/code&gt;).&lt;/p&gt;&#10;&#10;&lt;p&gt;Multiple variants can be applied to a module simultaneously, if it makes sense. You can style these intersections when needed:&lt;/p&gt;&#10;&#10;&lt;pre&gt;&lt;code class=&quot;css&quot;&gt;.msg { /* message module */ }&#10;.msg--loading { color: gray; }&#10;.msg--mine { color: blue; }&#10;.msg--loading.msg--mine { color: slategray; }&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&#10;&lt;p&gt;Variants can, but do not necessarily, represent states. They can also transform the module as desired for placement elsewhere. Or they can simply change the appearance to grab more or less visual attention. The classic example is &lt;code&gt;btn&lt;/code&gt;, a normal button, and &lt;code&gt;btn--primary&lt;/code&gt;, a &apos;primary&apos; button with strong contrast to the surrounding area due its purpose as the primary action on the screen.&lt;/p&gt;&#10;&#10;&lt;p&gt;&lt;em&gt;Do&lt;/em&gt; apply multiple variant classes to an element as appropriate:&lt;/p&gt;&#10;&#10;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;input&#10;  type=&quot;submit&quot;&#10;  class=&quot;btn btn--primary btn--disabled&quot;&#10;  value=&quot;Submit&quot; /&amp;gt;&#10;&#10;&amp;lt;section role=&quot;alert&quot; class=&quot;mdl mdl--alert mdl--open&quot;&amp;gt;&#10;  &amp;lt;header class=&quot;mdl__header&quot;&amp;gt; ... &amp;lt;/header&amp;gt;&#10;  &amp;lt;div class=&quot;mdl__body&quot;&amp;gt; ... &amp;lt;/div&amp;gt;&#10;&amp;lt;/section&amp;gt;&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&#10;&lt;p&gt;Do &lt;em&gt;not&lt;/em&gt; add the base module class to selectors unnecessarily: Style &lt;code&gt;.btn--primary&lt;/code&gt;, not &lt;code&gt;.btn.btn--primary&lt;/code&gt;.&lt;/p&gt;&#10;&#10;&lt;h4 id=&quot;layout-modules&quot;&gt;Layout Modules&lt;/h4&gt;&#10;&#10;&lt;p&gt;One valid use of a module is to create one or more containers for laying out content (= other modules).&lt;/p&gt;&#10;&#10;&lt;p&gt;There is no special naming designation for layout modules. In fact, a module can handle its own layout as well as doing other things. You do not need to decide whether a module is a layout module or a regular module; it can be both. Or you can separate the concerns if that increases your re-usability.&lt;/p&gt;&#10;&#10;&lt;p&gt;You can use the wildcard direct child selector (&lt;code&gt;&amp;gt; *&lt;/code&gt;) in layout modules, but it is even better to swap this for named parts.&lt;/p&gt;&#10;&#10;&lt;pre&gt;&lt;code class=&quot;css&quot;&gt;.xyz { /* module that lays out its children */ }&#10;.xyz &amp;gt; * { flex: 1; } /* Acceptable selector */&#10;.xyz__child { flex: 1; } /* Even better selector! */&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&#10;&lt;p&gt;ZASM strongly supports responsive design, which is what we call it when the same page, with the same markup, effortly resizes and rearranges itself to fit screens of any size and shape. ZASM avoids simple &quot;layout&quot; classes that always do the same thing (e.g., apply two columns). Instead we empower modules to lay out their parts however they want. That will often mean using &lt;code&gt;@media&lt;/code&gt; queries to switch to a compact, single-column layout on narrow screens. Or it can mean using flexbox-based responsive techniques. Or liberal use of &lt;code&gt;calc()&lt;/code&gt;. Or all of the above. It&apos;s up to you!&lt;/p&gt;&#10;&#10;&lt;p&gt;Caution: &lt;em&gt;Never&lt;/em&gt; write CSS with descendant and element name seletors like this for a layout module:&lt;/p&gt;&#10;&#10;&lt;pre class=&quot;code--bad-example&quot;&gt;&lt;code class=&quot;css&quot;&gt;.xyz div { float: left; }&lt;/code&gt;&lt;/pre&gt;&#10;&#10;&lt;p&gt;That&apos;s a great way to mess up just about every module nested within &lt;code&gt;.xyz&lt;/code&gt;, and it’s a completely avoidable violation of ZASM rules.&lt;/p&gt;&#10;&#10;&lt;h4 id=&quot;content-oriented-modules&quot;&gt;Content-Oriented Modules&lt;/h4&gt;&#10;&#10;&lt;p&gt;Sometimes you can&apos;t realistically apply class names to &lt;em&gt;everything.&lt;/em&gt; For instance, the contents of an article probably include lots of headings and paragraphs that don&apos;t have class names on them. Or maybe you need to display content generated by a third-party system or a certain software library that has its own ideas about markup.&lt;/p&gt;&#10;&#10;&lt;p&gt;This is not a problem in ZASM. After all, we have taken care to keep our base styles minimal, and most of our styles only trigger off the specific class names we have invented usng ZASM naming rules.&lt;/p&gt;&#10;&#10;&lt;p&gt;Cases where you need to bulk-style content that may be using no class names or non-ZASM class names call for &lt;em&gt;content-oriented modules.&lt;/em&gt;&lt;/p&gt;&#10;&#10;&lt;p&gt;These are just a special case of module that is focused on styling its children and descendants.&lt;/p&gt;&#10;&#10;&lt;p&gt;Imagine a &quot;content&quot; module named &lt;code&gt;cnt&lt;/code&gt;.&lt;/p&gt;&#10;&#10;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;article class=&quot;cnt&quot;&amp;gt;&#10;  &amp;lt;h1&amp;gt;Why My Dog Really Did Eat My Homework&amp;lt;/h1&amp;gt;&#10;  &amp;lt;p&amp;gt;Toby is not a bad dog. In fact, ... &amp;lt;/p&amp;gt;&#10;&amp;lt;/article&amp;gt;&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&#10;&lt;pre&gt;&lt;code class=&quot;css&quot;&gt;.cnt h1 { /* ... */ }&#10;.cnt p { /* ... */ }&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&#10;&lt;p&gt;Notably content-oriented modules can easily be nested within other modules, but other modules cannot be nested within a content-oriented module without risking styles breaking.&lt;/p&gt;&#10;&#10;&lt;p&gt;For this reason, content-oriented modules should be relatively &lt;em&gt;few&lt;/em&gt;, lest you ruin the composability and predictability of your ZASM-based stylesheet.&lt;/p&gt;&#10;&#10;&lt;p&gt;By the same logic, you should strive to use the direct child selector (&lt;code&gt;&amp;gt;&lt;/code&gt;) whenever possible instead of the descendant selector (space), but this will often be impossible for a well-needed content-oriented module. For example, &lt;code&gt;.cnt &amp;gt; p&lt;/code&gt; will work on our example HTML, but it will probably break once a piece of content appears that contains a &lt;code&gt;p&lt;/code&gt; using a &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; tag!&lt;/p&gt;&#10;&#10;&lt;h3 id=&quot;utilities&quot;&gt;Utilities&lt;/h3&gt;&#10;&#10;&lt;p&gt;Utility classes should be defined &lt;em&gt;sparingly.&lt;/em&gt; You may not even need or write a single utility class in a well-organized ZASM project.&lt;/p&gt;&#10;&#10;&lt;p&gt;Name them with a &lt;code&gt;u-&lt;/code&gt; prefix and kebab-case (hyphenate) the rest.&lt;/p&gt;&#10;&#10;&lt;p&gt;Utility classes are standalone classes that achieve a narrow purpose. If you are tempted to make a &quot;variant&quot; or &quot;part&quot; of a utility, you should convert it to a module instead.&lt;/p&gt;&#10;&#10;&lt;pre&gt;&lt;code class=&quot;css&quot;&gt;.u-clear {&#10;  clear: both;&#10;}&#10;&#10;.u-small-caps {&#10;  font-variant: small-caps;&#10;}&#10;&#10;.u-tabular-nums {&#10;  font-variant-numeric: tabular-nums;&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&#10;&lt;h3 id=&quot;dont-dos&quot;&gt;Don’t-Do’s&lt;/h3&gt;&#10;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;p&gt;Never use ancestor or parent selectors to style a module differently based on where it appears. Create a variant instead.&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Do not invent &lt;em&gt;states&lt;/em&gt; (like &lt;code&gt;.is-current&lt;/code&gt;). Instead, invent a variant.&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Do not write &lt;em&gt;layout&lt;/em&gt; classes; instead, define a module that has a layout purpose.&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Do not use &lt;code&gt;!important&lt;/code&gt; (unless it is necessary due to some horrible legacy code you can&apos;t jettison).&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Do not write element-based selectors (except for the smallest number necessary in base styles). For example, do not style &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;article&lt;/code&gt;. Instead, invent a module and apply it. It is acceptable to use ancestor selectors to style elements within a content-oriented module: &lt;code&gt;.cnt p { margin 1.2em 0; }&lt;/code&gt; is a fine rule for styling paragraphs within your main content area &lt;code&gt;.cnt&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10;&lt;h3 id=&quot;non-styling&quot;&gt;Non-Styling Class Names&lt;/h3&gt;&#10;&#10;&lt;p&gt;When elements will be targeted via JavaScript (e.g. with &lt;code&gt;querySelector()&lt;/code&gt;), prefer a &lt;code&gt;js-&lt;/code&gt; prefix: &lt;code&gt;class=&quot;js-whatever&quot;&lt;/code&gt;.&lt;/p&gt;&#10;&#10;&lt;p&gt;For instrumententation of click tracking, use a consistent prefix such as &lt;code&gt;track-&lt;/code&gt;: &lt;code&gt;class=&quot;track-home-page-call-to-action&quot;&lt;/code&gt;.&lt;/p&gt;&#10;&#10;&lt;p&gt;For enabling automated QA testing, always use class names beginning with &lt;code&gt;qa-&lt;/code&gt;: &lt;code&gt;class=&quot;qa-home-page-call-to-action&quot;&lt;/code&gt;.&lt;/p&gt;&#10;&#10;&lt;p&gt;It is &lt;em&gt;recommended&lt;/em&gt; to apply as many non-styling class names to the same element as needed, even if that element also uses one or more ZASM class names for styling purposes.&lt;/p&gt;&#10;&#10;&lt;h3 id=&quot;cheat-sheet&quot;&gt;Cheat Sheet&lt;/h3&gt;&#10;&#10;&lt;p&gt;For quick reference, enjoy &lt;a href=&quot;https://alanhogan.com/code/css/zasm/cheat-sheet&quot;&gt;the ZASM cheat sheet&lt;/a&gt;.&lt;/p&gt;&#10;&#10;&lt;h3 id=&quot;thanks&quot;&gt;Thanks&lt;/h3&gt;&#10;&#10;&lt;p&gt;This methodology is hugely inspired by &lt;a href=&quot;http://smacss.com/&quot; title=&quot;Scalable and Modular Approach to CSS&quot;&gt;SMACSS&lt;/a&gt; and &lt;a href=&quot;http://getbem.com/&quot; title=&quot;Block, Element, Modifier&quot;&gt;BEM&lt;/a&gt;.&lt;/p&gt;&#10;&#10;&lt;p&gt;This document is &lt;a href=&quot;https://github.com/alanhogan/zasm/&quot;&gt;open source&lt;/a&gt;. Issues and pull requests are welcome.&lt;/p&gt;&#10;&#10;&lt;h3 id=&quot;license&quot;&gt;License&lt;/h3&gt;&#10;&#10;&lt;p xmlns:cc=&quot;http://creativecommons.org/ns#&quot; xmlns:dct=&quot;http://purl.org/dc/terms/&quot;&gt;&lt;a property=&quot;dct:title&quot; rel=&quot;cc:attributionURL&quot; href=&quot;https://alanhogan.com/code/css/zasm&quot;&gt;The Zero-Ambiguity Stylesheet Methodology (ZASM)&lt;/a&gt; by &lt;a rel=&quot;cc:attributionURL dct:creator&quot; property=&quot;cc:attributionName&quot; href=&quot;https://alanhogan.com/&quot;&gt;Alan J. Hogan&lt;/a&gt; is licensed under &lt;a href=&quot;http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1&quot; target=&quot;_blank&quot; rel=&quot;license noopener noreferrer&quot; style=&quot;display:inline-block;&quot;&gt;CC BY 4.0 &lt;img style=&quot;height:22px!important;margin-left:3px;vertical-align:text-bottom;&quot; src=&quot;https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1&quot;&gt;&lt;img style=&quot;height:22px!important;margin-left:3px;vertical-align:text-bottom;&quot; src=&quot;https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#10;</description>
   <guid>https://alanhogan.com/code/css/zasm</guid>
   <link>https://alanhogan.com/code/css/zasm</link>
   <category/>
   <title>ZASM: Zero-Ambiguity Stylesheet Methodology</title>
   <pubDate>Thu, 28 Apr 2022 00:45:18 -0700</pubDate>
  </item>
  <item>
   <description>&#10;&#10;&lt;p&gt;Many people, including programmers and project managers, use the word “deprecation” incorrectly. This can lead to confusion and even unexpected downtime, so let’s all try to use the same definition.&lt;/p&gt;&#10;&#10;&lt;h3&gt;What is deprecation?&lt;/h3&gt;&#10;&#10;&lt;p&gt;The stellar Oxford English Dictionary defines the verb “deprecate” this way:&lt;/p&gt;&#10;&#10;&lt;blockquote&gt;&#10;  &lt;ol&gt;&#10;  &lt;li&gt;express disapproval of: &lt;em&gt;what I deprecate is persistent indulgence.&lt;/em&gt;&#10;  &#10;  &lt;ul&gt;&#10;  &lt;li&gt;(&lt;strong&gt;be deprecated&lt;/strong&gt;) (chiefly of a software feature) be usable but regarded as obsolete and best avoided, typically due to having been superseded: &lt;em&gt;this feature is deprecated and will be removed in later versions&lt;/em&gt; | (as adjective &lt;strong&gt;deprecated&lt;/strong&gt;) : &lt;em&gt;avoid the deprecated &amp;lt;blink&amp;gt; element that causes text to flash on and off.&lt;/em&gt;&lt;/li&gt;&#10;  &lt;/ul&gt;&lt;/li&gt;&#10;  &lt;/ol&gt;&#10;&lt;/blockquote&gt;&#10;&#10;&lt;p&gt;&lt;em&gt;Deprecation&lt;/em&gt; is the moment, act, or expression of such disapproval, or as we mean it particularly in software, “the classification of a software feature as obsolete and best avoided” (again Oxford).&lt;/p&gt;&#10;&#10;&lt;h3&gt;What is depreciation?&lt;/h3&gt;&#10;&#10;&lt;p&gt;Sometimes deprecation and depreciation are confused (because they look nearly identical). The latter is more common in finance than technology, and it refers to the reduction in value of something over time.&lt;/p&gt;&#10;&#10;&lt;h3&gt;What isn’t deprecation?&lt;/h3&gt;&#10;&#10;&lt;p&gt;When a piece of software, a service, or a feature is actually taken offline, or reaches an end-of-life or end-of-support phase, this is variously called &lt;em&gt;sunsetting&lt;/em&gt; or &lt;em&gt;EOL,&lt;/em&gt; but it is definitely not deprecation. Deprecation should have come earlier (often months or years earlier), to warn customers and users of the impending EOL event.&lt;/p&gt;&#10;&#10;&lt;h3&gt;An example of doing it right&lt;/h3&gt;&#10;&#10;&lt;p&gt;In a &lt;a href=&quot;https://stitcher.io/blog/new-in-php-82#deprecate-dynamic-properties-rfc&quot;&gt;recent blog post&lt;/a&gt; by Brent at Stitcher, one deprecation is described like this:&lt;/p&gt;&#10;&#10;&lt;blockquote&gt;&#10;  &lt;p&gt;Dynamic properties are deprecated in PHP 8.2, and will throw an ErrorException in PHP 9.0.&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&#10;&lt;p&gt;This is a good example because it clearly separates the PHP version which marks the feature as best avoided from the future version in which the feature will no longer work at all.&lt;/p&gt;&#10;</description>
   <guid>https://alanhogan.com/conversations/deprecation</guid>
   <link>https://alanhogan.com/conversations/deprecation</link>
   <category/>
   <title>Using “Deprecation” Correctly</title>
   <pubDate>Mon, 25 Apr 2022 10:04:18 -0700</pubDate>
  </item>
  <item>
   <description>&lt;p&gt;&lt;a href=&quot;/about/site&quot; title=&quot;About AlanHogan.com, the website&quot;&gt;This website&lt;/a&gt; runs my own content management system. Previously I wrote about upgrading it from &lt;a href=&quot;/blip&quot; title=&quot;Blip: Upgrading AlanHogan.com from PHP 5.6 to PHP 7&quot;&gt;PHP 5.6 to PHP 7&lt;/a&gt;.&lt;/p&gt;&#10;&#10;&lt;p&gt;Now I have managed to upgrade it to PHP 8.1 as well.&lt;/p&gt;&#10;&#10;&lt;p&gt;How?&lt;/p&gt;&#10;&#10;&lt;p&gt;First, I upgraded my staging site to run PHP 8.1. It failed badly — but I checked the error logs. It became clear that language changes had resulted in code in some of the libraries I am using (open-source code) was no longer compatible.&lt;/p&gt;&#10;&#10;&lt;p&gt;One such library was &lt;code&gt;ADOdb_lite&lt;/code&gt;, an abandoned project. But that was not a big deal. &lt;code&gt;ADOdb_lite&lt;/code&gt; had the same API as the larger project &lt;code&gt;ADOdb&lt;/code&gt;, which, luck would have it, is still &lt;a href=&quot;https://adodb.org/&quot; title=&quot;ADOdb homepage&quot;&gt;maintained&lt;/a&gt; as I write this.&lt;/p&gt;&#10;&#10;&lt;p&gt;The other incompatibility was &lt;a href=&quot;https://michelf.ca/projects/php-markdown/&quot; title=&quot;PHP Markdown homepage&quot;&gt;PHP Markdown&lt;/a&gt;, which is also still maintained. Thus, all I had to do was replace my version with the latest.&lt;/p&gt;&#10;&#10;&lt;p&gt;And that was it. My site was 100% functional on PHP 8.1!&lt;/p&gt;&#10;&#10;&lt;p&gt;Well, at least, as far as I could tell. A later look at my error logs showed that I was using an obsolete function in part of the code path of my popular &lt;a href=&quot;/asu/assembler.php&quot;&gt;online MIPS assembler&lt;/a&gt; and the &lt;a href=&quot;/asu/simulator.php&quot;&gt;corresponding MIPS simulator&lt;/a&gt;. The functionality of the obsolete function isn&apos;t needed in newer versions of PHP, so the fix was simple. I just &lt;a href=&quot;https://github.com/alanhogan/miphps-mips-simulator/commit/d617cab5f4194ee264abaec077f0970bca5da382&quot;&gt;added a check&lt;/a&gt; to see if the function exists before calling it.&lt;/p&gt;&#10;&#10;&lt;p&gt;That was all I needed to do. However, my error logs were still showing warnings about undefined variables and undefined array keys. These did not indicate bugs or incompatibilities (at least not necessarily), but nevertheless I added a few &lt;code&gt;isset()&lt;/code&gt; calls, ensuring the variables and array keys I was accessing really did exist first. This, if nothing else, helped tidy up the error log, reducing noise.&lt;/p&gt;&#10;&#10;&lt;p&gt;I want to give a big shout-out to &lt;a href=&quot;https://michelf.ca/&quot; title=&quot;Michel Fortin’s homepage&quot;&gt;Michel Fortin&lt;/a&gt;, maintainer of &lt;a href=&quot;https://michelf.ca/projects/php-markdown/&quot; title=&quot;PHP Markdown homepage&quot;&gt;PHP Markdown&lt;/a&gt;, for being a great maintainer. Same to Damien Regad and Mark Newnham of &lt;a href=&quot;https://adodb.org/&quot; title=&quot;ADOdb homepage&quot;&gt;ADOdb&lt;/a&gt;, who took over from the similarly great John Lim. It&apos;s thanks to these open-source maintainers that I have been able to keep my aging website online over the years with minimal maintenance effort.&lt;/p&gt;&#10;</description>
   <guid>https://alanhogan.com/conversations/php/upgrading-to-php-8-1</guid>
   <link>https://alanhogan.com/conversations/php/upgrading-to-php-8-1</link>
   <category/>
   <title>Upgrading AlanHogan.com to PHP 8.1</title>
   <pubDate>Fri, 08 Apr 2022 19:16:43 -0700</pubDate>
  </item>
  <item>
   <description>&lt;p&gt;Here’s a useful Mac tip to insert the current date in your preferred format nearly anywhere. It does not require any third-party software that can potentially slow down your computer and cost money.&lt;/p&gt;&#10;&#10;&lt;p&gt;I’ll show you how to add two specific date formats, as well as one for the current time, with this technique. You can use any, all, or a customization that suits your purposes.&lt;/p&gt;&#10;&#10;&lt;p&gt;You can either download my &lt;a href=&quot;/files/Date%20and%20Time%20Quick%20Actions.zip&quot; title=&quot;Quick Actions to insert date and time. ZIP file. Approx 250KB&quot;&gt;zip file&lt;/a&gt; (recommended) or paste the code into Automator yourself.&lt;/p&gt;&#10;&#10;&lt;h3&gt;With My Downloadable “Quick Actions”&lt;/h3&gt;&#10;&#10;&lt;p&gt;&lt;a href=&quot;/files/Date%20and%20Time%20Quick%20Actions.zip&quot; download title=&quot;Download: Quick Actions to insert date and time. ZIP file. Approx 250KB&quot; class=&quot;button button--download&quot;&gt;Date and Time Quick Actions.zip&lt;/a&gt;&lt;/p&gt;&#10;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;p&gt;Download this &lt;a href=&quot;/files/Date%20and%20Time%20Quick%20Actions.zip&quot; title=&quot;Quick Actions to insert date and time. ZIP file. Approx 250KB&quot;&gt;zip file&lt;/a&gt;. Unzip it. Place the contents in the correct location.&lt;/p&gt;&#10;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;p&gt;From a Finder window, just use the menu item Go &gt; Go to folder…, enter “~/Library/Services” (no quotes), and hit Return.&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Then drag the Workflow files you unzipped into the folder.&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;You will probably need to do something to get macOS to recognize these scripts. I recommend simply opening these scripts in Automator (by double-clicking each of them), then closing them. Or just log out of, and then back into, your Mac!&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;If this is successful, then in most applications, you should be able to view your new Quick Actions by clicking the current application name in the menu bar (top left of the screen) and then hovering over Services.&lt;/p&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Now let&apos;s make these actions available by keyboard shortcuts! Open System Settings &gt; Keyboard &gt; Shortcuts. Select “App Shortcuts” on the left. Select “All Applications” on the right. Click the Add button (which looks like a plus sign). For “Menu Title,” the exact name of the first Workflow you created; in my case it is “Insert Current Date as ISO”. Then set any shortcut you’d like; I’m rolling with “^⌥⌘M”. (This step works because your Quick Action workflow appears in the menu bar under [App Name] &gt; Services all the time.) I recommend the shortcuts and names in the table below.&lt;/p&gt;&#10;&#10;&lt;p&gt;&lt;img src=&quot;/images/date-shortcuts/adding-app-shortcut.png&quot; alt=&quot;Screen shot during this step&quot; /&gt;&#10;&lt;img src=&quot;/images/date-shortcuts/app-shortcuts.png&quot; alt=&quot;Screen shot after this step&quot; /&gt;&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;Because sometimes the above shortcuts don’t take, for some odd reason, there is one more step for each shortcut. While we are in System Settings &gt; Keyboard &gt; Shortcuts, Click “Services” on the left, expand the ”Text” section if applicable, find your new date/time actions, and add a keyboard shortcut to each. (Don’t see your actions? Take a look at the notes under step 1.) Use the same keyboard shortcut for each action as you did in the previous step! One or the other of these mechanisms should work — at least most of the time.&lt;/p&gt;&#10;&#10;&lt;p&gt;&lt;img src=&quot;/images/date-shortcuts/services.png&quot; alt=&quot;Screen shot after this step&quot; /&gt;&lt;/p&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;p&gt;That’s it. Now in almost any context, you can invoke your keyboard shortcut to insert the current date in ISO format at your insertion point (where the blinking cursor is, or replacing any currently selected text).&lt;/p&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&#10;&lt;!-- If you want this with another date and/or time format, modify the above instructions and script to select a different date format, changing the workflow’s name as appropriate. You can use as many such shortcuts as you want; just give them unique names and shortcuts. --&gt;&#10;&#10;&lt;h3&gt;My Date &amp;amp; Time Shortcuts&lt;/h3&gt;&#10;&#10;&lt;table class=&quot;formLayout text&quot;&gt;&#10;&lt;thead&gt;&#10;  &lt;tr&gt;&#10;    &lt;th&gt;Name&lt;/th&gt;&#10;    &lt;th&gt;Suggested Shortcut&lt;/th&gt;&#10;    &lt;th&gt;AppleScript&lt;/th&gt;&#10;  &lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;  &lt;tr&gt;&#10;    &lt;td&gt;Insert Full Current&lt;br&gt;Human-Readable Date&lt;/td&gt;&#10;    &lt;td&gt;^⌥⌘D&lt;/td&gt;&#10;    &lt;td&gt;&lt;pre&gt;&lt;code class=&quot;language-applescript&quot;&gt;tell (current date) to return date string&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;td&gt;Insert Current&lt;br&gt;Date as ISO&lt;/td&gt;&#10;    &lt;td&gt;^⌥⌘M&lt;/td&gt;&#10;    &lt;td&gt;&lt;pre&gt;&lt;code class=&quot;language-applescript&quot;&gt;tell (current date) as «class isot» as string to return the contents of [text 1 thru 10] as text&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;  &lt;tr&gt;&#10;    &lt;td&gt;Insert Current Time&lt;/td&gt;&#10;    &lt;td&gt;^⌥⌘T&lt;/td&gt;&#10;    &lt;td&gt;&lt;pre&gt;&lt;code class=&quot;language-applescript&quot;&gt;tell (current date) to return time string&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;  &lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&#10;&lt;h3&gt;Alternatively, Use Automator Yourself&lt;/h3&gt;&#10;&#10;&lt;p&gt;Here is the manual method in case you don’t trust my downloadable &lt;a href=&quot;/files/Date%20and%20Time%20Quick%20Actions.zip&quot; title=&quot;Quick Actions to insert date and time. ZIP file. Approx 250KB&quot;&gt;zip&lt;/a&gt;.&lt;/p&gt;&#10;&#10;&lt;ol&gt;&#10;&lt;li&gt;Open Automator.&lt;/li&gt;&#10;&lt;li&gt;Create a new document of type “Quick Action”.&lt;/li&gt;&#10;&lt;li&gt;Insert “Run AppleScript” item.&lt;/li&gt;&#10;&lt;li&gt;Replace the text with one of the short scripts from the table above. (Safety tip: Ask a trusted programmer friend if the code looks safe.)&lt;/li&gt;&#10;&lt;li&gt;Choose “Workflow receives no input in any application,” and check “Output replaces selected text.”&lt;/li&gt;&#10;&lt;li&gt;Save it with an appropriate name (my suggestion is to use the corresponding value in the first column of the table above). It should default to the correct location, which is your user directory’s Library/Services file.&lt;/li&gt;&#10;&lt;li&gt;Now follow the remaining steps from the downloadable method, starting with step 2.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&#10;&lt;h3&gt;What About iPhones?&lt;/h3&gt;&#10;&#10;&lt;p&gt;Bonus tip: Do you miss this shortcut on your iPhone or other iOS device? There is an affordable app that provides similar functionality via a software keyboard: &lt;a href=&quot;https://apps.apple.com/us/app/timestamp-keyboard/id1363760897&quot; title=&quot;TimeStamp Keyboard on the App Store&quot;&gt;TimeStamp Keyboard&lt;/a&gt;.&lt;/p&gt;&#10;&#10;&lt;div class=&quot;hr&quot;&gt;&lt;hr /&gt;&lt;/div&gt;&#10;&#10;&lt;p&gt;&lt;em&gt;Updated April 2024 with newer System Settings screen shots, no longer showing a mismatched keyboard shortcut. Thanks to reader Lynn for reporting the error. I also changed references from System Preferences to System Settings, reflecting changes in macOS since this article was originally published.&lt;/em&gt;&lt;/p&gt;&#10;&#10;&lt;p&gt;&lt;em&gt;Thanks to CJK for a &lt;a href=&quot;https://apple.stackexchange.com/a/396985/6417&quot;&gt;helpful answer on Stack Overflow&lt;/a&gt; that gave me most of what I needed here. &lt;a href=&quot;/contact?reason=date%20shortcuts&quot;&gt;Let me know&lt;/a&gt; if you liked this tip or have feedback on it.&lt;/em&gt;&lt;/p&gt;&#10;</description>
   <guid>https://alanhogan.com/tips/insert-current-date-with-keyboard-shortcut</guid>
   <link>https://alanhogan.com/tips/insert-current-date-with-keyboard-shortcut</link>
   <category/>
   <title>Insert the Current Date with a Keyboard Shortcut</title>
   <pubDate>Thu, 07 Apr 2022 19:24:50 -0700</pubDate>
  </item>
  <item>
   <description>&lt;p&gt;In a remarkable turn of events, and in the final days before the first Democratic primary election of the 2020 season, the results of a major presidential poll have been discarded and will not be released. Candidates and commentators were counting on the results of this poll for last-minute strategy and projection purposes.&lt;/p&gt;&#10;&#10;&lt;p&gt;An inconsistency had been discovered after at least one poll respondent said that their preferred candidate, Pete Buttigieg, was not included in a list of candidates read to them over the phone. This was unexpected, and poll results were invalidated over concerns that it was unclear how many times this error had occurred during polling operations.&lt;/p&gt;&#10;&#10;&lt;p&gt;Naturally this error drew concern and prompted some investigation as to its cause. The results were remarkable.&lt;/p&gt;&#10;&#10;&lt;p&gt;Reportedly, the poll worker had increased the font size on their computer, causing the final candidate’s name to be pushed off-screen and thus to be unread.&lt;/p&gt;&#10;&#10;&lt;p&gt;This is a dramatic example of an unfortunately commonly overlooked aspect of accessibility in software design: support of font size enlargement. Too often, interfaces are built to fit text at one size, with bounding boxes given hard-coded dimensions. When text sizes increase — or when that text is translated into a more long-winded language — this can lead to text overflowing those boxes. With nowhere to go, such text is often rendered invisible and unreadable.&lt;/p&gt;&#10;&#10;&lt;p&gt;While it is not clear from reports if this exact scenario was at play in the case of the wasted poll (perhaps the user missed a scroll bar?), it certainly is a common error, and this case provides a dramatic example of the costs of inaccessible interface design and development.&lt;/p&gt;&#10;</description>
   <guid>https://alanhogan.com/accessibility-error-sinks-poll</guid>
   <link>https://alanhogan.com/accessibility-error-sinks-poll</link>
   <category/>
   <title>Anticipated Iowa Poll Canceled Because Someone Neglected Accessibility</title>
   <pubDate>Sun, 02 Feb 2020 10:31:57 -0800</pubDate>
  </item>
 </channel>
</rss>