> All in One 586

Ads

Thursday, March 5, 2026

The Different Ways to Select in CSS

Temani Afif recently did this exercise and I thought I’d build off of it. Some of these are useful. Many of them are not. There’s a bird at the end!

html

html {
  /* I mean, duh */
}

:root

:root {
  /* Sarsaparilla, anyone? */
}

:root is a CSS pseudo-class that matches the root element of the current (XML) document. If the current document is a HTML document, then it matches <html>. The XML documents that you’ll most likely encounter as a web developer (besides HTML) are:

  • SVG documents: :root matches <svg>
  • RSS documents: :root matches <rss>
  • Atom documents: :root matches <feed>
  • MathML documents: :root matches <math>
  • Other XML documents: :root matches the outermost element (e.g., <note>)

But what’s the practicality of :root? Well, the specificity of pseudo-classes (0-1-0) is higher than that of elements (0-0-1), so you’re less likely to run into conflicts with :root.

It’s conventional to declare global custom properties on :root, but I actually prefer :scope because it semantically matches the global scope. In practice though, it makes no difference.

/* Global variables */
:root { --color: black; }
:scope { --color: black; }

Let’s talk about :scope some more…

:scope or &

:scope {
  /* Insert scope creep here */
}

Okay, that’s not really what :scope is for.

As I mentioned, :scope matches the global scope root (<html>). However, this is only true when not used within the newly baseline @scope at-rule, which is used to define a custom scope root.

We can also do this:

& {
  /* And...? */
}

Normally, the & selector is used with CSS nesting to concatenate the current selector to the containing selector, enabling us to nest selectors even when we aren’t technically dealing with nested selectors. For example:

element:hover {
  /* This */
}

element {
  &:hover {
    /* Becomes this (notice the &) */
  }
}

element {
  :hover {
    /* Because this (with no &) */
  }
}

element :hover {
  /* Means this (notice the space before :hover) */
}

element {
  :hover & {
    /* Means :hover element, but I digress */
  }
}

When & isn’t nested, it simply selects the scope root, which outside of an @scope block is <html>. Who knew?

‌:has(head) or :has(body)

:has(head) {
  /* Nice! */
}

:has(body) {
  /* Even better! */
}

<html> elements should only contain a <head> and <body> (à la Anakin Skywalker) as direct children. Any other markup inserted here is invalid, although parsers will typically move it into the <head> or <body> anyway. More importantly, no other element is allowed to contain <head> or <body>, so when we say :has(head) or :has(body), this can only refer to the <html> element, unless you mistakenly insert <head> or <body> inside of <head> or <body>. But why would you? That’s just nasty.

Is :has(head) or :has(body) practical? No. But I am going to plug :has(), and you also learned about the illegal things that you shouldn’t do to HTML bodies.

:not(* *)

:not(* *) {
  /* (* *) are my starry eyes looking at CSS <3 */
}

Any element that’s contained by another element (* *)? Yeah, :not() that. The only element that’s not contained by another element is the <html> element. *, by the way, is called the universal selector.

And if you throw a child combinator right in the middle of them, you get a cute bird:

:not(* > *) {
  /* Chirp, chirp */
}

“Siri, file this under Completely Useless.” (Ironically, Siri did no such thing).


The Different Ways to Select <html> in CSS originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



from CSS-Tricks https://ift.tt/yoHNwkQ
via IFTTT

Wednesday, March 4, 2026

Mostly Clear today!



With a high of F and a low of 32F. Currently, it's 40F and Clear outside.

Current wind speeds: 9 from the South

Pollen: 0

Sunrise: March 4, 2026 at 07:19PM

Sunset: March 5, 2026 at 06:47AM

UV index: 0

Humidity: 63%

via https://ift.tt/GeCRSLa

March 5, 2026 at 10:02AM

Tuesday, March 3, 2026

Showers Early today!



With a high of F and a low of 33F. Currently, it's 41F and Mostly Cloudy outside.

Current wind speeds: 8 from the Northwest

Pollen: 0

Sunrise: March 3, 2026 at 07:21PM

Sunset: March 4, 2026 at 06:46AM

UV index: 0

Humidity: 84%

via https://ift.tt/OAKrWRN

March 4, 2026 at 10:02AM

Monday, March 2, 2026

Partly Cloudy today!



With a high of F and a low of 27F. Currently, it's 43F and Partly Cloudy outside.

Current wind speeds: 8 from the Southeast

Pollen: 0

Sunrise: March 2, 2026 at 07:22PM

Sunset: March 3, 2026 at 06:45AM

UV index: 0

Humidity: 64%

via https://ift.tt/vB3Jifo

March 3, 2026 at 10:02AM

Popover API or Dialog API: Which to Choose?

Choosing between Popover API and Dialog API is difficult because they seem to do the same job, but they don’t!

After a bit lots of research, I discovered that the Popover API and Dialog API are wildly different in terms of accessibility. So, if you’re trying to decide whether to use Popover API or Dialog’s API, I recommend you:

  • Use Popover API for most popovers.
  • Use Dialog’s API only for modal dialogs.

Popovers vs. Dialogs

The relationship between Popovers and Dialogs are confusing to most developers, but it’s actually quite simple.

Dialogs are simply subsets of popovers. And modal dialogs are subsets of dialogs. Read this article if you want to understand the rationale behind this relationship.

![[popover-accessible-roles.jpg.webp]]

This is why you could use the Popover API even on a <dialog> element.

<!-- Using popover on a dialog element --> 
<dialog popover>...</div> 

Stylistically, the difference between popovers and modals are even clearer:

  • Modals should show a backdrop.
  • Popovers should not.

Therefore, you should never style a popover’s ::backdrop element. Doing so will simply indicate that the popover is a dialog — which creates a whole can of problems.

You should only style a modal’s ::backdrop element.

Popover API and its accessibility

Building a popover with the Popover API is relatively easy. You specify three things:

  • a popovertarget attribute on the popover trigger,
  • an id on the popover, and
  • a popover attribute on the popover.

The popovertarget must match the id.

<button popovertarget="the-popover"> ... </button>
<dialog popover id="the-popover"> The Popover Content </dialog>

Notice that I’m using the <dialog> element to create a dialog role. This is optional, but recommended. I do this because dialog is a great default role since most popovers are simply just dialogs.

This two lines of code comes with a ton of accessibility features already built-in for you:

  • Automatic focus management
    • Focus goes to the popover when opening.
    • Focus goes back to the trigger when closing.
  • Automatic aria connection
    • No need to write aria-expanded, aria-popup and aria-controls. Browsers handle those natively. Woo!
  • Automatic light dismiss
    • Popover closes when user clicks outside.
    • Popover closes when they press the Esc key.

Now, without additional styling, the popover looks kinda meh. Styling is a whole ‘nother issue, so we’ll tackle that in a future article. Geoff has a few notes you can review in the meantime.

Dialog API and its accessibility

Unlike the Popover API, the Dialog API doesn’t have many built-in features by default:

  • No automatic focus management
  • No automatic ARIA connection
  • No automatic light dismiss

So, we have to build them ourselves with JavaScript. This is why the Popover API is superior to the Dialog API in almost every aspect — except for one: when modals are involved.

The Dialog API has a showModal method. When showModal is used, the Dialog API creates a modal. It:

  1. automatically inerts other elements,
  2. prevents users from tabbing into other elements, and
  3. prevents screen readers from reaching other elements.

It does this so effectively, we no longer need to trap focus within the modal.

But we gotta take care of the focus and ARIA stuff when we use the Dialog API, so let’s tackle the bare minimum code you need for a functioning dialog.

We’ll begin by building the HTML scaffold:

<button 
  class="modal-invoker" 
  data-target="the-modal" 
  aria-haspopup="dialog"
>...</button>

<dialog id="the-modal">The Popover Content</dialog>

Notice I did not add any aria-expanded in the HTML. I do this for a variety of reasons:

  1. This reduces the complexity of the HTML.
  2. We can write aria-expanded, aria-controls, and the focus stuff directly in JavaScript – since these won’t work without JavaScript.
  3. Doing so makes this HTML very reusable.

Setting up

I’m going to write about a vanilla JavaScript implementation here. If you’re using a framework, like React or Svelte, you will have to make a couple of changes — but I hope that it’s gonna be straightforward for you.

First thing to do is to loop through all dialog-invokers and set aria-expanded to false. This creates the initial state.

We will also set aria-controls to the <dialog> element. We’ll do this even though aria-controls is poop, ’cause there’s no better way to connect these elements (and there’s no harm connecting them) as far as I know.

const modalInvokers = Array.from(document.querySelectorAll('.modal-invoker'))

modalInvokers.forEach(invoker => {
  const dialogId = invoker.dataset.target
  const dialog = document.querySelector(`#${dialogId}`)
  invoker.setAttribute('aria-expanded', false)
  invoker.setAttribute('aria-controls', dialogId)
})

Opening the modal

When the invoker/trigger is clicked, we gotta:

  1. change the aria-expanded from false to true to show the modal to assistive tech users, and
  2. use the showModal function to open the modal.

We don’t have to write any code to hide the modal in this click handler because users will never get to click on the invoker when the dialog is opened.

modalInvokers.forEach(invoker => {
  // ... 

  // Opens the modal
  invoker.addEventListener('click', event => {
    invoker.setAttribute('aria-expanded', true)
    dialog.showModal()
  })
})

Great. The modal is open. Now we gotta write code to close the modal.

Closing the modal

By default, showModal doesn’t have automatic light dismiss, so users can’t close the modal by clicking on the overlay, or by hitting the Esc key. This means we have to add another button that closes the modal. This must be placed within the modal content.

<dialog id="the-modal"> 
  <button class="modal-closer">X</button>
  <!-- Other modal content -->
</dialog>

When users click the close button, we have to:

  1. set aria-expanded on the opening invoker to false,
  2. close the modal with the close method, and
  3. bring focus back to the opening invoker element.
modalInvokers.forEach(invoker => {
  // ... 

  // Opens the modal
  invoker.addEventListener('click', event => {
    invoker.setAttribute('aria-expanded', true)
    dialog.showModal()
  })
})

const modalClosers = Array.from(document.querySelectorAll('.modal-closer'))

modalClosers.forEach(closer => {
  const dialog = closer.closest('dialog')
  const dialogId = dialog.id
  const invoker = document.querySelector(`[data-target="${dialogId}"]`)
  
  closer.addEventListener('click', event => {
    dialog.close()
    invoker.setAttribute('aria-expanded', false)
    invoker.focus()
  })
})

Phew, with this, we’re done with the basic implementation.

Of course, there’s advanced work like light dismiss and styling… which we can tackle in a future article.

Can you use the Popover API to create modals?

Yeah, you can.

But you will have to handle these on your own:

  1. Inerting other elements
  2. Trapping focus

I think what we did earlier (setting aria-expanded, aria-controls, and focus) are easier compared to inerting elements and trapping focus.

The Dialog API might become much easier to use in the future

A proposal about invoker commands has been created so that the Dialog API can include popovertarget like the Popover API.

This is on the way, so we might be able to make modals even simpler with the Dialog API in the future. In the meantime, we gotta do the necessary work to patch accessibility stuff.

Deep dive into building workable popovers and modals

We’ve only began to scratch the surface of building working popovers and modals with the code above — they’re barebone versions that are accessible, but they definitely don’t look nice and can’t be used for professional purposes yet.

To make the process of building popovers and modals easier, we will dive deeper into the implementation details for a professional-grade popover and a professional-grade modal in future articles.

In the meantime, I hope these give you some ideas on when to choose the Popover API and the Dialog API!

Remember, there’s no need to use both. One will do.


Popover API or Dialog API: Which to Choose? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



from CSS-Tricks https://ift.tt/EOxRAIf
via IFTTT

Sunday, March 1, 2026

Partly Cloudy today!



With a high of F and a low of 30F. Currently, it's 40F and Clear outside.

Current wind speeds: 6 from the Southeast

Pollen: 0

Sunrise: March 1, 2026 at 07:24PM

Sunset: March 2, 2026 at 06:44AM

UV index: 0

Humidity: 49%

via https://ift.tt/SHZf7dC

March 2, 2026 at 10:02AM

Saturday, February 28, 2026

Mostly Cloudy today!



With a high of F and a low of 28F. Currently, it's 45F and Fair outside.

Current wind speeds: 12 from the Southeast

Pollen: 0

Sunrise: February 28, 2026 at 07:25PM

Sunset: March 1, 2026 at 06:42AM

UV index: 0

Humidity: 33%

via https://ift.tt/rI8WclH

March 1, 2026 at 10:02AM

The Different Ways to Select in CSS

Temani Afif recently did this exercise and I thought I’d build off of it. Some of these are useful. Many of them are not. There’s a bird at...