<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	>

<channel>
	<title>Kilian Valkhof</title>
	<atom:link href="https://kilianvalkhof.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://kilianvalkhof.com</link>
	<description>Front-end &#38; user experience developer</description>
	<lastBuildDate>Thu, 22 Feb 2024 07:32:49 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.4.3</generator>
<site xmlns="com-wordpress:feed-additions:1">3707709</site>	<item>
		<title>The gotchas of CSS Nesting</title>
		<link>https://kilianvalkhof.com/2023/css-html/the-gotchas-of-css-nesting/</link>
		
		<dc:creator><![CDATA[Kilian Valkhof]]></dc:creator>
		<pubDate>Tue, 13 Jun 2023 10:53:17 +0000</pubDate>
				<category><![CDATA[CSS & HTML]]></category>
		<guid isPermaLink="false">https://kilianvalkhof.com/?p=3225</guid>

					<description><![CDATA[<p>I&#39;ve written before about the problems you can run into with CSS nesting (keep in mind that article uses an older syntax but the point still stands) and the question that @ChallengeCSS tweeted out today made me realize there&#39;s actually a few more gotcha&#39;s. Here&#39;s what they tweeted: Everyone is exited about CSS Nesting but [&#8230;]</p>
The post <a href="https://kilianvalkhof.com/2023/css-html/the-gotchas-of-css-nesting/">The gotchas of CSS Nesting</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></description>
										<content:encoded><![CDATA[<p>I&#39;ve <a href='https://kilianvalkhof.com/2021/css-html/css-nesting-specificity-and-you/'>written before</a> about the problems you can run into with CSS nesting (keep in mind that article uses an older syntax but the point still stands) and the question that <a href='https://twitter.com/ChallengesCss/status/1668536462906621953'>@ChallengeCSS</a> tweeted out today made me realize there&#39;s actually a few more gotcha&#39;s. <span id="more-3225"></span>Here&#39;s what they tweeted:</p>
<blockquote class="twitter-tweet">
<p lang="en" dir="ltr">Everyone is  exited about CSS Nesting but are you ready for it? Answer the below quiz 👇</p>
<p>What would be the result of the following code  (without cheating! 😈)</p>
<p>&#8220;`<br />body {<br />  @media all {<br />    background: red;<br />  }<br />   background: blue;<br />}<br />&#8220;`</p>
<p>No spoil in the comments!<a  href="https://twitter.com/hashtag/CSS?src=hash&#038;ref_src=twsrc%5Etfw">#CSS</a></p>
<p>— T. Afif @ CSS Challenges (@ChallengesCss) <a  href="https://twitter.com/ChallengesCss/status/1668536462906621953?ref_src=twsrc%5Etfw">June 13, 2023</a></p></blockquote>
<p><script async src="https://platform.twitter.com/widgets.js"  charset="utf-8"></script></p>
<p>Take a moment to come up with your own answer (or vote), then read on.</p>
<p>Now, I initially got it wrong. Here was my thinking pattern:</p>
<ol>
<li> @media doesn&#39;t add specificity, so both declarations have a specificity of 0,0,1</li>
<li><code>background: blue</code> comes later, so it wins</li>
</ol>
<p>But no, the background is red! It turns out that has to do with the way browsers transform your nested CSS rules to individual rules it can apply. So lets dive into how browsers do that.</p>
<h3>A related gotcha, <code>:is()</code></h3>
<p>Last week was CSS Day (which was <em>amazing</em>) and of course a bunch of the presentations mentioned CSS Nesting. Unfortunately, some had a simplified explanation of how rules get resolved. </p>
<p>The <code>&amp;</code> in nested CSS isn&#39;t just replaced by the ancestor, which is what you might think, but it&#39;s ancestor is also wrapped in <code>:is()</code>:</p>
<pre><code class='language-css' lang='css'>body {
    &amp; div {
        ...
    }
}

/* Doesn&#39;t become this: */
body div { ... }

/* It becomes this: */
:is(body) div { ... }
</code></pre>
<p>Now that doesn&#39;t sound like there is much of a difference between <code>body div</code> and <code>:is(body) div</code>, indeed both have a specificity of 0,0,2, but remember that<code>:is()</code> takes on the highest specificity of the selectors in it. So when you have the following:</p>
<pre><code class='language-css' lang='css'>main, #intro {
    &amp; div {
        ...
    }
}
</code></pre>
<p>The resulting selector, even when targeting a <code>div</code> in <code>main</code>, ends up as:</p>
<pre><code class='language-css' lang='css'>:is(main, #intro) div { ... }
</code></pre>
<p>Which makes it go from 0,0,1 for <code>main div</code> to 1,0,1 making it vastly more specific. That gotcha gets lost when examples fail to include the way ancestors are wrapped in <code>:is()</code> (and yes, they also nest :<code>is()</code>!)</p>
<h3 id='back-to-the-original-gotcha'>Back to the original gotcha</h3>
<p>So back to the challenge up top. You can intermingle properties and nesting. You shouldn&#8217;t to keep your code readable, but the following CSS works just fine and applies all the styling:</p>
<pre><code class='language-css' lang='css'>body {
  filter: blur(5px);
  
  @media all {
    background: red;
  }
    
  background: blue;
  
  @media all {
    color: deeppink;
  }
  
  rotate: 20deg;
}
</code></pre>
<p>It&#39;s when the browser parses this CSS into individual rules that the sneaky thing happens:</p>
<ol>
<li>The browser adds a new ruleset, <code>body</code>, and starts adding the properties to it/</li>
<li>The browser then adds another new ruleset for the nested media query and starts adding its properties to it/</li>
<li>When it exits the nested media query, it adds the rest of the properties to the original ruleset again until that is exited.</li>
</ol>
<p>So if we look at this CSS again:</p>
<pre><code class='language-css' lang='css'>body {
    @media all {
        background: red;
    }
    background: blue;
}
</code></pre>
<p>That actually resolves to these two rules in this specific order:</p>
<pre><code class='language-css' lang='css'>body {
    background: blue;
}
@media all {
    :is(body) {
        background: red;
    }
}
</code></pre>
<p>Now from this CSS, it makes more sense that red wins. It has the same specificity but it comes after the first rule so it wins. And that&#39;s the gotcha.</p>
<p><em>This post originally claimed that only <code>@-rules</code> could be intermingled with properties but this was incorrect. Thanks <a href="https://twitter.com/ChallengesCss/status/1668577684585164801">@ChallengesCSS</a> for correcting me.</em></p>The post <a href="https://kilianvalkhof.com/2023/css-html/the-gotchas-of-css-nesting/">The gotchas of CSS Nesting</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3225</post-id>	</item>
		<item>
		<title>:root isn&#8217;t global</title>
		<link>https://kilianvalkhof.com/2023/css-html/root-isnt-global/</link>
		
		<dc:creator><![CDATA[Kilian Valkhof]]></dc:creator>
		<pubDate>Mon, 01 May 2023 15:27:06 +0000</pubDate>
				<category><![CDATA[CSS & HTML]]></category>
		<guid isPermaLink="false">https://kilianvalkhof.com/?p=3209</guid>

					<description><![CDATA[<p>Most developers prefer to keep all their CSS custom properties in one place, and a pattern that has emerged in recent years is to put those on :root, a pseudo-class that targets the topmost element in your document (so that&#39;s always &#60;html&#62; on web pages). But just because they&#39;re in one place and in the [&#8230;]</p>
The post <a href="https://kilianvalkhof.com/2023/css-html/root-isnt-global/">:root isn’t global</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></description>
										<content:encoded><![CDATA[<p>Most developers prefer to keep all their CSS custom properties in one place, and a pattern that has emerged in recent years is to put those on <code>:root</code>, a pseudo-class that targets the topmost element in your document (so that&#39;s always <code>&lt;html&gt;</code> on web pages). But just because they&#39;re in one place and in the topmost element, it doesn&#39;t mean they&#39;re global.</p>
<p><span id="more-3209"></span></p>
<p>I first encountered this issue with <code>::backdrop</code>: <a href='https://kilianvalkhof.com/2023/css-html/backdrop-doesnt-inherit-from-anywhere/'>Backdrop doesn&#39;t inherit from anywhere</a> but after a recent rendering engine update to <a href='https://polypane.app'>Polypane</a> I noticed that all my custom selection colors (also powered by CSS custom properties) <a href='https://twitter.com/kilianvalkhof/status/1649056013495205903'>suddenly stopped working</a>. </p>
<p>Turns out, <code>::selection</code> is also not supposed to inherit styles, and Chromium 111+ is running an experiment to see what effect changing that has. Polypane runs with experimental features turned on, and so my selection styles became broken.</p>
<p>This is going to catch a lot of people off-guard because I, like many others, expect CSS Custom properties defined on <code>:root</code> to just be available everywhere.</p>
<h2 id='so-if-root-isnt-global-what-is'>So if <code>:root</code> isn&#39;t global, what is? </h2>
<p>Well, the jury&#39;s still out. </p>
<p>Discussions are happening in this GitHub issue: <a href='https://github.com/w3c/csswg-drafts/issues/6641'>Custom properties on :root</a> with a few options being discussed:</p>
<ul>
<li>Use @property with an initial value (not cross-browser supported yet, only uses the initial value).</li>
<li>Make <code>:root</code> special.</li>
<li>Create a new <code>:document</code> pseudo-class that does propagate custom properties.</li>
<li>Create an new at-rule called <code>@global</code>, <code>@root</code> or <code>@document</code>  that you could define custom properties in.</li>
<li>Make <code>::selection</code> etc inherit from their originating element (e.g. &quot;their parent&quot;).</li>
</ul>
<p>That last item would solve both the problems people run into (it not inheriting, and it potentially inheriting directly from <code>:root</code> so you can&#39;t overwrite custom properties in the cascade). I hope spec writers choose to do this regardless. </p>
<p>Specifically, I want/expect this to work:</p>
<pre><code class='language-css' lang='css'>p {
    --selection-bg: #0f0;
    &amp;::selection {
        background: var(--selection-bg);
    }
}
</code></pre>
<p>When it comes to &quot;a place to store global variables&quot; I have no strong opinion, though I think it&#39;s interesting to keep in mind that in JavaScript there is now <code>window</code>, <code>global</code> and <code>globalThis</code> because the naming across contexts didn&#39;t work. </p>
<p>In that light, <code>:document</code> or <code>@document</code> seem potentially problematic. For that reason, I like <code>@global</code> or <code>:global</code> (I haven&#39;t actually seen :global as a pseudo-class suggested yet, but it seems to be closest to how people expect things to work now). </p>
<p>In the mean time, you can use the suggestion I made in my <code>::backdrop</code> post and replace <code>:root { }</code> with <code>:root, ::backdrop, ::selection { }</code>. Sorry about that.</p>The post <a href="https://kilianvalkhof.com/2023/css-html/root-isnt-global/">:root isn’t global</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3209</post-id>	</item>
		<item>
		<title>A small JavaScript pattern I enjoy using</title>
		<link>https://kilianvalkhof.com/2023/javascript/a-small-javascript-pattern-i-enjoy-using/</link>
		
		<dc:creator><![CDATA[Kilian Valkhof]]></dc:creator>
		<pubDate>Mon, 03 Apr 2023 09:31:57 +0000</pubDate>
				<category><![CDATA[Javascript]]></category>
		<guid isPermaLink="false">https://kilianvalkhof.com/?p=3195</guid>

					<description><![CDATA[<p>There is a JavaScript pattern that I enjoy using that I don&#8217;t see a lot around the web, so I figured it would be worth sharing. When you have a piece of business logic, frequently that depends on a a certain value being true. An if statement: if ( status === 'active' ) { … [&#8230;]</p>
The post <a href="https://kilianvalkhof.com/2023/javascript/a-small-javascript-pattern-i-enjoy-using/">A small JavaScript pattern I enjoy using</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></description>
										<content:encoded><![CDATA[<p>There is a JavaScript pattern that I enjoy using that I don&#8217;t see a lot around the web, so I figured it would be worth sharing.<span id="more-3195"></span></p>
<p>When you have a piece of business logic, frequently that depends on a a certain value being true. An if statement:</p>
<pre><code class='language-javascript' lang='javascript'>if ( status === 'active' ) { … }
</code></pre>
<p>This is easy to parse for me and I can quickly see what it does. What often ends up happening though is that the business logic gets a second possibility, for example status being active or status being trialing:</p>
<pre><code class='language-javascript' lang='javascript'>if ( status === 'active' || status === 'trialing') { … }
</code></pre>
<p>This is still relatively easy to read but there&#8217;s repetition with &#8216;status&#8217; and I always need a second to think about the difference between <code>||</code> and <code>&amp;&amp;</code> to understand the behavior. So whenever I move from checking from one value to more than one, I switch to a different pattern:</p>
<pre><code class='language-javascript' lang='javascript'>if (['active', 'trialing'].includes(status)) { … }
</code></pre>
<p>I make an array of all possible values and then use <code>Array.includes()</code> to check if the status is contained in that array. </p>
<p>This pattern comfortably grows to many items and can also more easily be read aloud, helping understanding. </p>
<p>There is no repetition so as a small bonus it&#8217;s shorter. It has also helped me learn the difference between <a href='https://kilianvalkhof.com/2021/javascript/includes-contains-or-has-finding-things-in-iterables-lists-in-javascript/'>includes, contains and has</a>.</p>
<h2 id='partial-string-matching'>Partial string matching</h2>
<p>I get a lot of mileage out of the above pattern, but it only works when you&#8217;re matching the full string. Sometimes you need to check just the beginning or the end of a string and then .includes() won&#8217;t cut it because it only accepts values, not a function. </p>
<p>We don&#8217;t want to go back to multiple checks and the repetition that gives so if we need to check for a part of the string we need to change the function we use:</p>
<pre><code class='language-javascript' lang='javascript'>if (
  [&#39;http://&#39;, &#39;https://&#39;, &#39;file://&#39;, &#39;www.&#39;]
    .some(s =&gt; clipboard.startsWith(s))
) { … }
</code></pre>
<p><code>Array.some()</code> takes a function and returns a Boolean. It&#8217;s a little longer but we&#8217;re still not repeating ourselves. A nice benefit is that like <code>includes()</code> it will stop evaluating when it returns <code>true</code>, so we usually don&#8217;t have to loop over all the elements. </p>
<p>In the examples above I inlined the array but of course you can also store it in a global variable. That gives you the additional benefit of only instantiating a single array that you can reuse and that lets you update many checks in one go, should the business requirements change. </p>
<p>As I said, I get a lot of use out of this pattern. I hope this helps you recognize when it&#8217;ll be useful in your code in the future!</p>The post <a href="https://kilianvalkhof.com/2023/javascript/a-small-javascript-pattern-i-enjoy-using/">A small JavaScript pattern I enjoy using</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3195</post-id>	</item>
		<item>
		<title>I no longer understand prefers-contrast</title>
		<link>https://kilianvalkhof.com/2023/css-html/i-no-longer-understand-prefers-contrast/</link>
		
		<dc:creator><![CDATA[Kilian Valkhof]]></dc:creator>
		<pubDate>Wed, 08 Mar 2023 13:07:51 +0000</pubDate>
				<category><![CDATA[CSS & HTML]]></category>
		<guid isPermaLink="false">https://kilianvalkhof.com/?p=3179</guid>

					<description><![CDATA[<p>The prefers-contrast media query indicates whether someone prefers more or less contrast within the boundaries of your sites design. At least, that’s what I thought it meant, and it’s also how macOS seems to implement it with their ‘increase contrast’ accessibility feature. This is in contrast to the forced-colors media query, which overwrites all your [&#8230;]</p>
The post <a href="https://kilianvalkhof.com/2023/css-html/i-no-longer-understand-prefers-contrast/">I no longer understand prefers-contrast</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></description>
										<content:encoded><![CDATA[<p>The <code>prefers-contrast</code> media query indicates whether someone prefers more or less contrast within the boundaries of your sites design. At least, that’s what I thought it meant, and it’s also how macOS seems to implement it with their ‘increase contrast’ accessibility feature. This is in contrast to the <code>forced-colors</code> media query, which overwrites all your styles.<span id="more-3179"></span></p>
<p>To me it was clear that they served different purposes: one was to indicate a <em>preference</em> for an implemented design, just with more (or less) contrast, the other wanted 100% certainty that their colors were respected. Clear difference, clear implementation. </p>
<p>Except that turned out to be wrong.</p>
<p>While macOS sees <code>prefers-contrast</code> as a discrete thing, the spec (and Windows) intricately links it to <code>forced-colors</code>. There,  <code>prefers-contrast:more</code> matches when <code>forced-colors</code> with a high contrast theme is active, and <code>prefers-contrast: custom</code> is active with a contrast theme that has anything other than a full black or white background. </p>
<p>So now I’m left wondering: What on earth do spec makers expect website builders to do with <code>prefers-contrast</code>? If <code>forced-colors</code> already overwrites all the colors, what contrast is there left for us to change?</p>
<p><code>prefers-contrast</code> is a useless media query, and I don&#39;t understand why.</p>
<p>This isn’t the first time I’ve voiced concerns about <code>prefers-contrast</code>: earlier versions of the spec had a <code>forced</code> value that would match only when <code>forced-colors</code> was active. I thought this was a really dumb idea, <a href='https://kilianvalkhof.com/2021/css-html/prefers-contrast-forced-is-a-mistake/'>wrote about it</a> and to my surprise, the forced value got removed from the spec. Victory!</p>
<p>&#8230;Except they put it back as <code>custom</code> and apparently <em>retooled the entire media query</em> to match with <code>forced-colors: active</code>. </p>
<p>Worse still, the spec only mentions this in the <code>forced-colors</code> section, while the prefers contrast section only mentions <code>prefers-contrast: custom</code> matching when <code>forced-colors: active</code> matches. Under forced colors however, this is what <a href='https://drafts.csswg.org/mediaqueries-5/#forced-colors'>the latest version of the spec</a> says:</p>
<blockquote><p>In addition to <a href='https://drafts.csswg.org/mediaqueries-5/#descdef-media-forced-colors'>forced-colors: active</a>, the user agent must also match one of <a href='https://drafts.csswg.org/mediaqueries-5/#descdef-media-prefers-contrast'>prefers-contrast: more</a> or prefers-contrast: less if it can determine that the forced color palette chosen by the user has a particularly high or low contrast, and must make prefers-contrast: custom match otherwise.<br />
Similarly, if the forced color palette chosen by the user fits within one of the color schemes described by prefers-color-scheme, the corresponding value must also match.
</p></blockquote>
<p>Contrast this to what <a href='https://www.w3.org/TR/2020/WD-mediaqueries-5-20200731/#forced-colors'>the version before it</a> said:</p>
<blockquote><p>The UA will provide the color palette to authors through the CSS system color keywords and, if appropriate, trigger the appropriate value of <a href='https://www.w3.org/TR/2020/WD-mediaqueries-5-20200731/#descdef-media-prefers-color-scheme'>prefers-color-scheme</a> so that authors can adapt the page.
</p></blockquote>
<p>That&#39;s a whole new section essentially fusing <code>prefers-contrast</code> to <code>forced-colors</code>.</p>
<p>Coupling <code>forced-colors</code> and <code>prefers-contrast</code> like this completely breaks the ‘contract’ that the <code>prefers-*</code> prefix gives: <strong>a user has <em>preference</em> and it’s up to you to implement it.</strong> This is in contrast to other media queries, like <code>width</code> and, indeed, <code>forced-colors</code>, that tell us that something is a more intrinsic state of the device being used to access your site.</p>
<p><code>Prefers-*</code> in media queries is no longer something you can depend upon, and CSS is a little bit less explainable and a little less consistent.</p>
<h2 id='why-do-this'>Why do this?</h2>
<p><em>I have no idea why they decided this was a good idea.</em> Maybe the spec makers are confused by the name of ‘contrast themes’ on Windows and decided that contrast is contrast and no further research was needed? </p>
<p>I also have no any idea <strong>what to do with prefers contrast</strong>. It exists, and there is literally no reason to use it on its own. </p>
<p>This is doubly annoying for macOS, which has a very clear implementation for <code>prefers-contrast: more</code>. If you want to adapt your design for macOS, you can no longer use just that. You need to check if <code>prefers-contrast: more</code> is active, and if <code>forced-colors</code> isn’t:</p>
<pre><code class='language-css' lang='css'>@media (prefer-contrast: more) and (forced-colors: none) {
    /* Only now can you apply styling for the macOS implementation */
}
</code></pre>
<p><em>No one is going to do that</em>, and the spec makers know this because &quot;adoption being low&quot; is a common argument made by the CSS working group against <em>any</em> new media queries (like <code>prefers-reduced-complexity</code>, which is  <em>also tacked onto <code>prefers-contrast</code></em> by using it without a value). Usage being low is a great way to stop any discussion dead in the water, and is far from consistently applied throughout the specs being written.</p>
<p>So that leaves me with this: <strong>I no longer understand <code>prefers-contrast</code></strong>. I can’t explain why you would use it, I don’t know who it’s for or what developers are expected to do with it. Do you?</p>The post <a href="https://kilianvalkhof.com/2023/css-html/i-no-longer-understand-prefers-contrast/">I no longer understand prefers-contrast</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3179</post-id>	</item>
		<item>
		<title>::backdrop doesn&#8217;t inherit from anywhere</title>
		<link>https://kilianvalkhof.com/2023/css-html/backdrop-doesnt-inherit-from-anywhere/</link>
		
		<dc:creator><![CDATA[Kilian Valkhof]]></dc:creator>
		<pubDate>Thu, 19 Jan 2023 12:45:30 +0000</pubDate>
				<category><![CDATA[CSS & HTML]]></category>
		<guid isPermaLink="false">https://kilianvalkhof.com/?p=3145</guid>

					<description><![CDATA[<p>Earlier this month I was <a href='https://github.com/captainbrosset/devtools-tips/pull/48'>implementing a lightbox for devtoolstips.org</a> using <code>&#60;dialog&#62;</code>. I&#39;ll be writing about that soon but you can find the implementation in that link, it&#39;s remarkable how little code you need. While styling, I made use of the CSS custom properties that where already defined in the CSS to style the dialog and it&#39;s backdrop. Or so I thought.</p>
The post <a href="https://kilianvalkhof.com/2023/css-html/backdrop-doesnt-inherit-from-anywhere/">::backdrop doesn’t inherit from anywhere</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></description>
										<content:encoded><![CDATA[<blockquote><p> <b>December 2023 update!</b> The specification got updated to say that <code>::backdrop</code> inherits from &#8220;it&#8217;s originating element&#8221; (the <code>dialog</code> in this article). The change has been made it all three browser engines, but currently hasn&#8217;t shipped yet. Thanks <a href="https://mastodon.social/deck/@Schepp/111552629132906631">@Schepp</a> for letting me know.</a></p></blockquote>
<blockquote><p> <b>February 2024 update!</b> The specification update is now live in Polypane 18, Chromium 122, Safari 17.4 and Firefox 120!</p></blockquote>
<p>Earlier this month I was <a href='https://github.com/captainbrosset/devtools-tips/pull/48'>implementing a lightbox for devtoolstips.org</a> using <code>&lt;dialog&gt;</code>. I&#39;ll be writing about that soon but you can find the implementation in that link, it&#39;s remarkable how little code you need. While styling, I made use of the CSS custom properties that where already defined in the CSS to style the dialog and it&#39;s backdrop. Or so I thought.</p>
<p><span id="more-3145"></span></p>
<p>For some reason, the color of the backdrop wasn&#39;t what I expected, even though devtools picked up the right css var being set. It was just that the CSS var was not define. This puzzled me because it was clearly defined earlier in the CSS under the <code>:root</code> selector. So why couldn&#39;t devtools find it?</p>
<p>Turns out <code>::backdrop</code> doesn&#39;t inherit from anywhere. It says so clearly in <a href='https://fullscreen.spec.whatwg.org/#::backdrop-pseudo-element'>the spec</a>:</p>
<blockquote><p><em>&quot;It does not inherit from any element and is not inherited from.&quot;</em>
</p></blockquote>
<p>And honestly, that&#39;s pretty annoying. You&#39;ll either have to duplicate your vars in a specific declaration for <code>::backdrop</code>, or add <code>::backdrop</code> to your <code>:root</code> declaration containing all your CSS vars:</p>
<pre><code class='language-css' lang='css'>:root, ::backdrop {
    --my-var-1: #fff;
    --my-var-2: #000;
}</code></pre>
<p>If you use <code>:root</code> only to set CSS vars this isn&#39;t that much of an issue, but since it targets the <code>html</code> element anyway, I usually also add my page styling straight away.</p>
<p>Both the <code>::before</code> and <code>::after</code> pseudo elements behaved like this in the past though those got updated, and I&#39;m not sure why the same hasn&#39;t been done for <code>::backdrop</code>, it seems like an oversight.</p>
<p>In any case, <a href='https://twitter.com/fvsch/status/1611016986531618818'>Florens</a> came up with the idea of introducing a <code>:globalThis</code> in CSS, similar to <code>globalThis</code> in JavaScript, which just always refers to the global environment, be it <code>window</code>, <code>global</code> or something else. That would be a great solution for the use case of CSS custom properties that you just want available throughout your CSS. We can dream.</p>
<p>Anyway, now you know to look out for this situation. </p>
<h3 id='spread-the-word'>Spread the word</h3>
<p>Feel free to share this tweet or toot to tell other people.</p>
<div style="display:flex;gap:1rem;flex-direction:column;align-items: center;">
<blockquote class="twitter-tweet">
<p lang="en" dir="ltr">TIL that ::backdrop does not inherit from anywhere, which means CSS custom properties added to :root won&#39;t work for it.</p>
<p>The spec: <a href="https://t.co/YHstFAjQc1">https://t.co/YHstFAjQc1</a> <a href="https://t.co/w1d8tEwUyi">pic.twitter.com/w1d8tEwUyi</a></p>
<p>&mdash; Kilian Valkhof (@kilianvalkhof) <a href="https://twitter.com/kilianvalkhof/status/1610969364987011073?ref_src=twsrc%5Etfw">January 5, 2023</a></p></blockquote>
<p> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script><iframe src="https://mastodon.social/@Kilian/109637254769580233/embed" class="mastodon-embed" style="max-width: 100%; border: 0" width="400" allowfullscreen="allowfullscreen"></iframe><script src="https://static-cdn.mastodon.social/embed.js" async="async"></script></div>The post <a href="https://kilianvalkhof.com/2023/css-html/backdrop-doesnt-inherit-from-anywhere/">::backdrop doesn’t inherit from anywhere</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3145</post-id>	</item>
		<item>
		<title>I was on the Syntax.fm podcast to talk about Polypane</title>
		<link>https://kilianvalkhof.com/2023/web/i-was-on-the-syntax-fm-podcast-to-talk-about-polypane/</link>
		
		<dc:creator><![CDATA[Kilian Valkhof]]></dc:creator>
		<pubDate>Wed, 04 Jan 2023 09:37:05 +0000</pubDate>
				<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://kilianvalkhof.com/?p=3139</guid>

					<description><![CDATA[<p>Last Friday I went on the Syntax.fm Supper Club podcast to chat with Scott and Wes about everything Polypane. We go pretty deep into some of the features and in hindsight it&#8217;s funny how most of it boils down to &#8220;I needed this feature so I built it&#8221;. I had a great time geeking out [&#8230;]</p>
The post <a href="https://kilianvalkhof.com/2023/web/i-was-on-the-syntax-fm-podcast-to-talk-about-polypane/">I was on the Syntax.fm podcast to talk about Polypane</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></description>
										<content:encoded><![CDATA[<p>Last Friday I went on the Syntax.fm Supper Club podcast to chat with Scott and Wes about everything <a href="https://polypane.app">Polypane</a>. We go pretty deep into some of the features and in hindsight it&#8217;s funny how most of it boils down to &#8220;I needed this feature so I built it&#8221;. I had a great time geeking out about it so thank you Scott and Wes for having me!<span id="more-3139"></span></p>
<p>You can find the episode and show notes here: <a href="https://syntax.fm/show/556/supper-club-polypane-with-kilian-valkhof">Supper Club × Polypane with Kilian Valkhof</a>. Fingers crossed someone can help me and Scott out with my &#8220;Sick Pick&#8221; ;)</p>The post <a href="https://kilianvalkhof.com/2023/web/i-was-on-the-syntax-fm-podcast-to-talk-about-polypane/">I was on the Syntax.fm podcast to talk about Polypane</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3139</post-id>	</item>
		<item>
		<title>My experience at Modern Frontends</title>
		<link>https://kilianvalkhof.com/2022/web/my-experience-at-modern-frontends/</link>
		
		<dc:creator><![CDATA[Kilian Valkhof]]></dc:creator>
		<pubDate>Thu, 24 Nov 2022 14:19:26 +0000</pubDate>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://kilianvalkhof.com/?p=3088</guid>

					<description><![CDATA[<p>Sometimes we want something to be true so badly, we ignore all the red flags. I had only spoken at this big of a conference once, and that was mostly by accident. So when my CFP got accepted to Modern Frontends, I was elated. A huge conference, in London, surrounded by amazing speakers. As you&#8217;ve [&#8230;]</p>
The post <a href="https://kilianvalkhof.com/2022/web/my-experience-at-modern-frontends/">My experience at Modern Frontends</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></description>
										<content:encoded><![CDATA[<p>Sometimes we want something to be true so badly, we ignore all the red flags. I had only spoken at this big of a conference once, and that was mostly by accident. So when my CFP got accepted to Modern Frontends, I was elated. A huge conference, in London, surrounded by amazing speakers.<span id="more-3088"></span></p>
<p>As you&#8217;ve probably read elsewhere by now, that feeling obviously didn&#8217;t stay with me.</p>
<p>Still, I&#8217;ve pondered writing an article of my own. The run-up to the conference was full of red flags that I could write up that would&#8217;ve been somewhat interesting as a cautionary tale.</p>
<p>My interactions with the organiser, a woman named Gen Ashley, had been few and always somewhat antagonistic. At the time I thought it was just a result of the huge undertaking a conference like this is. I myself also aren&#8217;t the kindest person when under stress. Whatever, we&#8217;re all human.</p>
<p>But my experience has been far easier compared to what other speakers, all of the attendees and sponsors had to go through.</p>
<p>I got lucky. I got my travel and hotel paid for. I had a full room listen to me. I very much enjoyed meeting people I had only interacted with online before and chatting with speakers and attendees I hadn&#8217;t known before at all. I&#8217;m Dutch, so any lunch that&#8217;s above a piece of bread with a slice of cheese just registers as &#8220;fancy&#8221; in my head. I can&#8217;t help it. A cheese sandwich with green bits sticking out of it? Boom. Fancy.</p>
<p>I decided pretty early on (honestly, after Cassie bowed out and the red flags <i>really</i> started stacking up) to accept whatever was gonna happen and make the best of it. As a speaker, I owe that to every person that comes to listen to what I have to say.</p>
<p>Others weren&#8217;t as lucky as I was. Speakers paid out-of-pocket based on the promise of speaking in front of hundreds, if not thousands of people, and ended up speaking to a few. Attendees paid upward of 600 pound to attend, for something that should&#8217;ve been a year-closing celebration of the web community. Sponsors likewise anticipated interacting with thousands of devs, and from what I&#8217;ve understood, paid in accordance.</p>
<p>I can underwrite everything <a href="https://www.cassie.codes/posts/modern-frontends/">Cassie</a>, <a href="https://dev.to/thisisjofrank/my-experience-of-modern-frontends-conference-1cgg">Jo</a>, <a href="https://hidde.blog/modern-frontends-live/">Hidde</a>, <a href="https://kentcdodds.com/blog/my-modern-frontends-live-experience">Kent</a>, <a href="https://toddl.dev/posts/modern-frontends/">Todd</a>, <a href="https://dev.to/niamhmccoo/my-experience-at-modern-frontends-live-1lcn">Niamh</a>, <a href="https://jdhillen.com/blog/my-experience-at-modern-frontends-live/">JD</a>, <a href="https://christopherallanperry.github.io/blog/2022/11/20/modern_frontends-an_attendees_perspective.html">Chris</a>, <a href="https://mhartington.io/post/modern-frontends-live/">Mike</a>, <a href="https://www.youtube.com/watch?v=Ekn-qiH8Ozw">Vladyslav</a>, <a href="https://twitter.com/pattyneta/status/1595495394557022208">Patty</a>, <a href="https://dylanbeattie.net/2022/11/22/modern-frontends-2022.html">Dylan</a> and <a href="https://www.youtube.com/watch?v=CHJrO8TvNjI">James</a> have said, and want to explicitly focus your attention to Cassie and Jo, who very early on made very clear statements, risking ire and being labeled troublemakers (they&#8217;re not, except in the very best way!) They&#8217;re brave and we owe them.</p>
<p>So go and read the experiences linked up there. None of them are exaggerated. What happened was disgraceful and fraudulent. <strong>The only reason the conference went as smoothly as it did was that every single speaker decided to be there for the attendees and give their best</strong>, even if that did mean managing essentially everything not handled by the conference center.</p>
<p>The reason I ended up writing something anyway is because the organisers next event is already lined up, and it looks like they&#8217;re gonna try and do the same trick again. It&#8217;s called <a href="https://www.techknowday.com/ ">tech(k)now day</a>.</p>
<p><a href="https://twitter.com/cassiecodes/status/1595711878734516224">You should probably not go there</a>.</p>
<p><strong>And that sucks</strong>, because it has a fantastic, all female (and non-binary) lineup. Hosting a conference featuring and celebrating an underrepresented group is admirable and awesome, but only if you don&#8217;t exploit that group at the very same time. It seems she&#8217;s treating them as poorly as she did some of the speakers at Modern Frontends and they don&#8217;t deserve that.</p>
<p>They deserve better, and we as a community also deserve better. So don&#8217;t let her get away with it.</p>The post <a href="https://kilianvalkhof.com/2022/web/my-experience-at-modern-frontends/">My experience at Modern Frontends</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3088</post-id>	</item>
		<item>
		<title>Screenshotting VoiceOver on macOS</title>
		<link>https://kilianvalkhof.com/2022/accessibility/screenshotting-voiceover-on-macos/</link>
		
		<dc:creator><![CDATA[Kilian Valkhof]]></dc:creator>
		<pubDate>Mon, 31 Oct 2022 13:19:25 +0000</pubDate>
				<category><![CDATA[Accessibility]]></category>
		<guid isPermaLink="false">https://kilianvalkhof.com/?p=3070</guid>

					<description><![CDATA[<p>For an article I was writing I wanted to create a quick screenshot of one of the Rotor screens that Voiceover on macOS shows. I couldn&#39;t because when you have VoiceOver active the screenshot shortcuts (cmd + shift + 3/4) no longer work because they&#39;re captured by VoiceOver instead. If you also have this problem, [&#8230;]</p>
The post <a href="https://kilianvalkhof.com/2022/accessibility/screenshotting-voiceover-on-macos/">Screenshotting VoiceOver on macOS</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></description>
										<content:encoded><![CDATA[<p>For an article I was writing I wanted to create a quick screenshot of one of the Rotor screens that Voiceover on macOS shows. I couldn&#39;t because when you have VoiceOver active the screenshot shortcuts (<kbd>cmd + shift + 3/4</kbd>) no longer work because they&#39;re captured by VoiceOver instead. If you also have this problem, you can use the <code>screencapture</code> command line tool.</p>
<p><span id="more-3070"></span></p>
<p><img decoding="async" src="https://kilianvalkhof.com/wp-content/uploads/landmark-1024x376.png" alt="VoiceOver Landmark overview of the HTMHell.dev website." /></p>
<h2 id='screencapture'>Screencapture</h2>
<p><code>Screencapture</code> is a command-line interface to all the screenshot and screen capturing tools that are built into macOS, and that will let use screenshot VoiceOver because you can create a screenshot with a delay using the following:</p>
<pre>$ screencapture <span class="cm-attribute">-T10</span> filename.png</span></pre>
<p><code>-T</code> is the command line flag to set a timeout, and <code>10</code> is the number of seconds it should wait. Lastly, <code>filename.png</code> is what it should save the resulting screenshot as. If you don&#39;t want to save, you can replace the filename with <code>-c</code> to copy the result to clipboard instead</p>
<h3 id='steps'>Steps</h3>
<ol>
<li>The first time <code>screencapture</code> is called, your Mac will show a popup asking you if you want to give your terminal access to screen recording. Make sure to allow it, otherwise it won&#39;t be able to make screenshots.</li>
<li>Then, start a screencapture with enough time to configure VoiceOver to look the way you want it to look. I defaulted to 10 seconds, you might be faster.</li>
<li>Open VoiceOver (<kbd>cmd + F5</kbd>) and then open the Rotor (<kbd>ctrl + alt + u</kbd>) and use the arrow keys to go to the view you want to show. </li>
<li>Wait until screencapture is done, find your image in the folder you saved it in.</li>
</ol>
<p>Unfortunately I haven&#39;t found a way yet to capture just the Rotor as an image, because when you configure <code>screencapture</code> to capture a window instead (with <code>-W</code>) the timeout is discarded. So the above will make a screenshot of your entire desktop, and you&#39;ll have to crop it yourself.</p>
<p>If you&#39;ve been photographing your mac screen to get images of VoiceOver in action, I hope this helps! To get an overview of everything screencapture can do, you can execute <code>screencapture -h</code> to show the help page.</p>
<h3>Update: capturing just the Rotor</h3>
<p>After sharing this in the Fronteers Slack community, <a href="https://twitter.com/veyfeyken">Gijs</a> mentioned there was a way to capture the rotor as a standalone image:</p>
<ul>
<li>Open VoiceOver (<kbd>cmd + F5</kbd>).</li>
<li>Press <kbd>shift cmd 4</kbd> to start a screenshot capture.</li>
<li>Press Spacebar to switch to Window mode.</li>
<li>Open the Rotor (<kbd>ctrl + alt + u</kbd>) and navigate to desired dialog with arrow keys</li>
<li>Hover over the rotor with the mouse so it turns blue (indicating it&#8217;s selected for the screenshot).</li>
<li>Click or press enter to capture screenshot.</li>
</ul>
<p>This definitely works but it&#8217;s also very finnicky. If you do anything out of order you will either not be able to switch to window selection mode or you won&#8217;t be able to navigate in the rotor. Making a screenshot with a delay is a little more forgiving, but you won&#8217;t end up with an image of just the rotor.</p>
<h3>Another update: Screenshot tool in Dock</h3>
<p>This one is by <a href="https://sprungmarker.de">Sylvia</a></p>
<ul>
<li>Open Launchpad</li>
<li>Search for Screenshot</li>
<li>Drag the Screenshot tool to your dock</li>
<li>Open Rotor in VoiceOver</li>
<li>Click on Screenshot-Tool in your dock</li>
<li>Make a Screenshot with this tool</li>
</ul>
<p>Thanks Sylvia!</p>The post <a href="https://kilianvalkhof.com/2022/accessibility/screenshotting-voiceover-on-macos/">Screenshotting VoiceOver on macOS</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3070</post-id>	</item>
		<item>
		<title>When going somewhere does a thing: on links and buttons</title>
		<link>https://kilianvalkhof.com/2022/css-html/when-going-somewhere-does-a-thing-on-links-and-buttons/</link>
		
		<dc:creator><![CDATA[Kilian Valkhof]]></dc:creator>
		<pubDate>Tue, 04 Oct 2022 08:31:27 +0000</pubDate>
				<category><![CDATA[Accessibility]]></category>
		<category><![CDATA[CSS & HTML]]></category>
		<guid isPermaLink="false">https://kilianvalkhof.com/?p=3042</guid>

					<description><![CDATA[<p>At the Fronteers conference, Manuel during his presentation did an exercise on building HTML that seemed fairly straightforward. On the site of Max Böck there&#39;s a thing you can click to open up a theme selector. What&#39;s that thing? Of course, it&#39;s a button! Because it opens the theme selector at the top of the [&#8230;]</p>
The post <a href="https://kilianvalkhof.com/2022/css-html/when-going-somewhere-does-a-thing-on-links-and-buttons/">When going somewhere does a thing: on links and buttons</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></description>
										<content:encoded><![CDATA[<p>At the Fronteers conference, <a href="https://www.matuzo.at">Manuel</a> during his presentation did an exercise on building HTML that seemed fairly straightforward. On the <a href="https://mxb.dev">site of Max Böck</a> there&#39;s a <em>thing</em> you can click to open up a theme selector. What&#39;s that thing?<span id="more-3042"></span></p>
<p>Of course, it&#39;s a button! Because it opens the theme selector at the top of the page. <em>It does something!</em> Add an aria-expanded to the button, make sure focus is set and you&#39;re good to go. It&#39;s <em>obviously</em> a button.</p>
<p>But what if it&#39;s not?</p>
<p>After Manuels excellent talk I was discussing this with a group of folks and I was adamant that it obviously was <em>a button</em> because it clearly <em>opened a thing</em> but&#8230; I didn&#39;t have a great argument for why it also couldn&#39;t also be a link. After all, all the arguments for a link are pretty sound. It stuck with me and in this article I want to explore both.</p>
<h2 id="when-to-use-links-and-buttons">When to use links and buttons</h2>
<p>The &quot;common&quot; logic for when to use links or buttons is as follows:</p>
<ol>
<li>If it goes somewhere, it&#39;s a link.</li>
<li>If it does something, it&#39;s a button.</li>
</ol>
<p>But if you ask me, those two things aren&#8217;t always mutually exclusive. I&#39;ll give implementation examples of both that I think are fine.</p>
<h2 id="what-were-building">What we&#39;re building</h2>
<p>The functionality we&#39;re building is the following: The top right button on <a href="https://mxb.dev">mxb.dev</a> opens a theme selector at the top of the page, and the theme selector has a close button that closes it again. That&#39;s it. Here&#39;s a video:</p>
<div style="width: 800px;" class="wp-video"><!--[if lt IE 9]><script>document.createElement('video');</script><![endif]-->
<video class="wp-video-shortcode" id="video-3042-1" width="800" height="360" preload="metadata" controls="controls"><source type="video/mp4" src="https://kilianvalkhof.com/wp-content/uploads/linkbutton.mp4?_=1" /><a href="https://kilianvalkhof.com/wp-content/uploads/linkbutton.mp4">https://kilianvalkhof.com/wp-content/uploads/linkbutton.mp4</a></video></div>
<h2 id="using-a-button">Using a button</h2>
<p>This is the example Manuel gave and it&#39;s essentially the same as what I wrote in <a href="https://polypane.app/blog/the-perfect-responsive-menu/">The perfect responsive menu</a>.</p>
<p>The button looks like this:</p>
<pre><code class="language-html">&lt;button aria-expanded=&quot;false&quot; aria-controls=&quot;theme-selector&quot;&gt;
    Open Theme Selector
&lt;/button&gt;
</code></pre>
<p>and the theme selector looks like this:</p>
<pre><code class="language-html">&lt;div id=&quot;theme-selector&quot; hidden=&quot;true&quot;&gt;
  … pretend there's a theme controller here
  &lt;button aria-expanded=&quot;false&quot; aria-controls=&quot;theme-selector&quot;&gt;
    Close
  &lt;/button&gt;
&lt;/div&gt;
</code></pre>
<p>Then when clicking the button, using javascript, the <code>hidden</code> attribute of <code>theme-selector</code> is removed, the <code>aria-expanded</code> of the button is set to true, the JS moves the focus to the theme selector and then adds some CSS makes the theme selector appear (in the live implementation it&#39;s using an additional class, but you could also use the <code>[hidden]</code> attribute being there or not instead).</p>
<p>In the theme selector, we have a close button that does the same in reverse.</p>
<p>Here&#39;s how it works in a codepen:</p>
<p class="codepen" data-height="300" data-theme-id="light" data-default-tab="result" data-slug-hash="jOxKbBx" data-user="Kilian" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/Kilian/pen/jOxKbBx"><br />
  Button opening theme selector</a> by Kilian Valkhof (<a href="https://codepen.io/Kilian">@Kilian</a>)<br />
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<h2 id="using-a-link">Using a link</h2>
<p>Okay, here we go. Why this can be a link: Links <em>go somewhere</em>, including different parts of the same page. So we can add a link that goes to <code>#theme-selector</code>:</p>
<pre><code class="language-html">&lt;a href=&quot;#theme-selector&quot; id=&quot;theme-selector-controller&quot;&gt;
    Open Theme Selector
&lt;/a&gt;
</code></pre>
<p>Using the <code>:target</code> pseudo-class, we can make the theme controller appear after clicking the link:</p>
<pre><code class="language-css">#theme-selector:target {
  display: block;
}
</code></pre>
<p>This will make the theme selector stay open while we interact with it. Inside <code>#theme-selector</code> we add a second link that links back to our original button:</p>
<pre><code class="language-html">&lt;a href=&quot;#theme-selector-controller&quot;&gt;
    Close Theme Selector
&lt;/a&gt;
</code></pre>
<p>After clicking that, the <code>#theme-selector</code> no longer matches the target, so it&#39;s hidden again. You can see it in action here:</p>
<p class="codepen" data-height="300" data-theme-id="light" data-default-tab="result" data-slug-hash="wvjXKmp" data-user="Kilian" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/Kilian/pen/wvjXKmp"><br />
  Button opening theme selector</a> by Kilian Valkhof (<a href="https://codepen.io/Kilian">@Kilian</a>)<br />
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<p><script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script></p>
<h3 id="whats-wrong-with-the-link-solution">What&#39;s wrong with the link solution?</h3>
<p>The browser gives us all the building block for a link solution. It works without javascript and as far as I can tell, the accessibility is decent too: using <code>display</code> means the theme selector is hidden from assistive technologies and the browser itself makes sure the focus is managed.</p>
<p>The only things you lose is that the &quot;button&quot; is no longer aware of the expanded status and can&#8217;t be used as a toggle anymore. The toggle functionality I don&#8217;t have a solution for, but you could also say that now that the browser is maintaining a <code>target</code> that&#39;s what holds that status.</p>
<p>In short, it&#39;s simple, doesn&#39;t need javascript, manages focus and the link clearly <em>goes somewhere</em>. It follows all the rules. </p>
<p>So why do I still prefer the (much more complex!) button example?</p>
<h3>Addendum</h3>
<p>Here&#8217;s what <a href="https://benmyers.dev/">Ben</a> had to say about this: the above is accurate, but it&#8217;s not something he would recommend in practice for a few reasons:</p>
<ul>
<li>Buttons can explicitly convey the expanded/collapses state, which is useful information in itself.</li>
<li>Links and buttons have different keyboard triggers (both can be triggered with <kbd>enter</kbd> but buttons can also be activated with a <kbd>space</kbd>) and if you&#8217;re a sighted used, you might expect a button and be surprised when <kbd>space</kbd> does nothing.</li>
</ul>
<p>He also brought up the point of links opening in a new tab when you middle-click. Does it make sense to have that functionality on a new tab?</p>
<p>All in all, he helped me understand why I still preferred the button and explained it as such: <q>links are a semantically okayish way to do this; buttons are a more semantic way to do it</q>. Thanks Ben!</p>
<p><em>Thanks to <a href="https://www.matuzo.at">Manuel</a> and <a href="https://benmyers.dev/">Ben</a> for feedback on drafts of this article.</em></p>The post <a href="https://kilianvalkhof.com/2022/css-html/when-going-somewhere-does-a-thing-on-links-and-buttons/">When going somewhere does a thing: on links and buttons</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></content:encoded>
					
		
		<enclosure url="https://kilianvalkhof.com/wp-content/uploads/linkbutton.mp4" length="326419" type="video/mp4" />

		<post-id xmlns="com-wordpress:feed-additions:1">3042</post-id>	</item>
		<item>
		<title>On better browsers: arbitrary media queries and browser UIs</title>
		<link>https://kilianvalkhof.com/2022/css-html/on-better-browsers-arbitrary-media-queries-and-browser-uis/</link>
		
		<dc:creator><![CDATA[Kilian Valkhof]]></dc:creator>
		<pubDate>Wed, 14 Sep 2022 14:11:44 +0000</pubDate>
				<category><![CDATA[CSS & HTML]]></category>
		<guid isPermaLink="false">https://kilianvalkhof.com/?p=3027</guid>

					<description><![CDATA[<p>This morning Kitty Giraudel tweeted about an imaginary media query that would indicate right- or left-handedness and it made me imagine a future where sites can register support for one or more media features through a browser API, and the browser would offer these options in the UI. Two years ago I requested something similar [&#8230;]</p>
The post <a href="https://kilianvalkhof.com/2022/css-html/on-better-browsers-arbitrary-media-queries-and-browser-uis/">On better browsers: arbitrary media queries and browser UIs</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></description>
										<content:encoded><![CDATA[<p>This morning <a href='https://twitter.com/KittyGiraudel/status/1569953805986570241'>Kitty Giraudel tweeted</a> about an imaginary media query that would indicate right- or left-handedness and it <a href='https://twitter.com/kilianvalkhof/status/1569955314698522624'>made me imagine a future</a> where sites can register support for one or more media features through a browser API, and the browser would offer these options in the UI.<span id="more-3027"></span> </p>
<p>Two years ago I requested something similar to the Chromium team: making it possible to <a href='https://bugs.chromium.org/p/chromium/issues/detail?id=1058326&amp;q=kilianvalkhof&amp;can=1'>emulate arbitrary media queries in the devtools</a>. At the time I also wrote about that on this blog: <a href='https://kilianvalkhof.com/2020/web/i-want-my-own-media-queries-in-browsers/'>I want my own media queries in browsers</a></p>
<p>That never went anywhere, but this is more or less a continuation of that thought. Combining it with Kitty&#39;s imaginary &quot;prefers-main-side&quot;, and the idea that browsers should expose media query settings on a per-origin basis like page zoom, here&#39;s an idea that would be even more amazing to have in browsers:</p>
<h2 id='arbitrary-media-feature-support'>Arbitrary media feature support</h2>
<p>What if a site could register a media feature:</p>
<pre><code class='language-javascript' lang='javascript'>window.registerMediaFeature({
    name: &quot;prefers-main-side&quot;, 
    options: [&#39;right&#39;, &#39;left&#39;],
    default: &#39;right&#39;,
});
</code></pre>
<p>After which a browser would:</p>
<ul>
<li>Understand the media feature in your CSS</li>
<li>Match the default value and apply the CSS</li>
<li>Provide an appropriate toggle UI in the address bar</li>
</ul>
<p>This doesn&#8217;t just give you more ways to offer a customized experience for your visitors, at the same time this frees up real estate on the site itself because it no longer has to reserve space to provide a fully custom UI.</p>
<p>It should work both for known media features, like <code>prefers-color-scheme</code>, completely imagined ones like <code>prefers-main-side</code>, or not-yet-implemented features like <code>prefers-reduced-transparency</code>. </p>
<h3 id='overwriting-known-media-queries'>Overwriting known media queries</h3>
<p>Furthermore, it should allow overwriting the <em>values</em> of known media features to provide more options. For example, Twitter comes with two dark modes: &quot;dim&quot; and &quot;lights out&quot;. <code>prefers-color-scheme</code> only has &quot;light&quot; and &quot;dark&quot;, so they would extend prefers-color-scheme with a new value, and update the names to match their brand:</p>
<pre><code class='language-javascript' lang='javascript'>window.registerMediaFeature({
  name: &quot;prefers-color-scheme&quot;, 
  options: {
    light: &quot;Default&quot;,
    dim: &quot;Dim&quot;
    dark: &quot;Lights out&quot;,
  }
  default: &#39;light&#39;,
});
</code></pre>
<p>This way, a browser could still match the OS level setting (light or dark) to the options offered by Twitter as well as provide a UI to switch to &quot;Dim&quot;, allowing Twitter to get rid of a piece of custom in-page UI that does the same thing.</p>
<h2 id='ui'>UI</h2>
<p>The browser UI could be exposed in a dropdown similar to how <a href='https://polypane.app'>Polypane</a> has been showing it for a while, with big toggles that make it easy to see both which options have been selected as well as which options there are. </p>
<p><img decoding="async" src="https://kilianvalkhof.com/wp-content/uploads/Selection_1300-1024x506.png" alt="The Polypane UI with a list of media feature toggles visible" style="width:100%;border-radius:4px;" /></p>
<p>Browsers could automatically detect usage of regular media features and show those in the same UI, <a href='https://www.stefanjudis.com/notes/should-browsers-offer-per-site-user-preferences/'>storing the selection per-origin</a>. That way the choices a user made will get remembered next time they visit your site.</p>
<p>To prevent abuse, a website could ask for permission before they&#39;re allowed to register media features, or they could be limited to a fixed number of registered media features. <strong>Edit:</strong> <a href="https://darthmall.net/about/">Evan</a> suggested explicitly mentioning that the options would be same-origin restricted to prevent them from being used for fingerprinting.</p>
<p>But that&#39;s getting ahead of myself. What do you think of the concept? <a href='https://twitter.com/kilianvalkhof/status/1569955314698522624'>Reply on Twitter</a> with your thoughts!</p>
<p><strong>Update</strong> Looks like Kitty wrote about it themselves too: <a href="https://kittygiraudel.com/2022/09/14/dominant-hand-respecting-design/">Dominant hand respecting design</a> and they came up with a very similar API (though I think their use of the CSS global is better!):</p>
<pre><code class='language-javascript' lang='javascript'>CSS.registerMedia({
  name: 'prefers-dominant-hand',
  syntax: 'start | end | no-preference',
  initialValue: 'no-preference',
})
</code></pre>
<p>Now we just need to get the browsers on board ;)</p>The post <a href="https://kilianvalkhof.com/2022/css-html/on-better-browsers-arbitrary-media-queries-and-browser-uis/">On better browsers: arbitrary media queries and browser UIs</a> first appeared on <a href="https://kilianvalkhof.com">Kilian Valkhof</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3027</post-id>	</item>
	</channel>
</rss>
