<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Nathan Knowler</title>
        <link>https://knowler.dev/</link>
        <description>Some words.</description>
        <lastBuildDate>Fri, 23 Feb 2024 07:52:30 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>Deno</generator>
        <language>en-CA</language>
        <copyright>Code and content by Nathan Knowler. Except if noted otherwise, content on this website is licensed under a CC BY-NC-SA 4.0 license.</copyright>
        <item>
            <title><![CDATA[Declarative Custom Elements Should Take Inspiration From CSS]]></title>
            <link>https://knowler.dev/blog/declarative-custom-elements-should-take-inspiration-from-css</link>
            <guid>declarative-custom-elements-should-take-inspiration-from-css</guid>
            <pubDate>Wed, 21 Feb 2024 21:31:46 GMT</pubDate>
            <description><![CDATA[Why I think it’s worth approaching declarative custom elements the same way CSS solved stylings for HTML.]]></description>
            <content:encoded><![CDATA[<p>I’ll admit that I’m not fully read on this topic and that makes it a bit overwhelming to participate in this discussion. Nevertheless, I had a weird idea for it a while ago and I’d like to share it or at least write it on my own platform so that it doesn’t get lost the annals of some Discord channel.</p>
<h2 id="declarative-custom-elements-in-a-nutshell">Declarative Custom Elements in a nutshell</h2>
<p>As of yesterday, the Declarative Shadow DOM is now available in all browsers with its addition to Firefox. This is great. The Shadow DOM is no longer restricted to JavaScript. This declarative form is still quite limited. It mostly serves as a way to either avoid the dreaded <em>flash of unstyled content</em> and to do less work with JavaScript. It does nothing to actually define a custom element and further if you were to use this to server render all of your custom elements that use the Shadow DOM, it would mean you need to include all the CSS in each tag (or use a <code>&#x3C;link></code> tag which can be problematic, or so I’ve heard).</p>
<p>Enter <strong>Declarative Custom Elements</strong>. It’s a proposed way to declaratively define a custom element without JavaScript in your HTML. This would ultimately mean that you could use your custom elements without needing to server render their individual content and they would work in a limited way. You would still need JavaScript for a whole lot of functionality, but a lot of the work you might do to set up a custom element’s shadow root (i.e. the markup and styles) would be taken care of.</p>
<p>I’m not going to get into how this relates to HTML modules or anything like that—I don’t fully understand it and it’s not relevant. What I want to focus on is syntax we use to spell out these definitions.</p>
<h2 id="do-we-use-an-htmlxml-like-syntax-to-do-this">Do we use an HTML/XML like syntax to do this?</h2>
<p>When we think <em>declarative</em> and <em>custom elements</em>, immediately we jump to using HTML (or an XML-like) syntax to achieve this. This would require a significant extension of HTML. Further, are the ergonomics of HTML or XML up to the task? Are we selling what we could do with a JavaScript-free solution short?</p>
<p>Now, before someone brings up <em>XSLT</em>—yes, I know that exists, but please try to entertain what I’m saying, otherwise, close this tab.</p>
<h2 id="lets-talk-about-styling">Let’s talk about styling</h2>
<p>Wait, <em>what does styling have to do with this?</em> Well, nothing really. I do think it’s worth exploring how CSS solved issues of styling HTML.</p>
<p>As the kids say, <em>in the late 20th century</em>, you could style your HTML was with attributes and even elements. There was a <code>&#x3C;font></code> element. There was a <code>&#x3C;center></code> element. There were <code>color</code>, <code>bgcolor</code>, <code>align</code>, <code>rightmargin</code> attributes. All deprecated now, but when I was first learning web development in the mid-2000s some of these were still in use and as a beginner reading outdated resources, I even used some until I realized the power of CSS (and browsers deprecated them).</p>
<p>Anyway, using attributes and elements for styling was very limiting. CSS changed that by separating the concern of styling which meant that you could use the same rules for different markup without modifying the markup in every place it was used.</p>
<h2 id="what-if-we-used-a-different-declarative-option">What If we used a different declarative option?</h2>
<p>I think that a CSS-like syntax (read: <strong>not for styling</strong>) could be useful for creating element definitions as the problem that CSS solves for styling HTML seems strikingly similar to the problem of setting up a shadow root for a custom element. Yes, CSS can’t create <em>elements</em>. What CSS is great at matching selectors to a list of properties, which makes it helpful for solving the issue of setting the values of attributes in a dynamic way.</p>
<h2 id="what-this-could-look-like-an-example">What this could look like? An Example…</h2>
<p>Something I always test when using a templating language is how easy it is to create a navigation link that can indicate it’s the current page. I usually don’t create custom elements for these, since I don’t want them to require JavaScript. But if there were a way to do that declaratively, then I might entertain using an API like this:</p>
<pre><code class="hljs language-html"><span class="hljs-tag">&#x3C;<span class="hljs-name">nav-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>></span>Home<span class="hljs-tag">&#x3C;/<span class="hljs-name">nav-link</span>></span>
<span class="hljs-tag">&#x3C;<span class="hljs-name">nav-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/about"</span>></span>About<span class="hljs-tag">&#x3C;/<span class="hljs-name">nav-link</span>></span>
<span class="hljs-tag">&#x3C;<span class="hljs-name">nav-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/contact"</span>></span>Contact<span class="hljs-tag">&#x3C;/<span class="hljs-name">nav-link</span>></span>
</code></pre>
<p>Underneath, I’d want these to translate to something like:</p>
<pre><code class="hljs language-html"><span class="hljs-tag">&#x3C;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">aria-current</span>=<span class="hljs-string">"page"</span> <span class="hljs-attr">part</span>=<span class="hljs-string">"link"</span>></span>Home<span class="hljs-tag">&#x3C;/<span class="hljs-name">a</span>></span>
</code></pre>
<p>And give me a declarative selector to style it with:</p>
<pre><code class="hljs language-css"><span class="hljs-selector-tag">nav</span>-link:<span class="hljs-built_in">state</span>(current)::<span class="hljs-built_in">part</span>(link) {
	<span class="hljs-attribute">background-color</span>: DeepPink;
	<span class="hljs-attribute">color</span>: Black;
}
</code></pre>
<p>Here’s how I think this could look:</p>
<pre><code class="hljs language-html"><span class="hljs-comment">&#x3C;!-- This builds off the existing declarative shadow DOM syntax --></span>
<span class="hljs-tag">&#x3C;<span class="hljs-name">template</span> <span class="hljs-attr">defines</span>=<span class="hljs-string">"nav-link"</span> <span class="hljs-attr">shadowrootmode</span>=<span class="hljs-string">"open"</span>></span>
	<span class="hljs-comment">&#x3C;!-- Our template’s base markup. --></span>
	<span class="hljs-tag">&#x3C;<span class="hljs-name">a</span> <span class="hljs-attr">part</span>=<span class="hljs-string">"link"</span>></span><span class="hljs-tag">&#x3C;<span class="hljs-name">slot</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">slot</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">a</span>></span>

	<span class="hljs-comment">&#x3C;!--
		I want to indicate that these styles should be an adopted stylesheet
		rather than included along with the markup of every shadow root.
	--></span>
	<span class="hljs-tag">&#x3C;<span class="hljs-name">style</span> <span class="hljs-attr">adopted</span>></span><span class="css">
		<span class="hljs-selector-tag">a</span><span class="hljs-selector-attr">[aria-current=<span class="hljs-string">"page"</span>]</span> {
			<span class="hljs-attribute">text-decoration</span>: none;
			<span class="hljs-attribute">color</span>: inherit;
		}
	</span><span class="hljs-tag">&#x3C;/<span class="hljs-name">style</span>></span>

	<span class="hljs-comment">&#x3C;!--
		I’m using a style tag here for *just* syntax highlighting.
		For the love all things good: this is not for styling though.
	--></span>
	<span class="hljs-tag">&#x3C;<span class="hljs-name">style</span> <span class="hljs-attr">internals</span>></span><span class="css">
		<span class="hljs-comment">/* The syntax is still CSS-like though even though its not for styling */</span>

		<span class="hljs-keyword">@attribute</span> to {
			syntax: <span class="hljs-string">"&#x3C;url>"</span>;
			initial-value: none;
			observed: true;
      <span class="hljs-comment">/* Perhaps there could be a global registery for attributes these too that works with a custom attributes registry. */</span>
		}

		<span class="hljs-selector-tag">a</span> {
			<span class="hljs-comment">/* Since the `to` attribute is observed, this is now bound. */</span>
			href: <span class="hljs-built_in">host-attribute</span>(to);
		}

		<span class="hljs-comment">/* This works like a container style query */</span>
		<span class="hljs-keyword">@host</span> attribute(<span class="hljs-attribute">to</span>: location.path) {
			<span class="hljs-selector-pseudo">:host</span> {
				<span class="hljs-comment">/* Maybe you could set element’s custom state (i.e. `nav-link:state(current)`)  */</span>
				state-set: current;
			}

			<span class="hljs-comment">/* Most importantly, you could use this to set attributes for other elements in your shadow root */</span>
			<span class="hljs-selector-tag">a</span> {
				aria-current: page;
			}
		}

    <span class="hljs-comment">/*
      Perhaps you could even use `@media` here too to have media query
      specific rules (it maps to `window.matchMedia`, right?)
    */</span>
	</span><span class="hljs-tag">&#x3C;/<span class="hljs-name">style</span>></span>
<span class="hljs-tag">&#x3C;/<span class="hljs-name">template</span>></span>
</code></pre>
<p>As you can see, the idea is to use an additional tag, perhaps <code>&#x3C;internals></code> to declaratively bind the host element’s attributes to attributes for elements within the shadow root and the element’s custom state (i.e. CSS Custom State also known by its JavaScript API name <code>CustomStateSet</code>). Since CSS has a number of features like media queries or container queries, some form of these could be helpful for describing what should happen when an custom element is in a particular state.</p>
<h2 id="why">Why?</h2>
<p>You might wonder, why do this with a CSS-like language? Isn’t the point of not using JS so that we can do this HTML? If we’re going to do it with a CSS-like language, why don’t we just use JavaScript?</p>
<p>The main reason is that there are a lot more API overlaps between CSS and JavaScript. I don’t think it makes sense to recreate all of those in HTML. Our declarative custom elements aren’t going to be expressive as they could otherwise be, but why limit ourselves to what can be expressed with HTML or XML.</p>
<p>CSS syntax is already familiar and developers already understand its selectors. They even use them with their JavaScript.</p>
<p>CSS has limits that JavaScript does not. It can’t do quite as much as JavaScript can do. This makes it more ideal than running JavaScript.</p>
<p>So, why not fork off of something that’s already declarative, albeit limited in what it can do (that’s a positive for this situation, because JavaScript is heavy and can maybe do <em>too</em> much). The two languages: this <em>custom element defintion language</em> and CSS could be mutually beneficial to each other as well as each grows as well.</p>
<h2 id="closing-words">Closing words</h2>
<p>Anyway, that’s my two cents. Let me know what you think. Or don’t.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[This Personal Site Has Feature Flags]]></title>
            <link>https://knowler.dev/blog/this-personal-site-has-feature-flags</link>
            <guid>this-personal-site-has-feature-flags</guid>
            <pubDate>Sat, 10 Feb 2024 03:41:46 GMT</pubDate>
            <description><![CDATA[Using feature flags to work in public, experiment, and keep things moving.]]></description>
            <content:encoded><![CDATA[<p>Feature flags are something you see in some larger products. GitHub uses them a lot and I am genuinely excited when new flags show up. It’s fun to participate in something new, even if there are some rough edges.</p>
<p>This small, personal website is the farthest thing from a large product. I intentionally embrace its nature as something that’s small in scale. This manifests itself in a few ways:</p>
<ul>
<li>As of writing this, there is no JavaScript. Not because I don’t want there to be or because I <em>hate</em> JavaScript or something. While I certainly am a bonafide member of the <em>Anti-JavaScript JavaScript Club</em>, that means I like to use it when I need it. So far I haven’t found a use for it, but that doesn’t mean that I won’t. I do know that when I do, I will have am equitable alternative for those who do not have JavaScript enabled.</li>
<li>I don’t use a CSS build process or any pre-processor or any framework for that matter. If you look close, you’ll realize that sometimes there actually no rhyme or reason to the way that I’ve organized my CSS, in some places it’s messy, and there’s likely some dead code. My younger self would be grimacing.</li>
<li>I often hold off on implementing features that might seem relatively easy to implement (namely with JavaScript alone) as I don’t see them as absolutely necessary or I’m not interested in doing a half-assed job.</li>
</ul>
<p><strong>So, if I’ve embraced being small, why am I using a larger product pattern like feature flags?</strong> Well, it’s actually <em>because</em> I am small.</p>
<p>I often don’t have tonne of time to work on this website. That can make more ambitious projects harder to tackle. Sometimes, I’ll be in the middle of working on something, then life happens and I can’t return to it for a week or even longer. It can be really easy to forget what I was doing or sometimes I’ll have something pressing that I need to change or do. In those latter situations, I’ll stash or revert those working changes into oblivion.</p>
<p>Since this website isn’t just a home for the words I write, but is something that I use to learn and refine my skills as a web developer, I’m generally not working with deadlines and am more willing to take the time to get things right. The balance between being a perfectionist, but also someone who explores is hard to navigate—it can easily lead to accomplishing nothing. Something else to balance is keeping this thing working so that I can write.</p>
<p>A few months ago I realized I could use a “development flag” to maintain my progress on features I was working on and while continuing to push the website forward in other ways. After doing this for a little while, I realized that it might be beneficial to expose some of those work-in-progress bits to others for feedback and as a way of <em>working in public</em>.</p>
<p>Doing this allows me to take some risks I usually wouldn’t for the sake of preserving a working mainline experience. I can still preserve the that experience while exploring new features that won’t diverge from each other through stale branches or forgotten stashes. In some cases, I can explore techniques or web platform features that won’t be ready for a few years.</p>
<p>So, if you’re interested, <a href="/flags">I only have a couple small features at the moment</a>. Any feedback on their implementation is appreciated. I’ll be adding some more experimental features in the future.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How Much Do We Actually Need Templating?]]></title>
            <link>https://knowler.dev/blog/how-much-do-we-actually-need-templating</link>
            <guid>how-much-do-we-actually-need-templating</guid>
            <pubDate>Fri, 05 Jan 2024 21:11:03 GMT</pubDate>
            <description><![CDATA[Is this a problem we invented in our pursuit of taming the cascade with class names?]]></description>
            <content:encoded><![CDATA[<p><strong>Update: yes we do</strong></p>
<p>I’m wondering if the “burden of HTML structure” is greatly exaggerated due to practices like <abbr title="Block Element Modifier">BEM</abbr>.</p>
<p>In my opinion, it’s not so much writing the HTML, it’s wiring up all the classes correctly that makes it burdensome. The class names aren’t there so much to tell you what things are—that’s a nice benefit—but since they are technically necessary to tame the cascade. When the technical need for those class names is removed (i.e. using <code>@scope</code>) is the apparent need for templating still as strong?</p>
<p>Don’t get me wrong, I think templating is great, I’m just wondering if we overplay its need when some of the underlying problems are being solved by other means.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[So, You Want to Encapsulate Your Styles?]]></title>
            <link>https://knowler.dev/blog/so-you-want-to-encapsulate-your-styles</link>
            <guid>so-you-want-to-encapsulate-your-styles</guid>
            <pubDate>Thu, 04 Jan 2024 21:37:32 GMT</pubDate>
            <description><![CDATA[What is style encapsulation and how you can you achieve it without the Shadow DOM?]]></description>
            <content:encoded><![CDATA[<p>The Shadow DOM allows us to encapsulate our styles. What does that mean?</p>
<ol>
<li>
<p>Elements within a shadow tree are isolated and cannot be selected by styles set outside of the tree.</p>
</li>
<li>
<p>Styles set for the shadow tree are scoped to the elements within the tree.</p>
</li>
</ol>
<h2 id="how-can-styles-cross-the-shadow-boundary">How can styles cross the shadow boundary?</h2>
<p>Now, there are a few ways that styles can cross the boundary between the shadow tree and its outside context (known as the host’s context):</p>
<ol>
<li>
<p>Inheritance: the host element of the shadow tree is not within the tree (surprise!). This means that it can be selected from the outside and be styled in that way. The shadow tree inherits its styles from the host element. This means that any property that inherits will inherit from the outside context. Some properties such as <code>font-family</code> or <code>color</code> inherit by default for many elements. Unregistered custom properties do this as well. People often refer to this as “piercing the Shadow DOM.”</p>
</li>
<li>
<p>The <code>:host</code> pseudo-class and <code>:host()</code> pseudo-class function can be used to select the host element from inside the shadow tree. You can use the function to conditionally apply styles to elements within the tree when the host matches a particular selector.</p>
</li>
<li>
<p>This selector is likely being dropped from the spec: the <code>:host-context()</code> pseudo-class can be used to apply styles to the host element or to elements within the tree when the host is used in a specific context. The function matches an ancestor with a simple selector.</p>
</li>
<li>
<p>The <code>::slotted()</code> pseudo-element function allows us to select slotted elements from the host element’s light tree. Those elements are still subject to the styles of the host’s context. The shadow tree’s styles are cascaded before the host context’s styles and so any styles set with <code>::slotted()</code> will be weaker than those other styles. The only way to “win” this fight is <code>!important</code> and that completely blocks styling from outside the shadow tree for whatever property it’s applied to.</p>
<ul>
<li>Instead of inheriting directly from the host, slotted elements inherit from the slot element they are assigned to. That slot element being a part of the shadow tree, eventually does inherit from the host element, but this is just one thing to keep in mind.</li>
</ul>
</li>
<li>
<p>The <code>::part()</code> pseudo-element function allows the host’s context to select elements denoted as CSS parts using the <code>part</code> attribute in the shadow tree. Again, since the shadow tree’s styles are cascaded before the host’s context, the host’s context styles will win unless the <code>!important</code> flag is used on the styles within the shadow tree.</p>
<ul>
<li>Again, remember inheritance: since a part is what its children inherit from, applying styles with the <code>::part()</code> selector is one way you can indirectly style elements within a shadow tree.</li>
</ul>
</li>
</ol>
<h2 id="limitations-of-styling-the-shadow-dom">Limitations of styling the Shadow DOM</h2>
<p>Due to their nature of being cascaded before the host context’s styles, (which is directly after the user agent and user styles), styles set for a shadow tree cannot share styles with other shadow trees. This can be quite frustrating as it’s often desirable to reset elements or to provide some default elements for a document that one might want to be used even within the shadow tree.</p>
<p>Another apparent limitation is the the weakness of Shadow DOM styles in situations where styles are allowed to cross the boundary. For better or for worse, we have a generation of web developers who have to conditioned to think <code>!important</code> is bad (and often, rightly so) which causes them to miss out on its usefulness in this scenario.</p>
<p>Lastly, for slotted elements and for parts, the corresponding selectors only allow selecting the elements themselves and not their descendants. This can be extremely limiting, especially for form related elements which often require certain nested structures.</p>
<p>So, what do we do? The Shadow DOM is our only avenue for style encapsulation, right?</p>
<h2 id="style-encapsulation-without-the-shadow-dom">Style encapsulation without the Shadow DOM</h2>
<p>While there have always been ways of “encapsulating styles” in CSS, none of them have been quite the same as how the Shadow DOM works. Complex selectors can be used to “scope styles” to an ancestor. That falls short when multiple ancestors target the same elements: it becomes a battle of the cascade and specificity.</p>
<h3 id="using-cascade-layers-to-isolate-our-styles">Using cascade layers to isolate our styles</h3>
<p>Cascade layers can be used to effectively isolate our styles from the rest of the document’s styles. Remember, a shadow root’s styles are cascaded right after the user-agent and user styles. If we put our component’s styles in the first cascade layer of a document, then we’ve got the same environment for our styles.</p>
<pre><code class="hljs language-css"><span class="hljs-keyword">@layer</span> components;

<span class="hljs-keyword">@layer</span> components {
	<span class="hljs-attribute">icon</span>-<span class="hljs-selector-tag">button</span> <span class="hljs-selector-tag">button</span> {
		<span class="hljs-comment">/* Button styles */</span>
	}
}
</code></pre>
<p>But, that’s not quite all since styles in subsequent layers can still select our elements. Remember, how <code>!important</code> works in the Shadow DOM? We can use that the same way here. Using <code>!important</code> in a layer will prevent subsequent layers from styling whatever property of the element we apply it to.</p>
<pre><code class="hljs language-css"><span class="hljs-keyword">@layer</span> components;

<span class="hljs-keyword">@layer</span> components {
	<span class="hljs-attribute">icon</span>-<span class="hljs-selector-tag">button</span> <span class="hljs-selector-tag">button</span> {
		<span class="hljs-attribute">color</span>: DeepPink <span class="hljs-meta">!important</span>;
	}
}

<span class="hljs-attribute">icon</span>-<span class="hljs-selector-tag">button</span> <span class="hljs-selector-tag">button</span> {
	<span class="hljs-attribute">color</span>: Wheat <span class="hljs-meta">!important</span>; <span class="hljs-comment">/* important for good measure */</span>
}
</code></pre>
<p>Now it can be quite tedious to apply this to every single property we’ve set a value for. We can make use of a sub-layer to effectively make the child element of our component work as if they were an element in a shadow tree.</p>
<pre><code class="hljs language-css"><span class="hljs-keyword">@layer</span> components;

<span class="hljs-keyword">@layer</span> components {
	<span class="hljs-attribute">icon</span>-<span class="hljs-selector-tag">button</span> <span class="hljs-selector-tag">button</span> {
		<span class="hljs-keyword">@layer</span> styles {
			<span class="hljs-attribute">color</span>: DeepPink;
		}

		<span class="hljs-attribute">all</span>: revert-layer <span class="hljs-meta">!important</span>;
	}
}

<span class="hljs-attribute">icon</span>-<span class="hljs-selector-tag">button</span> <span class="hljs-selector-tag">button</span> {
	<span class="hljs-attribute">font-family</span>: Comic Sans;
	<span class="hljs-attribute">color</span>: Wheat <span class="hljs-meta">!important</span>; <span class="hljs-comment">/* important for good measure */</span>
}
</code></pre>
<p>What’s happening here is that we are reverting the “unlayered” styles of the <code>components</code> layer back to the previous layer. Unlayered styles come after layers, so in this case the previous layer of the “unlayered” styles of the <code>components</code> layer is its <code>styles</code> sub-layer (i.e. <code>components.styles</code>). That’s all a bit hard to understand without a visual, so here’s the order of the layers in our example:</p>
<ol>
<li>
<p>components</p>
<ol>
<li>styles
<ul>
<li>This is the previous layer (i.e. what the styles are being reverted to).</li>
</ul>
</li>
<li>unlayered
<ul>
<li><code>revert-layer</code> is applied on this sub-layer.</li>
</ul>
</li>
</ol>
</li>
<li>
<p>unlayered</p>
</li>
</ol>
<p>Using <code>!important</code> in tandem with <code>revert-layer</code> prevents all subsequent layers from styling whatever property it was set on. And since we used the <code>all</code> selector, that means everything except custom properties and some internationalization related properties.</p>
<p>Now that might seem heavy handed, but what we’ve got the basis for is practically the same as what we get with the Shadow DOM. Use <code>all: revert-layer !important</code> for any element that you want to consider “within the shadow tree” and therefore isolated from selection outside the tree. Elements without the rule will work the same as slotted or CSS part elements work. The only difference is that we have one tree and not two, which honestly is easier to reckon with.</p>
<h3 id="improving-our-scoping-with-scope">Improving our scoping with <code>@scope</code></h3>
<p>Since we are still partly encapsulating our styles with a complex selector, we still have the cascade and specificity to deal with in the <code>components</code> layer. In practice this means we might have difficulty composing two components that target the same descendant. Whatever comes later in the cascade—provided they have equal specificity—will win.</p>
<p>The <code>@scope</code> rule is still being implemented in browsers. As I write this, Chromium browsers are the only browsers which have it in stable and it is available through a flag in Safari Technology Preview.</p>
<pre><code class="hljs language-css"><span class="hljs-keyword">@layer</span> components {
	<span class="hljs-keyword">@scope</span> (icon-button) {
		<span class="hljs-selector-tag">button</span> {
			<span class="hljs-keyword">@layer</span> styles {
				aspect-ratio: <span class="hljs-number">1</span>;
				<span class="hljs-attribute">border-radius</span>: <span class="hljs-number">9999px</span>;
			}

			<span class="hljs-attribute">all</span>: revert-layer <span class="hljs-meta">!important</span>;
		}
	}

	<span class="hljs-keyword">@scope</span> (toggle-button) {
		<span class="hljs-selector-tag">button</span> {
			<span class="hljs-keyword">@layer</span> styles {
				<span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.5rem</span>;
			}

			<span class="hljs-attribute">all</span>: revert-layer <span class="hljs-meta">!important</span>;
		}
	}
}
</code></pre>
<p>Now whichever element is closer in scope to the shared descendant will have its styles take precedent. For example, here the shape of the button will be a circle and not a squre with rounded corners since <code>icon-button</code> is closer in scope:</p>
<pre><code class="hljs language-html"><span class="hljs-tag">&#x3C;<span class="hljs-name">toggle-button</span>></span>
	<span class="hljs-tag">&#x3C;<span class="hljs-name">icon-button</span>></span>
		<span class="hljs-tag">&#x3C;<span class="hljs-name">button</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Dark Mode"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">aria-pressed</span>=<span class="hljs-string">"false"</span>></span>
			<span class="hljs-tag">&#x3C;<span class="hljs-name">darkmode-icon</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">darkmode-icon</span>></span>
		<span class="hljs-tag">&#x3C;/<span class="hljs-name">button</span>></span>
	<span class="hljs-tag">&#x3C;/<span class="hljs-name">icon-button</span>></span>
<span class="hljs-tag">&#x3C;/<span class="hljs-name">toggle-button</span>></span>
</code></pre>
<h3 id="solving-the-shortcomings-of-shadow-dom-styles">Solving the shortcomings of Shadow DOM styles</h3>
<p>Earlier, we listed some issues we had with Shadow DOM styling. So far, since we’re using a single tree for our elements, we don’t have the problem of not being able to select the descendants of slots or parts.</p>
<p>The problem of “weak” styles still remain for our new “slotted” or “part” elements (i.e. those which aren’t heavy-handedly preventing styling from subsequent layers), however, there is something we can do which might make that a non-issue—and which could make you consider applying that heavy handed approach to all the elements within these types of components. We have control over which layer we’ve set these styles in, so we can include a layer of shared styles which can serve as a basis for all our components. So instead of setting these styles in the first layer, we could include a <code>reset</code> or <code>defaults</code> layer before that.</p>
<h3 id="how-to-remain-extensible">How to remain extensible</h3>
<p>In the past, <a href="https://knowler.dev/blog/extensible-web-components">I’ve written that when you write web components, you should do so in an extensible manner</a> and that means leveraging slots and parts as a default. What I am suggesting here seems to run against that advice.</p>
<p>The difference here is that since we are in the “Light DOM”, the need for slots/parts to remain extensible doesn’t exist because we’re not working with a tree that is off limits.</p>
<p>Further, since we can allow layers before our components layer to style elements in our component’s tree, we have a new door to allow our elements to be extensible that doesn’t currently exist with the Shadow DOM (see <a href="https://github.com/WICG/webcomponents/issues/909">the “open-stylable” proposal</a> to see a discussion about changing this).</p>
<p>There’s one more way that we can allow for modification.</p>
<h3 id="declarative-custom-property-apis">Declarative custom property APIs</h3>
<p>With the advent of Cascade Layers, we can use <code>!important</code> to narrow down the available CSS API for elements. Doing so feels kind of wrong—like you are taking something away—but there is an opportunity to be generous. That generosity comes in the form of custom properties.</p>
<p>We can use custom properties to provide a constrained way of modifying our components. Design system implementors can set the rules for modification.</p>
<h3 id="styling-through-custom-attributes">Styling through custom attributes</h3>
<p>Another way we can allow for modification is with custom attributes. This technique is nothing new. It allows consumers to be more declarative with saying what they want.</p>
<pre><code class="hljs language-css"><span class="hljs-keyword">@layer</span> components {
	<span class="hljs-keyword">@scope</span> (icon-button) {
		<span class="hljs-selector-pseudo">:where</span>(&#x26;) {
			<span class="hljs-attr">--shape</span>: circle;
		}

		<span class="hljs-selector-pseudo">:scope</span> {
			container: icon-button;
		}

		<span class="hljs-selector-tag">button</span> {
			<span class="hljs-keyword">@layer</span> styles {
				aspect-ratio: <span class="hljs-number">1</span>;
				<span class="hljs-attribute">border-radius</span>: <span class="hljs-number">9999px</span>; <span class="hljs-comment">/* Defaults to a circle */</span>

				<span class="hljs-selector-pseudo">:where</span>(<span class="hljs-selector-attr">[shape=<span class="hljs-string">"circle"</span>]</span>) &#x26; {
					<span class="hljs-attribute">border-radius</span>: <span class="hljs-number">9999px</span>;
				}
				<span class="hljs-selector-pseudo">:where</span>(<span class="hljs-selector-attr">[shape=<span class="hljs-string">"square"</span>]</span>) &#x26; {
					<span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0</span>;
				}
			}

			<span class="hljs-attribute">all</span>: revert-layer <span class="hljs-meta">!important</span>;
		}
	}
}
</code></pre>
<p>The downside here is that this is an HTML API and not a CSS API. Some might prefer that, but I personally think that a CSS API is more powerful since it allows other elements to change the styling of your element without the help of JS.</p>
<h2 id="better-custom-properties-with-style-queries">Better custom properties with style queries</h2>
<p>Style queries allow us to query a custom property value set on a container. Currently, this is only available in Chromium (in stable). We can use style queries to provide even better custom properties—custom properties that are more declarative in regard to their values. (And we can keep the HTML API too!)</p>
<pre><code class="hljs language-css"><span class="hljs-keyword">@layer</span> components {
	<span class="hljs-keyword">@scope</span> (icon-button) {
		<span class="hljs-selector-pseudo">:scope</span> { container: icon-button; }

		<span class="hljs-comment">/* We need to set these values weakly so other elements can override them their own CSS */</span>
		<span class="hljs-selector-pseudo">:where</span>(&#x26;) { <span class="hljs-attr">--shape</span>: circle; }
		<span class="hljs-selector-pseudo">:where</span>(<span class="hljs-selector-attr">[shape=<span class="hljs-string">"square"</span>]</span>) { <span class="hljs-attr">--shape</span>: square; }

		<span class="hljs-selector-tag">button</span> {
			<span class="hljs-keyword">@layer</span> styles {
				aspect-ratio: <span class="hljs-number">1</span>;

				<span class="hljs-comment">/* Set the shape */</span>
				<span class="hljs-keyword">@container</span> icon-button style(<span class="hljs-attribute">--shape</span>: circle) {
					<span class="hljs-attribute">border-radius</span>: <span class="hljs-number">9999px</span>;
				}
				<span class="hljs-keyword">@container</span> icon-button style(<span class="hljs-attribute">--shape</span>: square) {
					<span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0</span>;
				}
			}

			<span class="hljs-attribute">all</span>: revert-layer <span class="hljs-meta">!important</span>;
		}
	}
}
</code></pre>
<h3 id="what-should-this-be-used-for">What should this be used for?</h3>
<p>You might be looking at this code and be thinking: “that all seems impractical” or that’s a lot of boilerplate. I agree and I disagree. I don’t think this is how you should write all of your styles. It does however work quite well for a design system or for shared components. You probably aren’t introducing new components every day and so the amount of times you’d need to employ this pattern are few and far between.</p>
<p>If you wanted to colocate these styles with a web component, you can easy do so with <code>document.adoptedStyleSheets</code>. The nice thing about the scoped rule is that it doesn’t matter so much the order you insert the styles into your components layer. You could even make the layer the styles get inserted into configurable.</p>
<h2 id="could-this-be-the-future-of-encapsulated-component-styles">Could this be the future of encapsulated component styles?</h2>
<p>By not using the Shadow DOM, we actually have a better styling experience for our components when we leverage Cascade Layers, the forthcoming <code>@scope</code> rule, and style queries. And we might need to rethink our relationship with the notorious <code>!important</code> flag.</p>
<p>Yes, the Shadow DOM allows for templating and that’s not something we can do in the Light DOM yet, but it could still be on the horizon. If you’re already building Web Components that already don’t use the Shadow DOM, this approach can fill the desire you might have for encapsulated styling.</p>
<p>Again, this technique uses features that aren’t available broadly yet, but could this be the future?</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[2024 CSS Wishlist]]></title>
            <link>https://knowler.dev/blog/2024-css-wishlist</link>
            <guid>2024-css-wishlist</guid>
            <pubDate>Wed, 03 Jan 2024 19:13:02 GMT</pubDate>
            <description><![CDATA[What I’ve love to see for CSS in 2024.]]></description>
            <content:encoded><![CDATA[<p>2023 was a great year for CSS. Notably, we has <code>:has()</code> and we got
nesting across browsers now! And there’s so much more.</p>
<p>In 2024, I’d love to see the following implemented in all browsers:</p>
<h2 id="1-style-queries-for-custom-properties">1. Style queries for custom properties</h2>
<p>These are going to revolutionize how we write component styles. One
significant use-case is allowing you to create your own custom-CSS-API
for a component—I’ll write more on this in the future.</p>
<h2 id="2-text-box-trim-and-margin-trim">2. <code>text-box-trim</code> and <code>margin-trim</code></h2>
<p>These aren’t the same, but I’ve grouped them together because they are
just so useful for typography. I recently created a printed document and
I used Safari Technology Preview just so I could use both of these. They
seem like low hanging fruit for implementation.</p>
<h2 id="3-the-scope-rule">3. The <code>@scope</code> rule</h2>
<p>So much of the styles we write are candidate for the CSS <code>@scope</code> rule. <a href="https://12daysofweb.dev/2023/css-scope/">Miriam Suzanne has a fantastic article</a> about this. Also, scope proximity is fascinating!</p>
<h2 id="4-scroll-driven-animations">4. Scroll-driven animations</h2>
<p>I work on websites that use scroll animations all over the place. Being
able to do these all with CSS would be awesome and there are so many
other use cases for them beyond just your typical scrolly-telling sites.</p>
<h2 id="5-types-for-attr">5. Types for <code>attr()</code></h2>
<p>Using attribute values for properties other than <code>content</code> would be
great. This goes hand-in-hand with style queries and will greatly
improve how we write component styles.</p>
<h2 id="6-anchor-positioning">6. Anchor positioning</h2>
<p>While I haven’t been following this too closely, the fact that there is
work being done here is fantastic and makes me excited for its
implementation across browsers. I’m elated to see all that we can now
achieve without JS that is also accessible.</p>
<h2 id="7-view-transitions">7. View transitions</h2>
<p>View transitions are magical and I really do hope we see more progress
here towards stable implementation.</p>
<h2 id="thank-you-css-wish-fulfillers">Thank you CSS wish fulfillers</h2>
<p>I want to end this by expressing gratitude for everyone involved in the
process of making these CSS wishes come true. Whether you are working on
specifications, research, implementation, experimenting, or offering
feedback—I am so grateful for you and your work. You make the web a
better place. Thank you!</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Mental Model for Styling the Shadow DOM]]></title>
            <link>https://knowler.dev/blog/a-mental-model-for-styling-the-shadow-dom</link>
            <guid>a-mental-model-for-styling-the-shadow-dom</guid>
            <pubDate>Mon, 11 Dec 2023 19:58:21 GMT</pubDate>
            <description><![CDATA[Writing styles for the Shadow DOM is like creating a user agent stylesheet for your custom element.]]></description>
            <content:encoded><![CDATA[<p><strong>Writing styles for the Shadow DOM is like creating a user agent stylesheet for your custom element.</strong> This is a good mental model for how to expect Shadow DOM styles to behave and for writing good styles for a custom element.</p>
<h2 id="shadow-dom-styles-are-cascaded-before-the-document-styles">Shadow DOM styles are cascaded before the document styles</h2>
<p>Crucial to writing styles for the Shadow DOM is understanding where they fit in the cascade. It’s common to understand Shadow DOM styles as something that gets cascaded after a document’s styles, but that’s not the case. Styles written for the Shadow DOM are cascaded after the user agent and user styles. Document styles or those in the custom element’s host context override the styles you set in the Shadow DOM—not the other way around. This is why Shadow DOM styles appear to be weak which makes them similar to user agent styles. Here’s a simplified ordering of the cascade:</p>
<ol>
<li>User agent styles</li>
<li>User styles (i.e. styles which relate to user preferences like font size, etc.)</li>
<li>Shadow context styles (including layers)</li>
<li>Document or light context styles (including layers)</li>
<li>Inline styles</li>
</ol>
<p>For a more in-depth overview of the cascade, I recommend reading <a href="https://css-tricks.com/css-cascade-layers/">Miriam Suzanne’s “A Complete Guide to CSS Cascade Layers.”</a></p>
<p><strong>The apparent weakness of shadow styles is actually their strength—it’s what allows your custom element to remain extensible.</strong> With that being said, there are cases where one might need their shadow styles to prevail over those of the document. Let’s revisit a friend whose got a bad reputation.</p>
<h2 id="using-important-for-its-actual-purpose">Using <code>!important</code> for its actual purpose</h2>
<p>The <code>!important</code> flag has a long history of abuse, so much so that we would never consider using it a good practice, would we? This is something that we need to rethink as we become the authors of custom elements.</p>
<p><code>!important</code> allows us to denote what styles are so important about our custom element’s shadow styles that they should not be changed by consumers. Using <code>!important</code> with a shadow CSS rule for the shadow host, a slotted element, or CSS parts will prevent that rule from being changed in the host’s context.</p>
<p>Once we understand that our shadow styles act more like a user agent stylesheet where their weakness is a strength and that we can reclaim <code>!important</code> for its proper use, we’re ready to write Shadow DOM styles for our custom elements.</p>
<h2 id="set-good-defaults-and-embrace-extensibility">Set good defaults and embrace extensibility</h2>
<p>I’ve often seen the advice to not write styles for slotted elements at all (i.e. using the <code>::slotted()</code> selector) and I don’t think that’s good advice. With this mental model I’ve presented above, I hope you can see your shadow styles are more about providing a good usable default that is designed to be overridden or extended. Embrace the use of slots and parts in your custom element designs, and don’t be afraid to style them.</p>
<p>Great styles will help communicate what affordances a custom element provides. For example, if you have a custom element that decorates a <code>&#x3C;button></code> element as a toggle button using the <code>aria-pressed</code> attribute, provide shadow styles for both of those states:</p>
<pre><code class="hljs language-css"><span class="hljs-selector-pseudo">::slotted</span>(<span class="hljs-selector-tag">button</span><span class="hljs-selector-attr">[aria-pressed=<span class="hljs-string">"true"</span>]</span>) {
  <span class="hljs-comment">/* Styles for when the button is pressed */</span>
}

<span class="hljs-selector-pseudo">::slotted</span>(<span class="hljs-selector-tag">button</span><span class="hljs-selector-attr">[aria-pressed=<span class="hljs-string">"false"</span>]</span>) {
  <span class="hljs-comment">/* Styles for when the button isn’t pressed */</span>
}
</code></pre>
<p>If there’s only one ways an affordance can be visually communicated, you can use <code>!important</code> to ensure that isn’t overridden. You can even use <code>!important</code> on a rule, but use custom properties to allow for more constrained modification of the rule.</p>
<h2 id="resetting-a-custom-elements-shadow-styles-is-very-easy">Resetting a custom element’s shadow styles is very easy</h2>
<p>Maybe you think these default styles just introduce extra work for the consumer to override? Well, it’s actually not very difficult to revert all of the shadow styles for an element.</p>
<p>Say we have a slotted button that has some default styles from the Shadow DOM. We can target the element and set <code>all: revert</code> and sure enough we’re back to the user agent styles for that element. The one exception is those styles that we’ve deemed important with the <code>!important</code> flag. I hope you can see this as a positive. We’ve got an incredible way of resetting an element while still respecting what’s vital to it. Reset without fear! <a href="https://codepen.io/knowler/pen/OJdGxoq">Check out this pen of resetting shadow styles in action</a> or see a reduced example of it below:</p>
<pre><code class="hljs language-html"><span class="hljs-tag">&#x3C;<span class="hljs-name">style</span>></span><span class="css">
	toggle-<span class="hljs-selector-tag">button</span> <span class="hljs-selector-tag">button</span> {
		<span class="hljs-attribute">all</span>: revert;
	}
</span><span class="hljs-tag">&#x3C;/<span class="hljs-name">style</span>></span>
<span class="hljs-tag">&#x3C;<span class="hljs-name">toggle-button</span>></span>
	<span class="hljs-comment">&#x3C;!-- Using the Declarative Shadow DOM for visualizing the example --></span>>
	<span class="hljs-tag">&#x3C;<span class="hljs-name">template</span> <span class="hljs-attr">shadowrootmode</span>=<span class="hljs-string">"open"</span>></span>
		<span class="hljs-tag">&#x3C;<span class="hljs-name">style</span>></span><span class="css">
			<span class="hljs-selector-pseudo">::slotted</span>(<span class="hljs-selector-tag">button</span>) {
				<span class="hljs-comment">/* Will be overridden by revert */</span>
				<span class="hljs-attribute">font-family</span>: system-ui;
				<span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
				<span class="hljs-attribute">font-size</span>: <span class="hljs-number">1em</span>;
				<span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5em</span>;
				<span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.5em</span>;
			}

			<span class="hljs-comment">/* The following will not be overridden by revert (but provides some ability to be modified) */</span>

			<span class="hljs-selector-pseudo">::slotted</span>(<span class="hljs-selector-tag">button</span>) {
				<span class="hljs-attribute">border</span>: <span class="hljs-number">0.125em</span> solid <span class="hljs-built_in">var</span>(--color-foreground) <span class="hljs-meta">!important</span>;

				<span class="hljs-comment">/* Custom properties are not included in `all`, so these are safe. */</span>
				<span class="hljs-attr">--color-foreground</span>: DeepPink;
				<span class="hljs-attr">--color-background</span>: White;
			}

			<span class="hljs-selector-pseudo">::slotted</span>(<span class="hljs-selector-tag">button</span><span class="hljs-selector-attr">[aria-pressed=<span class="hljs-string">"true"</span>]</span>) {
				<span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--color-foreground) <span class="hljs-meta">!important</span>;
				<span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--color-background) <span class="hljs-meta">!important</span>;
			}

			<span class="hljs-selector-pseudo">::slotted</span>(<span class="hljs-selector-tag">button</span><span class="hljs-selector-attr">[aria-pressed=<span class="hljs-string">"false"</span>]</span>) {
				<span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--color-background) <span class="hljs-meta">!important</span>;
				<span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--color-foreground) <span class="hljs-meta">!important</span>;
			}
		</span><span class="hljs-tag">&#x3C;/<span class="hljs-name">style</span>></span>
		<span class="hljs-tag">&#x3C;<span class="hljs-name">slot</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"button"</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">slot</span>></span>
	<span class="hljs-tag">&#x3C;/<span class="hljs-name">template</span>></span>
	<span class="hljs-tag">&#x3C;<span class="hljs-name">button</span> <span class="hljs-attr">slot</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">aria-pressed</span>=<span class="hljs-string">"true"</span>></span>Dark Mode<span class="hljs-tag">&#x3C;/<span class="hljs-name">button</span>></span>
<span class="hljs-tag">&#x3C;/<span class="hljs-name">toggle-button</span>></span>
</code></pre>
<h2 id="but-what-about-design-system-components">But what about design system components?</h2>
<p>A popular use case for custom elements is implementing a library of design system components. The mental model I’ve presented above works really well for introducing new UI primitives where extensibility is vital for reusability. Design system components don’t allow for such free-handed extensibility: visual design constraints are crucial. Is this use case at odds with the mental model? I don’t think so.</p>
<p>If you’re using the Shadow DOM at all, understanding it how I’ve explained will serve you. It might even help you identify when you’ve got a bad expectation of it and steer you towards a more appropriate solution. I’ve got some techniques that I’ll share in a future post for how to use the Shadow DOM to enforce design constraints while allowing the use of slots and parts—and what’s even greater news is that some of the techniques don’t even require the Shadow DOM at all. You can have Shadow DOM like isolation in the Light DOM. Stay tuned…</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Extensible Web Components]]></title>
            <link>https://knowler.dev/blog/extensible-web-components</link>
            <guid>extensible-web-components</guid>
            <pubDate>Sat, 11 Nov 2023 09:13:26 GMT</pubDate>
            <description><![CDATA[Why starting off with styling the Shadow DOM usually indicates a misunderstanding of its purpose.]]></description>
            <content:encoded><![CDATA[<p>The promise of encapsulated styling is usually what attracts people to Web Components and it’s also where a lot of people get their start actually writing them. For many, that’s what Web Components are: bits of Shadow DOM with isolated styling. It certainly is one of the most magical aspects of them—especially for anyone who’s ever struggled with CSS. Writing CSS freely without a thought of specificity, existing styles to override, or just not breaking something else on the page seems liberating.</p>
<p>It doesn’t take long for the euphoria to wear off. Often it’s replaced with confusion when people begin to introduce features like slots into their components. “What do you mean, <a href="https://shadowdom.style/">the Light DOM styles take precedence over the Shadow DOM styles</a>? I thought it was supposed to be the opposite?” It’s also scandalizing for some to discover that, yes, CSS properties do inherit through a shadow root boundary and this is true for (unregistered) custom properties whose default behaviour is to inherit their value. This only ends up coming across that the Shadow DOM isn’t real encapsulation. Something with our mental model of Web Components isn’t quite right.</p>
<h2 id="starting-with-styling-the-shadow-dom-is-a-misstep">Starting with styling the Shadow DOM is a misstep</h2>
<p>As I was watching and participating in numerous conversations about Web Components take place over the last few days, when <a href="https://sfba.social/@fonts/111383440314353875">Robin Rendle pointed out that “Folks start with styles first[…]”</a> it made me realize the <em>starting with styles</em> is indicative of our misunderstanding of what Web Components are and where to start when we build them.</p>
<p>The focus on isolated, scoped styles creates a sense that Web Components are meant to be closed off as a default. To be frank, this is against the grain they were built. We might as drop the “Web” from Web Components if this is what we expect.</p>
<p>In reality, the way that features like slots work (i.e. the CSS <code>::slotted()</code> selector used for styling slotted Light DOM content from the Shadow DOM), having less precedence over the styles for the actual slotted Light DOM content, and the same for CSS Parts used to expose elements from the Shadow DOM for styling outside, show us that Web Components were designed for extension.</p>
<h2 id="the-web-is-extensible">The web is extensible</h2>
<p>Extensibility is an underlying principle of the web. Web Components do not deviate from this principle. Features like slots and CSS parts should be embraced when using the Shadow DOM. Why? Because they empower the extension of what is already there and they allow the extension of what they introduce.</p>
<p>Often, the impulse I see in people (myself included) in building Web Components is to move chunks of their markup and styles to the Shadow DOM. Doing this closes off that markup and those styles from extension. This is a choice that will get us in loads of trouble. Not only is that content inaccessible without the use of JavaScript, potentially fraught with technical and accessibility bugs, but now we’ve limited its ability to extend the existing Light DOM and to be extended with CSS.</p>
<p>Our approach to Web Components should be one that is open by default. We should embrace extensibility in our designs and build with <a href="https://en.wikipedia.org/wiki/Rule_of_least_power">the rule of least power</a> in mind. I think in practice this means adopting approaches like <strong>progressive enhancement</strong>. When this is our approach, we realize that the Light DOM is where we should start and that it serves as valuable foundation to extend.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Now, I hope that I haven’t come across as being dismissive of the Shadow DOM. I actually think it’s pretty great, but what I hope I’ve done, is highlight that when it’s the first and only thing we focus on for Web Components, we actually misunderstand how to use it and it’s purpose.</p>
<p>In the future, I’ll expand on my thoughts of <a href="https://knowler.dev/blog/a-mental-model-for-styling-the-shadow-dom">how to best understand writing styles for the Shadow DOM</a> that lead to a more extensible web. I think understanding Web Components as being extensible makes styling the Shadow DOM make a lot of sense.</p>
<p>Today, I encourage you to get started with Web Components. Start with the most humble and least powerful thing: <em>a custom element</em>—no CSS or JavaScript required (though, a different <code>display</code> property might be a good idea).</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building for the Me That I Don’t Know Yet]]></title>
            <link>https://knowler.dev/blog/building-for-the-me-that-i-don-t-know-yet</link>
            <guid>building-for-the-me-that-i-don-t-know-yet</guid>
            <pubDate>Wed, 08 Nov 2023 20:43:45 GMT</pubDate>
            <content:encoded><![CDATA[<p>I have a lofty goal of creating my own <abbr title="Content Management System">CMS</abbr> for this website. I also have a lofty goal of doing so in a way that is as accessible and performant as possible.</p>
<p>At the end of the day, it’s just me using this thing, so why does it matter that I build this according to such a high standard? I don’t need assistive technology to use the web. I am also privileged with fast Internet and usage limits that I generally don’t exceed. I could do so much more and so much faster if I just built for myself and my own needs today.</p>
<p>But who I am today is not promised for tomorrow. I don’t know who I am tomorrow. I don’t want what I build to be bound to who I am today. My life could radically change between today and tomorrow.</p>
<p>I hope the me of tomorrow whether that be (literally) the day after today or decades from now appreciates how I chose to build today. That is why I strive for such high ideals.</p>
<p>A little backstory behind these musings: I recently built a <abbr title="Command Line Interface">CLI</abbr> for publishing and updating posts on this website. It’s very geared towards my current workflow and what I currently like to use. Right now, I’m quite at home in the terminal and I love using Neovim for writing and editing text. This tool is quite effective and it made me question my whole endeavour of building a CMS especially one with such high standards.</p>
<p>I’ve had enough times in my life that have completely altered how I did things—if not forever, then just for a season. There were things that I left behind as they could no longer serve me where I found myself. Some of those things were great things.</p>
<p>I don’t want that to be the case for this website. The beauty of the web is that it isn’t static. It’s flexible and it adapts to whatever situation it finds itself in. I love this about it and I want to tap into that for this website. Embracing this is how I build for myself tomorrow: the me that I don’t know (yet).</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Context Matters for Semantic HTML]]></title>
            <link>https://knowler.dev/blog/context-matters-for-semantic-html</link>
            <guid>context-matters-for-semantic-html</guid>
            <pubDate>Mon, 06 Nov 2023 17:54:49 GMT</pubDate>
            <description><![CDATA[An invitation to learn HTML semantics beyond tag names.]]></description>
            <content:encoded><![CDATA[<p>I see three stages to learning semantic HTML.</p>
<p><strong>The first stage is <em>expanding your vocabulary</em></strong> beyond using <code>&#x3C;div></code>, <code>&#x3C;span></code>, and other special elements (e.g. <code>&#x3C;a></code>, <code>&#x3C;button></code>, <code>&#x3C;input></code>, etc.). Often at this stage, HTML authors will tap into a wider vocabulary of elements, but use them as it makes sense to them. For example, I’ve seen card elements created like this:</p>
<pre><code class="hljs language-html"><span class="hljs-tag">&#x3C;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>></span>
	<span class="hljs-tag">&#x3C;<span class="hljs-name">header</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">header</span>></span>
	<span class="hljs-tag">&#x3C;<span class="hljs-name">main</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">main</span>></span>
	<span class="hljs-tag">&#x3C;<span class="hljs-name">footer</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">footer</span>></span>
<span class="hljs-tag">&#x3C;/<span class="hljs-name">section</span>></span>
</code></pre>
<p>While this might make a bit more sense to the person who wrote the code—this is a misuse of semantics, which leads me to the second stage…</p>
<p><strong>The second stage is <em>understanding the semantics of the elements beyond their tag name</em>.</strong> This means understanding what <abbr title="Accessible Rich Internet Applications">ARIA</abbr> role they map to. For example, while some are straightforward like the <code>&#x3C;main></code> element having the role of <code>main</code>, others are a bit different, like the <code>&#x3C;header></code> element mapping to the <code>banner</code> role or the <code>&#x3C;footer></code> element mapping to the <code>contentinfo</code> role.</p>
<p>The third is similar to the second and perhaps could be understood as the second learned correctly. <strong>The third stage is <em>understanding that the context an element is used in affects its meaning</em>.</strong> So for that last example: the <code>&#x3C;header></code> element maps to the <code>banner</code> role and the <code>&#x3C;footer></code> element maps to the <code>contentinfo</code> role—that is only true if they’re used in a specific context.</p>
<p>The following are two common examples where the <code>&#x3C;header></code> and <code>&#x3C;footer></code> elements would <strong>not</strong> have any corresponding ARIA role since they’re being used as a descendant of the <code>&#x3C;main></code> element or a <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Content_categories#sectioning_content">sectioning content</a> element (i.e. <code>article</code>, <code>section</code>, <code>nav</code>, <code>aside</code>).</p>
<pre><code class="hljs language-html"><span class="hljs-tag">&#x3C;<span class="hljs-name">body</span>></span>
	<span class="hljs-tag">&#x3C;<span class="hljs-name">main</span>></span>
		<span class="hljs-tag">&#x3C;<span class="hljs-name">header</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">header</span>></span>
		<span class="hljs-tag">&#x3C;<span class="hljs-name">footer</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">footer</span>></span>
	<span class="hljs-tag">&#x3C;/<span class="hljs-name">main</span>></span>
<span class="hljs-tag">&#x3C;/<span class="hljs-name">body</span>></span>
</code></pre>
<pre><code class="hljs language-html"><span class="hljs-tag">&#x3C;<span class="hljs-name">body</span>></span>
	<span class="hljs-tag">&#x3C;<span class="hljs-name">article</span>></span>
		<span class="hljs-tag">&#x3C;<span class="hljs-name">header</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">header</span>></span>
		<span class="hljs-tag">&#x3C;<span class="hljs-name">footer</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">footer</span>></span>
	<span class="hljs-tag">&#x3C;/<span class="hljs-name">article</span>></span>
<span class="hljs-tag">&#x3C;/<span class="hljs-name">body</span>></span>
</code></pre>
<p>In the next example, the <code>&#x3C;header></code> and <code>&#x3C;footer></code> elements are direct descendants of the <code>&#x3C;body></code> element and therefore have their respective <code>banner</code> and <code>contentinfo</code> roles.</p>
<pre><code class="hljs language-html"><span class="hljs-tag">&#x3C;<span class="hljs-name">body</span>></span>
	<span class="hljs-tag">&#x3C;<span class="hljs-name">header</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">header</span>></span>
	<span class="hljs-tag">&#x3C;<span class="hljs-name">main</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">main</span>></span>
	<span class="hljs-tag">&#x3C;<span class="hljs-name">footer</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">footer</span>></span>
<span class="hljs-tag">&#x3C;/<span class="hljs-name">body</span>></span>
</code></pre>
<p>This doesn’t mean that your <code>&#x3C;header></code> or <code>&#x3C;footer></code> elements must be at the top-level as direct descedants of the <code>&#x3C;body></code> element. You can wrap them in a <code>&#x3C;div></code> element (or layers of <code>&#x3C;div></code> elements).</p>
<pre><code class="hljs language-html"><span class="hljs-tag">&#x3C;<span class="hljs-name">body</span>></span>
	<span class="hljs-tag">&#x3C;<span class="hljs-name">div</span>></span>
		<span class="hljs-tag">&#x3C;<span class="hljs-name">header</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">header</span>></span>
		<span class="hljs-tag">&#x3C;<span class="hljs-name">main</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">main</span>></span>
		<span class="hljs-tag">&#x3C;<span class="hljs-name">footer</span>></span><span class="hljs-tag">&#x3C;/<span class="hljs-name">footer</span>></span>
	<span class="hljs-tag">&#x3C;/<span class="hljs-name">div</span>></span>
<span class="hljs-tag">&#x3C;/<span class="hljs-name">body</span>></span>
</code></pre>
<p>Also, this doesn’t mean that you shouldn’t use <code>&#x3C;header></code> or <code>&#x3C;footer></code> within sectioning elements. Just make sure you’re not expecting them to do anymore than be a slight improvement of the developer experience over using <code>&#x3C;div></code>. Their more forgiving nature lends them to be helpful for that use unlike an element like <code>&#x3C;main></code> which you should only use in its appropriate context.</p>
<p>Personally, I tend to avoid using those element outside of contexts where they have more semantic meaning, because I think it makes the HTML source more clear and it means I can be less specific when writing CSS (i.e. if there’s only one <code>&#x3C;header></code> element on the page, there isn’t going to be any conflict if I use a simple selector like the <code>header</code> type selector). Instead of using <code>&#x3C;div></code>, I might use a custom element name like <code>article-header</code>. If you do this, just keep in mind that you’ll likely want to assign a different CSS <code>display</code> value to these elements since the default is <code>inline</code>.</p>
<p>There’s a lot more that can be said on this topic, like if there is more than one <code>&#x3C;nav></code> element on a page they should have different accessible names or that <code>&#x3C;section></code> doesn’t really do much on its own (see <a href="https://toddl.dev/posts/section-is-the-new-div/">Todd Libby’s article, “<code>&#x3C;section></code> is the new <code>&#x3C;div></code>”</a> or <a href="https://www.scottohara.me/blog/2021/07/16/section.html">Scott O’Hara’s article, “Accessibility of the section element”</a>). I guess this is my invitation to you to look deeper into the meaning behind the elements we use and understand the real effects they have on people consuming the HTML documents we author.</p>]]></content:encoded>
        </item>
    </channel>
</rss>