Modern CSS Features

July 20, 2025

Introduction

CSS continues to evolve rapidly, introducing powerful new features that make styling more intuitive, flexible, and maintainable. While many developers are still catching up with Flexbox and Grid, the CSS specification has moved far beyond these foundations.

In this post, we'll explore the most impactful modern CSS features that you should start using today, along with practical examples and browser support information.

Container Queries

Container queries are perhaps the most revolutionary CSS feature in recent years. Instead of responding to viewport size, elements can now respond to their container's size.

Basic Container Query Syntax

/* Define a containment context */
.card-container {
  container-type: inline-size;
  container-name: card;
}

/* Query the container */
@container card (min-width: 400px) {
  .card {
    display: flex;
    flex-direction: row;
  }
  
  .card-content {
    padding: 2rem;
  }
}

@container card (max-width: 399px) {
  .card {
    display: flex;
    flex-direction: column;
  }
  
  .card-content {
    padding: 1rem;
  }
}

Practical Example: Responsive Card Component

.card-wrapper {
  container-type: inline-size;
  container-name: card-component;
}

.card {
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  overflow: hidden;
}

/* Small container: stack vertically */
@container card-component (max-width: 300px) {
  .card {
    text-align: center;
  }
  
  .card-image {
    width: 100%;
    height: 200px;
  }
  
  .card-title {
    font-size: 1.2rem;
  }
}

/* Large container: horizontal layout */
@container card-component (min-width: 500px) {
  .card {
    display: flex;
    align-items: center;
  }
  
  .card-image {
    width: 200px;
    height: 150px;
    flex-shrink: 0;
  }
  
  .card-content {
    padding: 1.5rem;
  }
  
  .card-title {
    font-size: 1.5rem;
  }
}

Image

Small Container

Stacked layout

Image

Large Container

Horizontal layout

:has() Selector (Parent Selector)

The :has() pseudo-class allows you to select parent elements based on their children - something developers have wanted for decades.

Basic Usage

/* Select cards that have an image */
.card:has(img) {
  border: 2px solid #3498db;
}

/* Select form that has invalid input */
.form:has(input:invalid) {
  border-left: 4px solid #e74c3c;
}

/* Select article that doesn't have a featured image */
.article:not(:has(.featured-image)) {
  padding-top: 2rem;
}

Advanced Examples

/* Style navigation based on current page */
.nav:has(.nav-item[aria-current="page"]) {
  background-color: rgba(52, 152, 219, 0.1);
}

/* Adjust grid based on content */
.grid:has(.grid-item:nth-child(odd):last-child) {
  /* If odd number of items, center the last one */
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}

/* Interactive hover effects */
.card-group:has(.card:hover) .card:not(:hover) {
  opacity: 0.5;
  transform: scale(0.95);
}

CSS Subgrid

Subgrid allows nested grid items to align with their parent grid's tracks.

.main-grid {
  display: grid;
  grid-template-columns: 1fr 2fr 1fr;
  grid-template-rows: auto auto auto;
  gap: 1rem;
}

.nested-grid {
  display: grid;
  grid-column: 1 / -1;
  grid-row: 2;
  
  /* Inherit parent's column tracks */
  grid-template-columns: subgrid;
  grid-template-rows: subgrid;
}

.nested-item {
  /* These will align with parent grid tracks */
  background: #3498db;
  padding: 1rem;
  color: white;
}

CSS Cascade Layers

Cascade layers give you explicit control over the cascade, making CSS more predictable and maintainable.

/* Define layer order */
@layer reset, base, components, utilities;

/* Reset layer */
@layer reset {
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }
}

/* Base layer */
@layer base {
  body {
    font-family: system-ui, sans-serif;
    line-height: 1.6;
  }
  
  h1, h2, h3 {
    margin-bottom: 1rem;
  }
}

/* Components layer */
@layer components {
  .button {
    background: #3498db;
    color: white;
    padding: 0.75rem 1.5rem;
    border: none;
    border-radius: 4px;
    cursor: pointer;
  }
  
  .button:hover {
    background: #2980b9;
  }
}

/* Utilities layer (highest priority) */
@layer utilities {
  .text-center { text-align: center !important; }
  .hidden { display: none !important; }
}

Color Functions and Spaces

Modern CSS introduces new color functions and support for different color spaces.

oklch() and oklab()

:root {
  /* More perceptually uniform colors */
  --primary: oklch(0.7 0.15 250); /* lightness, chroma, hue */
  --secondary: oklch(0.8 0.1 180);
  --accent: oklch(0.6 0.2 30);
}

.button {
  background: var(--primary);
  
  /* Lighten by adjusting lightness */
  background: oklch(from var(--primary) calc(l + 0.1) c h);
}

.button:hover {
  /* Increase chroma for more vivid color */
  background: oklch(from var(--primary) l calc(c + 0.05) h);
}

color-mix() Function

:root {
  --primary: #3498db;
  --secondary: #e74c3c;
}

.mixed-color {
  /* Mix 60% primary with 40% secondary */
  background: color-mix(in srgb, var(--primary) 60%, var(--secondary));
}

.gradient-stop {
  /* Create smooth gradients */
  background: linear-gradient(
    to right,
    var(--primary),
    color-mix(in srgb, var(--primary), var(--secondary) 50%),
    var(--secondary)
  );
}

View Transitions API

Create smooth transitions between different states or pages.

/* Enable view transitions */
::view-transition-root {
  /* Default transition for all elements */
}

/* Customize specific transitions */
.page-title {
  view-transition-name: page-title;
}

::view-transition-old(page-title),
::view-transition-new(page-title) {
  animation-duration: 0.5s;
  animation-timing-function: ease-in-out;
}

::view-transition-old(page-title) {
  animation-name: slide-out-right;
}

::view-transition-new(page-title) {
  animation-name: slide-in-left;
}

@keyframes slide-out-right {
  to {
    transform: translateX(100%);
    opacity: 0;
  }
}

@keyframes slide-in-left {
  from {
    transform: translateX(-100%);
    opacity: 0;
  }
}
// Trigger view transition
function navigateToPage(url) {
  if (!document.startViewTransition) {
    // Fallback for browsers without support
    window.location.href = url;
    return;
  }
  
  document.startViewTransition(() => {
    window.location.href = url;
  });
}

CSS Nesting

Native CSS nesting eliminates the need for preprocessors in many cases.

.card {
  background: white;
  border-radius: 8px;
  padding: 1rem;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  
  & h2 {
    margin-top: 0;
    color: #333;
  }
  
  & .card-content {
    margin: 1rem 0;
    
    & p {
      line-height: 1.6;
      color: #666;
    }
  }
  
  & .card-actions {
    display: flex;
    gap: 0.5rem;
    margin-top: 1rem;
  }
  
  &:hover {
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    transform: translateY(-2px);
  }
  
  &.featured {
    border: 2px solid #3498db;
    
    & h2 {
      color: #3498db;
    }
  }
}

Scroll-Driven Animations

Create animations based on scroll progress without JavaScript.

@keyframes fade-in-up {
  from {
    opacity: 0;
    transform: translateY(50px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.scroll-animation {
  animation: fade-in-up linear forwards;
  animation-timeline: view();
  animation-range: entry 0% entry 100%;
}

/* Progress bar based on scroll */
.progress-bar {
  position: fixed;
  top: 0;
  left: 0;
  height: 4px;
  background: #3498db;
  transform-origin: left;
  
  animation: progress linear;
  animation-timeline: scroll(root);
  animation-range: 0% 100%;
}

@keyframes progress {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

Browser Support and Progressive Enhancement

Feature Detection

/* Use @supports for feature detection */
@supports (container-type: inline-size) {
  .container {
    container-type: inline-size;
  }
}

@supports not (container-type: inline-size) {
  /* Fallback styles */
  .card {
    max-width: 400px;
  }
}

/* Multiple feature detection */
@supports (display: grid) and (gap: 1rem) {
  .modern-grid {
    display: grid;
    gap: 1rem;
  }
}

JavaScript Feature Detection

// Check for CSS features
function supportsContainerQueries() {
  return CSS.supports('container-type', 'inline-size');
}

function supportsHasSelector() {
  return CSS.supports('selector(:has(div))');
}

function supportsViewTransitions() {
  return 'startViewTransition' in document;
}

// Apply progressive enhancement
if (supportsContainerQueries()) {
  document.body.classList.add('supports-container-queries');
}

if (supportsViewTransitions()) {
  document.body.classList.add('supports-view-transitions');
}

Practical Implementation Strategy

1. Start with Container Queries

/* Begin with simple container queries */
.sidebar {
  container-type: inline-size;
}

@container (min-width: 250px) {
  .widget {
    display: flex;
    align-items: center;
    gap: 1rem;
  }
}

2. Gradually Introduce :has()

/* Start with simple use cases */
.form:has(input:focus) {
  box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.3);
}

.article:has(.featured-image) {
  padding-top: 0;
}

3. Use Cascade Layers for Organization

@layer reset, base, layout, components, utilities;

@import url("reset.css") layer(reset);
@import url("components.css") layer(components);

Browser Support Status

  • Container Queries: Excellent support in modern browsers (Safari 16+, Chrome 105+, Firefox 110+)
  • :has() Selector: Good support (Safari 15.4+, Chrome 105+, Firefox 121+)
  • CSS Nesting: Excellent support (Safari 16.5+, Chrome 112+, Firefox 117+)
  • Subgrid: Good support (Safari 16+, Chrome 117+, Firefox 71+)
  • View Transitions: Limited support (Chrome 111+), with polyfills available
  • Color Functions: Partial support, gradually improving

Conclusion

Modern CSS features are transforming how we build responsive, maintainable web interfaces. While browser support varies, many of these features can be used today with proper fallbacks and progressive enhancement.

Key takeaways:

  • Container queries eliminate the need for many JavaScript-based responsive solutions
  • :has() selector finally gives us true parent selection capabilities
  • CSS layers provide explicit cascade control for better maintainability
  • View transitions enable smooth animations without complex JavaScript
  • Color functions offer more precise and flexible color manipulation

Start experimenting with these features in your projects, beginning with the ones that have the best browser support and clear fallback strategies. The future of CSS is here, and it's more powerful than ever.