Modern CSS You Can Use Today: Container Queries, :has() and Friends

CSS has changed more in the last three years than in the decade before. Many features that used to need JavaScript or hacks now work in every major browser. Here are the ones we use daily.

Modern CSS You Can Use Today: Container Queries, :has() and Friends

If you learned CSS a few years ago and haven't looked closely since, you might be surprised by how much has changed. A lot of the JavaScript we used to write for layouts and interactions is no longer necessary.

The handy way to check whether something is safe to use is to look at its "Baseline" status, which is shown on MDN and caniuse. Baseline means the feature works across the current versions of Chrome, Edge, Firefox and Safari. Everything below is Baseline.

Container queries

Media queries respond to the screen size. Container queries respond to the size of a component's container. This is a big deal for reusable components.

A product card can show a horizontal layout when it sits in a wide content area and a stacked layout in a narrow sidebar, using the same HTML and CSS. No more writing three variations of a card for different contexts.

You mark an element as a container with container-type: inline-size, then write @container (min-width: 400px) { ... } rules for its children.

The :has() selector

Often called the "parent selector", though it's more powerful than that. It lets you style an element based on what it contains.

Some things we use it for:

  • Style a form group differently when its input is invalid: .field:has(input:invalid)
  • Change a card's layout if it contains an image: .card:has(img)
  • Highlight a table row when its checkbox is checked

Before :has(), all of these needed JavaScript to add a class.

Native CSS nesting

You can now nest rules directly in plain CSS, the way you would in Sass:

.card { padding: 1rem; & h3 { margin: 0; } }

For small projects, this alone removes the need for a preprocessor.

Cascade layers

@layer lets you control which styles win, regardless of selector specificity or source order. It's a lifesaver when combining a framework like Bootstrap with your own styles. Put the framework in a lower layer and your overrides always win, without !important everywhere.

Subgrid

Grid items can now align their children to the parent grid. The classic use case is a row of cards where the titles, descriptions and buttons line up perfectly across cards, even when the text lengths differ.

Smaller wins

  • aspect-ratio for keeping images and videos in proportion without padding tricks.
  • clamp() for fluid typography that scales smoothly between a minimum and maximum size.
  • gap in flexbox for spacing items without margin hacks.
  • accent-color for styling checkboxes, radio buttons and range sliders to match your brand in one line.
  • text-wrap: balance for headings that don't leave a single lonely word on the last line.
  • :focus-visible for focus outlines that appear for keyboard users but not on mouse clicks.

What this means for your projects

Less JavaScript means faster pages, fewer things to break, and simpler code to maintain. When we build a new site now, we reach for CSS first and only add JavaScript when there's genuinely no CSS solution. More and more often, there is one.

Y
Written by the YPage Technologies team

We design and build websites, web applications and SaaS products for growing businesses, and share what we learn along the way.

Work with us

Ready to start your next project?

Let's talk about your website, web app or digital product.

Get in touch