🌞
CSS 2024

Native CSS Nesting

No more preprocessors needed! CSS now supports nesting natively. Write cleaner, more organised stylesheets with less repetition.

Chrome 112+ Firefox 117+ Safari 16.5+ Edge 112+

Goodbye SASS, Hello Native Nesting!

For years, we've relied on preprocessors like SASS and LESS for nesting. Now CSS has caught up! Native nesting means faster builds, simpler tooling, and one less dependency in your project.

❌ The Old Way (Repetitive)

/* So much repetition! */
.card {
    background: white;
    padding: 2rem;
}

.card h2 {
    margin-bottom: 1rem;
}

.card p {
    line-height: 1.6;
}

.card:hover {
    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}

.card:hover h2 {
    color: #2563eb;
}

✅ The New Way (Native Nesting)

/* Clean and organised! */
.card {
    background: white;
    padding: 2rem;
    
    h2 {
        margin-bottom: 1rem;
    }
    
    p {
        line-height: 1.6;
    }
    
    &:hover {
        box-shadow: 0 4px 12px rgba(0,0,0,0.1);
        
        h2 {
            color: #2563eb;
        }
    }
}

Nesting in Action

Basic Nesting

/* Nested navigation styles */
.demo-nav {
    background: #f3f4f6;
    padding: 1rem;
    border-radius: 0.5rem;
    
    ul {
        display: flex;
        gap: 2rem;
        list-style: none;
        margin: 0;
        padding: 0;
    }
    
    li {
        position: relative;
        
        &.active {
            font-weight: 600;
            
            a {
                color: #2563eb;
            }
            
            &::after {
                content: '';
                position: absolute;
                bottom: -0.5rem;
                left: 0;
                right: 0;
                height: 2px;
                background: #2563eb;
            }
        }
    }
    
    a {
        color: #6b7280;
        text-decoration: none;
        transition: color 0.2s;
        
        &:hover {
            color: #111827;
        }
    }
}

The & Selector

/* Using & for parent reference */
.btn-nested {
    padding: 0.75rem 1.5rem;
    border: 2px solid #e5e7eb;
    background: white;
    border-radius: 0.5rem;
    cursor: pointer;
    transition: all 0.2s;
    
    /* Modifier classes */
    &.primary {
        background: #2563eb;
        border-color: #2563eb;
        color: white;
        
        &:hover {
            background: #1d4ed8;
        }
    }
    
    &.secondary {
        background: #7c3aed;
        border-color: #7c3aed;
        color: white;
        
        &:hover {
            background: #6d28d9;
        }
    }
    
    /* States */
    &:hover {
        transform: translateY(-2px);
        box-shadow: 0 4px 12px rgba(0,0,0,0.1);
    }
    
    &:active {
        transform: translateY(0);
    }
    
    &:disabled {
        opacity: 0.5;
        cursor: not-allowed;
        
        &:hover {
            transform: none;
            box-shadow: none;
        }
    }
}

Media Queries & Nesting

Responsive Card

Resize your browser to see me change!

One
Two
Three
/* Nested media queries */
.responsive-card {
    padding: 2rem;
    background: white;
    border-radius: 1rem;
    box-shadow: 0 4px 6px rgba(0,0,0,0.1);
    
    h4 {
        margin-bottom: 1rem;
        color: #1f2937;
    }
    
    .card-grid {
        display: grid;
        gap: 1rem;
        
        /* Mobile first approach */
        grid-template-columns: 1fr;
        
        @media (min-width: 640px) {
            grid-template-columns: repeat(2, 1fr);
        }
        
        @media (min-width: 1024px) {
            grid-template-columns: repeat(3, 1fr);
        }
    }
    
    .card-item {
        padding: 1rem;
        background: #f3f4f6;
        border-radius: 0.5rem;
        text-align: center;
        
        @media (min-width: 640px) {
            padding: 1.5rem;
        }
    }
}

Complex Component

CSS Tips

Native CSS Nesting is Here!

Learn how to use CSS nesting to write cleaner, more maintainable stylesheets.

/* Complex nested component */
.blog-card {
    display: flex;
    flex-direction: column;
    background: white;
    border-radius: 1rem;
    overflow: hidden;
    transition: transform 0.3s;
    
    &:hover {
        transform: translateY(-4px);
        
        .blog-card__image {
            transform: scale(1.05);
        }
    }
    
    &__image {
        height: 200px;
        background: linear-gradient(135deg, #667eea, #764ba2);
        position: relative;
        transition: transform 0.3s;
        
        display: flex;
        align-items: center;
        justify-content: center;
        color: white;
        font-size: 2rem;
        
        &::before {
            content: '📝';
        }
    }
    
    &__category {
        position: absolute;
        top: 1rem;
        left: 1rem;
        padding: 0.25rem 0.75rem;
        background: rgba(255,255,255,0.9);
        color: #764ba2;
        border-radius: 9999px;
        font-size: 0.75rem;
        font-weight: 600;
    }
    
    &__content {
        padding: 1.5rem;
        flex: 1;
        display: flex;
        flex-direction: column;
    }
    
    &__title {
        margin: 0 0 0.5rem;
        color: #1f2937;
        font-size: 1.25rem;
    }
    
    &__excerpt {
        color: #6b7280;
        line-height: 1.6;
        flex: 1;
    }
    
    &__footer {
        display: flex;
        justify-content: space-between;
        margin-top: 1rem;
        padding-top: 1rem;
        border-top: 1px solid #e5e7eb;
        font-size: 0.875rem;
        color: #9ca3af;
    }
}

Nested Animations

Hover over me for a surprise!

/* Nested animations and keyframes */
.animation-demo {
    text-align: center;
    padding: 3rem;
    
    .loader {
        display: inline-flex;
        gap: 0.5rem;
        margin-bottom: 2rem;
        
        &__dot {
            width: 12px;
            height: 12px;
            background: #2563eb;
            border-radius: 50%;
            animation: bounce 1.4s infinite ease-in-out both;
            
            &:nth-child(1) {
                animation-delay: -0.32s;
            }
            
            &:nth-child(2) {
                animation-delay: -0.16s;
            }
        }
    }
    
    .animation-text {
        font-size: 1.25rem;
        color: #6b7280;
        transition: all 0.3s;
        display: inline-block;
        
        &:hover {
            color: #2563eb;
            transform: scale(1.1) rotate(2deg);
            
            animation: wiggle 0.5s ease-in-out;
        }
    }
}

/* Keyframes still go outside */
@keyframes bounce {
    0%, 80%, 100% {
        transform: scale(0);
    }
    40% {
        transform: scale(1);
    }
}

@keyframes wiggle {
    0%, 100% { transform: rotate(0deg); }
    25% { transform: rotate(-5deg); }
    75% { transform: rotate(5deg); }
}

Migrating from SASS

What Works the Same ✅

  • Basic nesting of selectors
  • The & parent selector
  • Nesting media queries
  • Nesting pseudo-classes and pseudo-elements

What's Different ⚠️

  • No variables (use CSS custom properties)
  • No mixins (coming soon with @mixin)
  • No extends (use CSS classes)
  • No math operations (use calc())

Best Practices 🎯

  • Don't nest too deeply (3 levels max)
  • Use BEM naming for clarity
  • Keep specificity in check
  • Test in all target browsers

SASS to CSS Migration Example

SASS (Before)

// SASS with variables and mixins
$primary: #2563eb;
$radius: 0.5rem;

@mixin button-style {
    padding: 0.75rem 1.5rem;
    border-radius: $radius;
    transition: all 0.2s;
}

.form {
    padding: 2rem;
    
    &__group {
        margin-bottom: 1.5rem;
        
        label {
            display: block;
            margin-bottom: 0.5rem;
            color: darken($primary, 20%);
        }
        
        input {
            @include button-style;
            border: 2px solid $primary;
            
            &:focus {
                outline: none;
                border-color: lighten($primary, 10%);
            }
        }
    }
}

Native CSS (After)

/* CSS with custom properties */
:root {
    --primary: #2563eb;
    --primary-dark: #1d4ed8;
    --primary-light: #60a5fa;
    --radius: 0.5rem;
}

.form {
    padding: 2rem;
    
    &__group {
        margin-bottom: 1.5rem;
        
        label {
            display: block;
            margin-bottom: 0.5rem;
            color: var(--primary-dark);
        }
        
        input {
            /* Direct styles instead of mixin */
            padding: 0.75rem 1.5rem;
            border-radius: var(--radius);
            transition: all 0.2s;
            border: 2px solid var(--primary);
            
            &:focus {
                outline: none;
                border-color: var(--primary-light);
            }
        }
    }
}

Nesting Rules & Gotchas

Rule 1: Implicit &

/* CSS automatically adds & */
.parent {
    .child { }     /* = .parent .child */
    & .child { }   /* = .parent .child */
    
    div { }        /* = .parent div */
    & div { }      /* = .parent div */
}

Rule 2: Combining Selectors

/* Be careful with specificity */
.card {
    /* This becomes .card.active */
    &.active { }
    
    /* This becomes .card .active */
    .active { }
    
    /* Multiple selectors */
    h2, h3 {
        margin: 0;
    }
}

Rule 3: At-Rules

/* Media queries and supports */
.element {
    width: 100%;
    
    @media (min-width: 768px) {
        width: 50%;
    }
    
    @supports (display: grid) {
        display: grid;
    }
}

Pro Tips

📏

Keep It Shallow

Avoid nesting more than 3 levels deep. It makes CSS harder to read and increases specificity.

🎯

BEM + Nesting

Combine BEM naming with nesting for the best of both worlds - clarity and convenience.

🔍

DevTools Support

Modern DevTools show nested CSS properly, making debugging much easier than before.

Tea Break Wisdom

Like a perfectly nested tea cosy, CSS nesting keeps everything warm and organised!

Keep Learning Modern CSS

Native nesting is just the beginning. Explore more cutting-edge CSS features!