Modern CSS Features You Probably Missed — Part 1

Tushar ShuklaTS
Tushar ShuklaA senior frontend developer, curious tech tinkerer and an anime fan.
0 views
6 mins read
If you know CSS from what it was a couple of years ago, then you don't know CSS at all (just kidding 😅). CSS has grown rapidly in the last few years. Many new features are already stable in modern browsers, but a lot of developers still don't use them simply because they aren't aware. To be honest, I sometimes feel like it is turning into a capable programming language 😄.

This two-part series will cover modern CSS features that make your life easier. Part 1 is focused on practical, production-ready features you can start using today.
For each feature, I've added a Production Readiness rating (1-10):
1-3 → Experimental, not ready for use
4-6 → Useful but limited browser support
7-8 → Safe in many cases, some caveats
9-10 → Well supported and highly practical

1. Layout & Sizing

1.1 aspect-ratio

What it does: Defines the width-to-height ratio of an element.
Why it matters: If you've ever tried to embed a youtube video on a webpage, you know the struggle of maintaining the aspect ratio with tricks like padding hacks for responsiveness. This property makes it a breeze.
.card {
  aspect-ratio: 16 / 9; /* defines ratio */
  background: #ddd;
}
<div class="card">Responsive Card</div>
  • Production Readiness: 10/10
  • Browser Support: Widely supported in modern Chromium, Firefox, Safari — see Can I use
  • Docs: MDN

1.2 content-visibility

What it does: Skips rendering off-screen content until needed.
Why it matters: Big paint/layout savings for long feeds, dashboards, and lists.

Keyword values for content-visibility:
  • auto
  • visible
  • hidden
.article {
  content-visibility: auto; /* focus: render when near viewport */
  contain-intrinsic-width: 100vw; /* reserve space to avoid jumps horizontally */
  contain-intrinsic-height: 110vh; /* reserve space to avoid jumps vertically */
}
  • Production Readiness: 9/10 (great in Chromium; test fallbacks for non-supporting browsers)
  • Browser Support: Strong in Chromium; limited elsewhere — see Can I use
  • Docs: MDN

1.3 display: contents

What it does: Makes the element's children act like they're direct children of the parent, ignoring the wrapper.
Why it matters: Useful for grids and flex layouts where wrapper elements break alignment.
<div class="grid">
  <div class="item-wrap">
    <article class="item"></article>
  </div>
  <div class="item-wrap">
    <article class="item"></article>
  </div>
</div>
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.75rem;
}
 
.item-wrap {
  display: contents; /* focus: wrapper disappears for layout */
}
  • Production Readiness: 8/10
  • Browser Support: Good support, some accessibility caveats in Safari - see Can I use
  • Docs: MDN

1.4 Multi-value display (e.g., display: inline flex)

What it does: Combines outer and inner display types.
Why it matters: Express intent directly (inline formatting + flex layout).
Now, you may wonder, how is this any different from just using display: inline-flex?
From what I understand, there is NO FUNCTIONAL DIFFERENCE between display: inline flex and display: inline-flex. The key is that the two-value syntax separates concerns clearly by distinguishing outer display (how container behaves) from inner display (how children are laid out).
.badge {
  display: inline flex; /* focus: inline formatting + flex children */
  gap: 0.25rem;
  padding: 0.25rem 0.5rem;
  border: 1px solid #ddd;
  border-radius: 999px;
}
  • Production Readiness: 9/10
  • Browser Support: Good across modern browsers — see Can I use
  • Docs: MDN

1.5 subgrid

What it does: Allows child grids to align directly to their parent grid tracks.
Why it matters: Perfect for nested layouts where alignment used to be messy.
.layout {
  display: grid;
  grid-template-columns: 16rem 1fr;
  gap: 1rem;
}
 
.article {
  display: grid;
  grid-template-rows: subgrid; /* focus: inherit parent rows */
  grid-row: 1 / span 2;
  row-gap: 0.5rem;
}
  • Production Readiness: 7/10 (supported in modern engines; patterns still maturing)
  • Browser Support: Now available in all major engines — see Can I use
  • Docs: MDN

1.6 Container Queries

What it does: Lets you style elements based on the size of their container, not the viewport.
Why it matters: Enables truly reusable, responsive components.
.card {
  container-type: inline-size; /* focus: enable container query */
  padding: 1rem;
  border: 1px solid #ddd;
}
 
@container (min-width: 420px) {
  .card__content {
    display: flex; /* focus: change layout when the container grows */
    gap: 1rem;
  }
}
  • Production Readiness: 8/10 (excellent support; watch performance in deeply nested UIs)
  • Browser Support: Strong across major browsers — see Can I use
  • Docs: MDN

2. Styling & Readability

2.1 text-wrap

What it does: Controls how text wraps when it hits boundaries.
Why it matters: Improves typography without weird line breaks.
h2,
.card-title {
  text-wrap: balance; /* focus: more even line breaks */
}
  • Production Readiness: 8/10
  • Browser Support: Good in Chromium/Safari; Firefox partial — see Can I use
  • Docs: MDN

2.2 white-space-collapse

What it does: Controls how sequences of whitespace are collapsed.
Why it matters: Cleaner rendering for user-generated or preformatted text.
.review {
  white-space-collapse: preserve; /* focus: keep intentional spacing */
}
  • Production Readiness: 7/10
  • Browser Support: Supported in Chromium/Safari; Firefox pending — see Can I use
  • Docs: MDN

2.3 overscroll-behavior

What it does: Controls how scrolling behaves at boundaries.
Why it matters: Prevents annoying “scroll chaining” when nested scrolls bounce.
.modal {
  overflow: auto;
  overscroll-behavior: contain; /* focus: keep scroll inside modal */
}
In above code example, the modal will not allow scrolling to propagate to the parent container, which is useful for preventing unwanted scroll behavior when interacting with modals or other scrollable elements.
  • Production Readiness: 9/10
  • Browser Support: Wide support across modern browsers — see Can I use
  • Docs: MDN

2.4 scrollbar-gutter: stable

What it does: Reserves space for scrollbars to avoid layout shifts when they appear.
Why it matters: Fixes annoying page jumps when scrollbars toggle.
html {
  scrollbar-gutter: stable both-edges; /* focus: reserve space proactively */
}
  • Production Readiness: 8/10
  • Browser Support: Good in Chromium/Safari; Firefox pending — see Can I use
  • Docs: MDN

2.5 light-dark() color function

What it does: Adjusts colors automatically based on theme (light or dark).
Why it matters: No need for separate media queries.
.card {
  background: light-dark(#ffffff, #111111); /* focus: auto theme switch */
  color: light-dark(#111111, #f5f5f5);
}
  • Production Readiness: 7/10
  • Browser Support: Chromium/Safari support; Firefox work ongoing — see Can I use
  • Docs: MDN

3. Organizing Your CSS

3.1 @supports (feature queries)

What it does: Apply styles only if a property is supported.
Why it matters: Progressive enhancement without JS checks.
@supports (display: grid) {
  .products {
    display: grid; /* focus: use grid where supported */
    gap: 1rem;
  }
}
  • Production Readiness: 10/10
  • Browser Support: Excellent across modern browsers — see Can I use
  • Docs: MDN

3.2 @layer (cascade layers)

What it does: Creates ordered “buckets” in the cascade.
Why it matters: Predictable overrides; fewer specificity fights.
@layer reset, base, components, utilities; /* focus: declare order */
 
@layer reset {
  *,
  *::before,
  *::after {
    margin: 0;
    padding: 0;
  }
}
 
@layer utilities {
  .text-center {
    text-align: center;
  }
 
  .btn {
    border-radius: 0.75rem;
  }
}
 
@layer components {
  .btn {
    padding: 0.5rem 0.75rem;
    border-radius: 0.5rem;
  }
}
In above code, notice that @layer utilities is defined before @layer components where as we have declared a different order of these 'buckets' at the top. Despite this, the styles in @layer utilities will take precedence over those in @layer components if there are any conflicts, like in the .btn class.
  • Production Readiness: 9/10
  • Browser Support: Strong across major browsers — see Can I use
  • Docs: MDN

3.3 Native CSS Nesting

What it does: Lets you nest selectors without preprocessors like Sass, Less etc.
Why it matters: Cleaner, scoped styles.
.card {
  padding: 1rem;
  border: 1px solid #eee;
 
  & h3 {
    /* focus: nested selector */
    margin: 0 0 0.5rem;
  }
 
  & .cta {
    display: inline-flex;
    gap: 0.5rem;
  }
}
  • Production Readiness: 8/10
  • Browser Support: Broad in modern engines — see Can I use
  • Docs: MDN

3.3 :has() (parent selector)

What it does: Styles an element based on its children.
Why it matters: State-aware styling without extra classes, something devs wanted for decades.
/* highlight incomplete forms */
.form:has(:invalid) {
  /* focus: style parent when child is invalid */
  outline: 2px solid #ff6b6b;
}
 
/* image-only articles */
article:has(> img:first-child:last-child) {
  text-align: center;
}
  • Production Readiness: 8/10
  • Browser Support: Supported in all modern browsers — see Can I use
  • Docs: MDN

Wrapping Up Part 1

These features are safe, stable, and practical - you can start using most of them today. They solve long-standing CSS headaches like ratio hacks, nested selectors, scroll issues, and responsive components. If you adopt only a few, start with aspect-ratio, container queries, @layer, and overscroll-behavior - they quickly improve layout resilience, readability, and code organization.

Up next — Part 2: where, we'll look at animations, interactivity, and experimental features that are shaping the future of CSS.
You may also like
If you like my work, consider supporting me.
Support My Work
Found an issue?

If you found a typo, incorrect information or have a feature request, please raise an issue by clicking this button.

And that's a wrap!

Piqued your interest?

Let's connect!