<rss version="2.0">
  <channel>
    <title>QuirksBlog</title>
    <link>https://quirksmode.org/quirksblog/</link>
    <description>ppk's blog since 2003</description>
    <item>
      <title>Safari :has(:empty) bug</title>
      <link>https://quirksmode.org/quirksblog/2026/0410-bugreport.html</link>
      <pubDate>2026-04-10T07:00:00+02:00</pubDate>
      <description><![CDATA[<p>This week I spent too much time on a <a href="/browserbugs/safari-has-empty.html">Safari :has(:empty) bug</a> &#8212; my first bug report in at least five years. I did it mostly to prove I could still do it. The Safari team <a href="https://github.com/WebKit/WebKit/pull/62402" class="external">already fixed</a> the bug, so this report helped a bit.</p>

<p>A month ago I I created a <a href="spelverkoop/" hreflang="nl">sales page</a> to sell about two-thirds of my board game collection. (If you're in Amsterdam and want to buy one of them, hey, let's talk!) I show sold games in a separate table until they&#8217;re actually collected &#8212; and I decided to hide that table if it contained no data.</p>

<pre>
main:has(tbody:empty){
	display: none;
}</pre> 

<p>Isn't CSS cool nowadays?</p>

<p>Except in Safari (Mac and iOS). No content at all was visible. Unless you resized the page. Vertically.</p>

<p>It says something shameful about my testing habits that it took me a month to notice. Then again, it was browser bug #32820 or so in my professional career.</p> 

<p>(Meanwhile I removed the offending rule, so you can only see the bug on the <a href="/browserbugs/safari-has-empty.html">bug report page</a>.)</p>

<h3>The bugs these days</h3>

<p>The problem is, I'm just not very impressed by today&#8217;s browser bugs. The ones we had 25 years ago, when Netscape and IE battled it out, now <em>those</em> were the real deal! And they remained bugs for <em>years</em>. Nobody fixed bugs within 24 hours.</p>

<p>But today&#8217;s web developers start crying as soon as pretty much anything goes even slightly wrong, and I simply don&#8217;t take the silly yelling youngsters who encounter My First Very Minor Browser Cncompatibility seriously. And no, I&#8217;m not old.</p>

<p>This goes beyond a minor incompatibility, though. A selector that should work doesn&#8217;t work. On <em>my</em> page. Somebody really should do something.</p>

<p>Was that somebody going to be me? Did I feel like solving the bug, as I did in the good old days? Or would I just remove the offending selector and let it be?</p>

<p>To my surprise, I wanted to prove I could still solve a browser bug. I mean, I have this huge brain lobe dedicated to browser incompatibilities, but it kind of atrophied in the past ten years. Could it still handle a juicy bug?</p>

<p>It could. Actually, the process went fairly smoothly and was enjoyable, and I even found a partial workaround. 

<h3>Findings</h3>

<p>My findings, summarised:</p>

<ul>
	<li><code>y:has(x:empty)</code> or <code>:has(x:empty) y</code> is checked for emptiness only once, between DOMContentLoaded and load.
	<li>Emptiness is resolved incorrectly if element <code>x</code> is filled by a JavaScript onload AND the body  overflows the html vertically, but not horizontally.
	<li>If this is the case AND element y has CSS lengths in viewport units AND element x is currently filled, resizing the window updates the styles of element y &#8212; permanently.
	<li>A special case applies if <code>y</code> has <code>display: none</code>, as it had in my original page. See <a href="/browserbugs/safari-has-empty.html">the report</a>.
</ul>

<p>From the <a href="https://github.com/WebKit/WebKit/pull/62402" class="external">fix</a> it appears that the problem was simply that <code>:has</code> was not updated after the <code>:empty</code> state changed. Initially I assumed that that was the case, but the wealth of extra bits and pieces of bug I found made it appear it was much more complicated. (I&#8217;ve never been able to figure out which of these details are important and which ones merely obscure the truth, but I tend to err on the side of over-reporting.)</p>

<h4>Workaround</h4>

<p>Adding a non-<code>:has</code> selector such as the one below fixes the bug. It needs a CSS declaration, but that can just be a variable that you never use. It has to contain the <code>:empty</code> element and select your <code>y</code> element, like this:</p>


<pre>
x:empty ~ * {
	--bug: 'solved';
}

:has(x:empty) y {
	// works!
}
</pre>

<p>This may not always work. In particular, it doesn't work for my original use case since I can&#8217;t write a selector for <code>main</code> that also touches <code>tbody:empty</code> without using <code>:has</code>.</p>

<pre>
main tbody:empty {
	// doesn't work
	// selects tbody instead of main
}

main:has(tbody:empty){
	display: none;
}</pre> 

<p>In order to truly solve the problem you&#8217;d have to remove the <code>:has(:target)</code>, I&#8217;m afraid &#8212; so that&#8217;s what I did on my page. All the better that the bug has been solved.</p>

<h3>Time and money</h3>

<p>The process took me about eight hours: six for the research, and two for the report writing interspersed with some research &#8212; for instance, the workaround came from an idea I had fairly late in the writing process. And that doesn&#8217;t count writing this blog post.</p>

<p>Although I don&#8217;t regret spending a working day on this bug, it&#8217;s not something I&#8217;m going to do a lot of. I mean, conference catering proposals don&#8217;t check themselves, and sponsors and speakers need gentle reminders every now and then. This week I did less conference work than I had planned.</p>

<p>And this sort of bug squashing doesn&#8217;t make you any money. That&#8217;s part of the problem &#8212; it always has been.</p>

<p>But still, it was fun. It&#8217;s good to be back.</p>]]></description>
    </item>
    <item>
      <title>Conference organising in 2026</title>
      <link>https://quirksmode.org/quirksblog/2026/0407-conferences.html</link>
      <pubDate>2026-04-07T07:00:00+02:00</pubDate>
      <description><![CDATA[<p>If you've been following any conference organisers at all, you'll know that we have a  much tougher job than ever before and complain loudly. Tickets are more difficult to sell these days &#8212; not only because fewer people buy them, but also because they buy them much later.</p>

<p>Until a year ago my conferences were exempt from this trend, but starting with <a href="https://perfnow.nl/" class="external">performance.now()</a> 2025 ticket sales became a lot more difficult. perf 25 didn't sell out, not even close, and that was a first. It was the sponsors that pulled the conference through &#8212; thank you for that!</p>

<p>Now that we're at the half-way point for <a href="https://cssday.nl" class="external">CSS Day 2026</a> I can say we're definitely behind CSS 2025, though the situation is not as disastrous as for perf 25. It's quite conceivable sales will become better &#8212; these last three weeks are already better than the previous seven, and there <em>will</em> be late sales, no matter what. Still, my (as-yet unexplained) immunity to industry trends is over.</p>

<p>There are several lessons to be drawn from this.</p>

<p>From 2022 to about a year ago my theory was that CSS Day and performance.now() are focused, specialised conferences, while most of the complaining conferences were general ones. It seemed logical to me: specialise, and you'll attract specialists who won't go to a general web conference, and your ticket sales will remain strong. Now I find that this theory is not necessarily correct.</p>

<h3>Cash flow</h3>

<p>This year I'm implementing a solution that I've been talking about for ages with other conference organisers: more expensive late tickets. As an example, currently CSS 26 <a href="https://cssday.nl/tickets.html" class="external">tickets</a> are €675, but on 14th of May, a month before the conference, that price will go up to €750. See it as a lateness tax. I'm planning something similar for perf 26, but probably even more aggressive with three tiers instead of two.</p>

<p>I'm not very worried about sales effects: the number of people for whom €750 is a serious financial issue but €675 is not is probably negligible compared to people who have the budget anyway but are just late. (Or these might be famous last words, we'll see.)</p>

<p>Still, in addition to the total sales there's also the issue of sales timing. Right now I do not dare to order a barista or captioning for CSS Day. Attendees tend to really like them, but strictly speaking they're luxuries. When ticket sales are as unpredictable as they are now I balk at spending the extra ~€9K they would cost, though. If sales pick up considerably (or I find <a href="https://cssday.nl/sponsorships.html" class="external">sponsors</a>) I'll do it, but there's a practical time limit as well.

<p>From about a month before the conference it's no longer really possible to place an order, since my favourite captioners and baristas will have accepted other jobs. So it's not just about the size of the cash flow, but also about its timing. And that's what makes late ticket orders such a problem. It's quite possible that, in hindsight, I could have afforded a barista and captioning, but the ticket sales just came too late.</p>

<h3>Sponsors</h3>

<p>It's hard to find CSS Day sponsors. Fortunately that does not go for performance.now(): barista and captioning are already covered by sponsorship contracts &#8212; and it's possible that once more it's the sponsors, and not the ticket sales, that will pull the conference through.</p>

<p>The problem here should be obvious: more reliance on sponsors means they'll get a bigger say in the conference. My conferences don't do sponsored talks at all, and I hope that continues to be the case. The perf sponsors are a great bunch, and they're typically driven by the engineers in the company, not the marketing people. That helps. A lot. I don't see them trying to influence the schedule.</p>

<p>But ... well, I don't have to draw you a picture of what would happen if that changes.</p>

<h3>US extinction event</h3>

<p>One of the things I worry about is that whatever extinction event took out the US web conference circuit will also take place in Europe. But I'm not entirely sure what happened, so I'm not sure how to avoid it.</p>
		
<p>Fact is that there are WAY fewer web conferences in the US than there used to be. When I worked for the <a href="https://interledger.org/" class="external">ILF</a> I did some research for sponsorship purposes, and I found few survivors. In fact, this is how my first round of research on the Socials went:</p>

<ul>
<li><strong>Me</strong>: Hi, I'm looking for US web conferences. Know of any good ones?</li>

<li><strong>The world</strong>: [crickets]</li>

<li><strong>Me</strong>: ... </li>

<li><strong>The world</strong>: ... do you need more crickets?</li>

<li><strong>Me</strong>: ... nah ...</li>

<li><strong>Someone</strong>: Err ... Smashing?</li>
</ul>

<p>The joke is, of course, that <a href="https://smashingconf.com/" class="external">Smashing Conferences</a> is a European organiser. And they don't do a 2026 US conference.</p>

<p>I heard two explanations for the extinction that sort-of make sense to me. First, Covid. In general, Americans are much more worried about diseases than Europeans, and where Europeans flocked back to the conference circuit in 2022, Americans did not; or not to the same degree, I'm not sure.</p>

<p>Second, even before Covid the US conferences had become over-reliant on sponsors (read: VCs), and they basically only treated topics the sponsors wanted to see treated. Nowadays that means a lot of AI, some AI for diversity, supported by a solid helping of AI. In contrast, my two conferences (28 speakers) will probably see a single talk about AI.</p>

<p>(A third factor could be Trump, but that only explains why non-Americans don't want to go to the US. It shouldn't affect internal US conferences, and the extinction took place well before 2025.)</p>

<p>I can't speak for the truth of these theories. The last time I was in the US was at Smashing New York 2024, and that seemed like a perfectly normal web conference with happy attendees and only a single talk about AI &#8212; but it was organised by Europeans, not Americans, so it's probably not representative.</p>

<p>Or is it? Is it the destiny of the Europeans to ride to the aid of our beleaguered American colleagues, for rescue or revenge? Or am I being overly dramatic and in love with my own words after my <a href="20260403-back.html">blogging break</a>? Questions, questions...</p>

<p>For a while now I've been thinking about organising something performance-related in North America. I even did a little bit of work. But it all depends on how ticket sales go in the next few months. If they're bad I just don't dare to order (and pay for) anything.</p>

<p>The conference circuit is in a slump these days. That won't change as long as people don't buy tickets. And a good conference circuit is typically  something that you start to miss only when it's too late.</p>]]></description>
    </item>
    <item>
      <title>Back</title>
      <link>https://quirksmode.org/quirksblog/2026/0403-back.html</link>
      <pubDate>2026-04-03T07:00:00+02:00</pubDate>
      <description><![CDATA[<p>Tap tap. Is this thing on? [... clears throat ...] Well, I'm back.</p>

<p>Who among you noticed I didn't blog for over four years? [No hands are raised. Nobody even pays attention.] Right.</p>

<p>The story is boring. I used to run Movable Type, an old Perl blogging system, from 2003, when I started blogging, to 2021, when my ISP shut down. My original plan for moving to another ISP failed miserably. With only days on the clock I had to jump to an essentially random ISP who didn't support Perl, but did offer Wordpress.</p>

<p>So now I was left with no blog, but with this big blue 'Install Wordpress' button (div?) that both enticed and frightened me. I never felt comfortable pressing it. I didn't want Wordpress to take over the non-blog part of this site &#8212; I still run that by hand-coding HTML and FTP-ing it to the server &#8212;  and it can't generate static HTML pages out of the box.</p> 

<p>Then <a href="https://paulvanbuuren.nl/" class="external">Paul van Buuren</a> told me a partial install was possible, and there was a plugin for creating static pages. That sounded a lot better. So I decided to do a partial install for blogging purposes only, with the static page plugin &#8212; later.</p>

<p>But later became never.</p>

<p>Then I switched ISPs again, to get rid of the passive-aggressive tone of my old one, and because <a href="https://jvhellemond.nl/" class="external">Jan van Hellemond</a>, who now helps me out with the conferences, recommended it for various reasons. I moved over the <a href="https://cssday.nl" class="external">conference</a> <a href="https://perfnow.nl" class="external">sites</a> a few weeks ago, and this week QuirksMode followed.</p>

<p>I asked Jan for advice on a blogging system, and this week it turned out he'd created a simple one himself. It's so new it doesn't even have a name. Let's see if it works. If you can read this it does.</p>

<p>So here I am, typing away in my static HTML file that I've always used to preview my blogposts in. Once I'm done I'll publish it with the newfangled publication system (really only an upload and a shell command). It's still a confusing process because it's so new to me, but it feels better than a massive Wordpress install.</p>

<p>And I may have something useful to say about CSS, once I've done some tests.</p>

<p>And BBEdit still remembers the macros I need for my blogging, such as Shift+Option+A for an external link, and Option+- for an em-dash. </p>

<p>It's good to be back.</p>]]></description>
    </item>
    <item>
      <title>Thidrekssaga XII - XIV</title>
      <link>https://quirksmode.org/quirksblog/2026/0402-ths.html</link>
      <pubDate>2026-04-02T07:00:00+02:00</pubDate>
      <description><![CDATA[<p>In the four blogless years I concluded my guided tour through the Thidrekssaga with parts <a href="/ths/firstread/grimhild.html">XII</a>, <a href="/ths/firstread/return.html">XIII</a>, and <a href="/ths/firstread/death.html">XIV</a>..</p>

<p>These parts treat Grimhild's plot to kill her brothers in revenge for their killing of Sigfrid, the return of Dietrich von Bern from exile, and the death of a few main characters of the saga, ending with two version of Dietrich's own death. <span class="smaller">(Incidentally, I think I'm ready to defend the theory that the first of those two stories was written in Aachen at the end of Charlemagne's reign. Writing a proper scholarly article takes a lot of time, though.)</span></p>

<p>My <a href="/blog/archives/2020/10/side_project_th.html">original purpose</a> was not only to continue my research, but also to learn a bit of PHP and to solve the thorny issues of footnotes (which really are sidenotes) on the Web. My 2020 solution, which you can for instance see <a href="/ths/saga.php?ch=53-56">here</a>, was OK enough for a first try, but far from perfect. In particular, you will see that the current sidenotes can overlap one another; they're all positioned absolutely.</p>

<p>I'm hoping Anchor Positioning can help solve this; there was something with 'place positioned element here, but below any other positioned element', right...?</p>]]></description>
    </item>
    <item>
      <title>The old blog</title>
      <link>https://quirksmode.org/quirksblog/2026/0401-old.html</link>
      <pubDate>2026-04-01T07:00:00+02:00</pubDate>
      <description><![CDATA[<p>Go <a href="/blog/archives/2021/09/">here</a> to continue reading
the old 2003-2021 blog in reverse-chronological order.</p>]]></description>
    </item>

  </channel>
</rss>
