Modern CSS Features and Experimental APIs

1. CSS Nesting Syntax and Implementation

Feature Syntax Browser Support Description
Basic Nesting NEW .parent { & .child { } } Chrome 120+, Safari 17.2+ Native CSS nesting without preprocessor
Direct Nesting .parent { .child { } } Chrome 120+, Safari 17.2+ Type selector requires &
Ampersand (&) &:hover, &.active Modern browsers Reference parent selector
Compound Nesting &-suffix Modern browsers BEM-style concatenation
Media Query Nesting @media { & { } } Modern browsers Nest media queries inside selectors
Multiple Selectors &:is(.a, .b) Modern browsers Multiple parent references

Example: Native CSS nesting

/* Basic nesting with & */
.card {
    background: white;
    padding: 1rem;
    border-radius: 8px;
    
    /* Nested element */
    & .title {
        font-size: 1.5rem;
        margin-bottom: 0.5rem;
    }
    
    /* Pseudo-class */
    &:hover {
        box-shadow: 0 4px 8px rgba(0,0,0,0.1);
    }
    
    /* Pseudo-element */
    &::before {
        content: '';
        display: block;
    }
    
    /* Compound selector (BEM-style) */
    &--featured {
        border: 2px solid #007acc;
    }
    
    &__header {
        display: flex;
        justify-content: space-between;
    }
    
    &__title {
        font-weight: bold;
    }
}

/* Compiles to: */
/*
.card { background: white; padding: 1rem; border-radius: 8px; }
.card .title { font-size: 1.5rem; margin-bottom: 0.5rem; }
.card:hover { box-shadow: 0 4px 8px rgba(0,0,0,0.1); }
.card::before { content: ''; display: block; }
.card--featured { border: 2px solid #007acc; }
.card__header { display: flex; justify-content: space-between; }
.card__title { font-weight: bold; }
*/

/* Direct nesting (type selectors need &) */
.article {
    /* ✅ CORRECT: Class/ID can be direct */
    .content { }
    #main { }
    
    /* ❌ WRONG: Type selector needs & */
    p { }  /* Won't work! */
    
    /* ✅ CORRECT: Use & with type selector */
    & p {
        line-height: 1.6;
    }
    
    & > p {
        /* Direct child paragraphs */
    }
}

/* Multiple nesting levels */
.nav {
    display: flex;
    
    & .nav-item {
        padding: 0.5rem 1rem;
        
        & .nav-link {
            color: #333;
            text-decoration: none;
            
            &:hover {
                color: #007acc;
            }
            
            &:focus {
                outline: 2px solid currentColor;
            }
        }
        
        &.active .nav-link {
            font-weight: bold;
        }
    }
}

Example: Advanced nesting patterns

/* Media query nesting */
.container {
    width: 100%;
    padding: 1rem;
    
    @media (min-width: 768px) {
        & {
            width: 750px;
            margin: 0 auto;
        }
    }
    
    @media (min-width: 1024px) {
        & {
            width: 960px;
            padding: 2rem;
        }
    }
}

/* Nested at-rules */
.button {
    padding: 0.5rem 1rem;
    background: #007acc;
    color: white;
    
    @supports (backdrop-filter: blur(10px)) {
        & {
            background: rgba(0, 122, 204, 0.8);
            backdrop-filter: blur(10px);
        }
    }
    
    @media (prefers-reduced-motion: no-preference) {
        & {
            transition: transform 0.2s;
        }
        
        &:hover {
            transform: scale(1.05);
        }
    }
}

/* Multiple parent selectors with :is() */
.nav {
    &:is(.horizontal, .vertical) {
        display: flex;
    }
    
    &:is(.horizontal) {
        flex-direction: row;
    }
    
    &:is(.vertical) {
        flex-direction: column;
    }
}

/* Complex nesting scenarios */
.theme-dark {
    & .card {
        background: #2d2d2d;
        color: #f0f0f0;
        
        & .title {
            color: white;
        }
        
        &:hover {
            background: #3d3d3d;
        }
    }
    
    & .button {
        background: #404040;
        
        &:hover {
            background: #505050;
        }
    }
}

/* Nesting with :has() */
.article {
    & {
        padding: 2rem;
    }
    
    &:has(img) {
        padding-top: 0;
        
        & img {
            width: 100%;
            height: auto;
        }
    }
    
    &:has(> .featured) {
        border-left: 4px solid #007acc;
    }
}
Note: Native CSS nesting requires & for type selectors and pseudo-classes. Class/ID selectors can be direct children. Media queries and @supports can be nested inside selectors. Browser support: Chrome 120+, Safari 17.2+, Firefox 117+.

2. CSS Cascade Layers (@layer)

Concept Syntax Purpose Specificity
Layer Declaration @layer name { } Create named layer Order-based, not specificity-based
Layer Ordering @layer reset, base, theme; Define layer priority Later layers have higher priority
Anonymous Layer @layer { } Unnamed layer Lowest priority
Nested Layers @layer outer.inner { } Layer hierarchy Dot notation for sub-layers
Layer Import @import url() layer(name); Import into layer Organize external CSS
Unlayered Styles Normal CSS rules Highest priority Always override layered styles

Example: Cascade layers basics

/* 1. Define layer order (lowest to highest priority) */
@layer reset, base, components, utilities, overrides;

/* 2. Add styles to layers */
@layer reset {
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
}

@layer base {
    body {
        font-family: system-ui, sans-serif;
        line-height: 1.6;
        color: #333;
    }
    
    a {
        color: #007acc;
        text-decoration: none;
    }
}

@layer components {
    .button {
        padding: 0.5rem 1rem;
        border: none;
        border-radius: 4px;
        cursor: pointer;
    }
    
    .card {
        background: white;
        padding: 1rem;
        border-radius: 8px;
        box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    }
}

@layer utilities {
    .text-center {
        text-align: center;
    }
    
    .mt-1 {
        margin-top: 0.5rem;
    }
    
    .hidden {
        display: none;
    }
}

@layer overrides {
    .force-visible {
        display: block !important;
    }
}

/* Unlayered styles have HIGHEST priority */
.emergency-fix {
    color: red;
    /* This beats ALL layered styles, even with !important in layers */
}

/* Layer priority demonstration */
@layer base {
    .text {
        color: blue;  /* Specificity: (0,1,0) */
    }
}

@layer components {
    p {
        color: green;  /* Specificity: (0,0,1) but HIGHER layer */
    }
}

/* Result: p.text will be GREEN (layer order wins over specificity) */

Example: Nested and sub-layers

/* Define nested layer structure */
@layer framework {
    @layer reset, base, components, utilities;
}

/* Add to nested layers using dot notation */
@layer framework.reset {
    *, *::before, *::after {
        box-sizing: border-box;
    }
}

@layer framework.base {
    body {
        margin: 0;
        font-family: system-ui;
    }
}

@layer framework.components {
    @layer buttons, cards, modals;
    
    @layer buttons {
        .btn {
            padding: 0.5rem 1rem;
            border: none;
            border-radius: 4px;
        }
        
        .btn-primary {
            background: #007acc;
            color: white;
        }
    }
    
    @layer cards {
        .card {
            background: white;
            padding: 1rem;
            border-radius: 8px;
        }
    }
}

@layer framework.utilities {
    .flex {
        display: flex;
    }
    
    .gap-1 {
        gap: 0.5rem;
    }
}

/* Import external CSS into layers */
@import url('normalize.css') layer(framework.reset);
@import url('components.css') layer(framework.components);
@import url('utilities.css') layer(framework.utilities);

/* Layer order with imports */
@layer reset, vendor, components;
@import url('reset.css') layer(reset);
@import url('bootstrap.css') layer(vendor);
@import url('custom.css') layer(components);

/* Anonymous layer (lowest priority) */
@layer {
    /* Styles here have lowest priority */
    .experimental {
        color: purple;
    }
}

Example: Practical layer architecture

/* Complete layer architecture for an application */

/* 1. Declare all layers upfront */
@layer reset, tokens, base, layout, components, utilities, themes, overrides;

/* 2. Reset layer */
@layer reset {
    @import url('modern-normalize.css');
    
    *, *::before, *::after {
        box-sizing: border-box;
    }
}

/* 3. Design tokens */
@layer tokens {
    :root {
        --color-primary: #007acc;
        --color-text: #1a1a1a;
        --spacing-unit: 0.5rem;
        --font-sans: system-ui, sans-serif;
    }
}

/* 4. Base styles */
@layer base {
    body {
        font-family: var(--font-sans);
        color: var(--color-text);
        line-height: 1.6;
    }
    
    h1, h2, h3, h4, h5, h6 {
        font-weight: 600;
        line-height: 1.2;
    }
}

/* 5. Layout primitives */
@layer layout {
    .container {
        max-width: 1200px;
        margin: 0 auto;
        padding: 0 1rem;
    }
    
    .flex {
        display: flex;
    }
    
    .grid {
        display: grid;
    }
}

/* 6. Components */
@layer components {
    @layer buttons, cards, forms, navigation;
    
    @layer buttons {
        .button {
            padding: 0.5rem 1rem;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            background: var(--color-primary);
            color: white;
        }
    }
    
    @layer cards {
        .card {
            background: white;
            padding: 1rem;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
    }
}

/* 7. Utilities (highest in normal layers) */
@layer utilities {
    .text-center { text-align: center; }
    .hidden { display: none; }
    .sr-only {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
    }
}

/* 8. Theme layer */
@layer themes {
    .theme-dark {
        --color-bg: #1a1a1a;
        --color-text: #f0f0f0;
        background: var(--color-bg);
        color: var(--color-text);
    }
}

/* 9. Overrides (when absolutely necessary) */
@layer overrides {
    .js-visible {
        display: block !important;
    }
}

/* Unlayered: Emergency fixes only */
.critical-fix {
    /* This beats everything */
}

/* Benefits of this architecture:
   - Predictable specificity
   - Easy to understand priority
   - No need for !important (mostly)
   - Third-party CSS can be contained
   - Components can't accidentally override resets
*/
Warning: Unlayered styles always beat layered styles, regardless of specificity. !important within layers inverts the layer order. Layer order is defined by first declaration. Plan layer architecture before implementation.

3. CSS Scope (@scope)

Feature Syntax Browser Support Purpose
Basic Scope @scope (.root) { } Chrome 118+ Limit styles to subtree
Scope with Limit @scope (.root) to (.limit) { } Chrome 118+ Exclude nested scopes
:scope Pseudo-class :scope { } All modern Reference scope root
Multiple Scopes @scope (.a, .b) { } Chrome 118+ Apply to multiple roots
Nested Scopes Scopes within scopes Chrome 118+ Fine-grained control

Example: CSS @scope basics

/* Basic scope: styles only apply inside .card */
@scope (.card) {
    /* All selectors are scoped to .card descendants */
    h2 {
        font-size: 1.5rem;
        margin-bottom: 0.5rem;
    }
    
    p {
        line-height: 1.6;
        color: #666;
    }
    
    button {
        padding: 0.5rem 1rem;
        background: #007acc;
        color: white;
    }
    
    /* :scope references the .card itself */
    :scope {
        background: white;
        padding: 1rem;
        border-radius: 8px;
    }
    
    /* Equivalent to .card > h2 */
    :scope > h2 {
        border-bottom: 2px solid #007acc;
    }
}

/* Without @scope, you'd need: */
.card { background: white; padding: 1rem; border-radius: 8px; }
.card h2 { font-size: 1.5rem; margin-bottom: 0.5rem; }
.card p { line-height: 1.6; color: #666; }
.card button { padding: 0.5rem 1rem; background: #007acc; color: white; }
.card > h2 { border-bottom: 2px solid #007acc; }

/* Scope with exclusion boundary */
@scope (.card) to (.nested-card) {
    /* Styles apply inside .card but NOT inside .nested-card */
    p {
        color: #333;
    }
    
    /* This won't affect paragraphs inside .nested-card */
}

/* HTML structure:
<div class="card">
    <p>Affected by scope</p>
    <div class="nested-card">
        <p>NOT affected (excluded)</p>
    </div>
</div>
*/

/* Multiple scope roots */
@scope (.header, .footer, .sidebar) {
    nav {
        display: flex;
        gap: 1rem;
    }
    
    a {
        color: inherit;
        text-decoration: none;
    }
}

/* Practical example: Modal component */
@scope (.modal) {
    :scope {
        position: fixed;
        inset: 0;
        display: flex;
        align-items: center;
        justify-content: center;
        background: rgba(0,0,0,0.5);
    }
    
    .modal-content {
        background: white;
        padding: 2rem;
        border-radius: 8px;
        max-width: 500px;
        width: 90%;
    }
    
    .modal-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 1rem;
    }
    
    h2 {
        margin: 0;
        font-size: 1.5rem;
    }
    
    button {
        padding: 0.5rem 1rem;
        border: none;
        border-radius: 4px;
        cursor: pointer;
    }
    
    .close-button {
        background: transparent;
        font-size: 1.5rem;
    }
}

Example: Advanced @scope patterns

/* Scope for theming */
@scope (.theme-dark) {
    :scope {
        background: #1a1a1a;
        color: #f0f0f0;
    }
    
    .card {
        background: #2d2d2d;
        border-color: #404040;
    }
    
    .button {
        background: #404040;
        color: white;
    }
    
    a {
        color: #6db3f2;
    }
}

@scope (.theme-light) {
    :scope {
        background: #ffffff;
        color: #1a1a1a;
    }
    
    .card {
        background: white;
        border-color: #e0e0e0;
    }
    
    .button {
        background: #007acc;
        color: white;
    }
}

/* Nested scope exclusion */
@scope (.article) to (.codeBlock, .callout) {
    /* Styles apply to .article but exclude .codeBlock and .callout */
    p {
        font-size: 1rem;
        line-height: 1.6;
    }
    
    /* Code blocks and callouts maintain their own styling */
}

/* Scope with media queries */
@scope (.responsive-nav) {
    :scope {
        display: flex;
    }
    
    .nav-item {
        padding: 0.5rem;
    }
    
    @media (max-width: 768px) {
        :scope {
            flex-direction: column;
        }
        
        .nav-item {
            width: 100%;
        }
    }
}

/* Comparing scope to nesting */

/* With @scope (cleaner for components) */
@scope (.card) {
    :scope { padding: 1rem; }
    h2 { font-size: 1.5rem; }
    p { color: #666; }
}

/* With nesting (more verbose) */
.card {
    & {
        padding: 1rem;
    }
    
    & h2 {
        font-size: 1.5rem;
    }
    
    & p {
        color: #666;
    }
}

/* Use @scope for:
   - Component encapsulation
   - Theme boundaries
   - Section-specific styles
   - Preventing style leakage
   
   Use nesting for:
   - Parent-child relationships
   - State variations
   - BEM patterns
   - Pseudo-classes/elements
*/

/* Scope specificity */
@scope (.card) {
    p {
        /* Specificity: (0,1,1) = .card p */
        color: blue;
    }
}

.card p {
    /* Same specificity: (0,1,1) */
    /* Last rule wins (cascade) */
    color: red;
}

/* But @scope provides better isolation */
@scope (.card) to (.nested) {
    /* This won't affect .nested descendants */
    p { color: blue; }
}
Note: @scope provides true style encapsulation without Shadow DOM. Use to () to exclude nested components. :scope references the root element. Browser support limited to Chrome 118+, use feature detection or fallbacks.

4. CSS Container Style Queries

Feature Syntax Browser Support Purpose
Container Size Query @container (width > 400px) Chrome 105+, Safari 16+ Query container dimensions
Container Style Query NEW @container style(--theme: dark) Chrome 111+ (flag) Query container custom properties
container-type inline-size | size Modern browsers Enable container queries
container-name container-name: sidebar Modern browsers Name container for targeting
Container Units cqw, cqh, cqi, cqb Modern browsers Relative to container size

Example: Container style queries

/* Container with custom property */
.card-container {
    container-name: card;
    container-type: inline-size;
    --theme: light;
}

/* Query the container's style */
@container card style(--theme: light) {
    .card {
        background: white;
        color: #1a1a1a;
    }
}

@container card style(--theme: dark) {
    .card {
        background: #2d2d2d;
        color: #f0f0f0;
    }
}

/* Dynamic theme switching */
.card-container[data-theme="dark"] {
    --theme: dark;
}

.card-container[data-theme="light"] {
    --theme: light;
}

/* Multiple style conditions */
.section {
    container-type: inline-size;
    --variant: default;
    --size: medium;
}

@container style(--variant: featured) {
    .card {
        border: 2px solid #007acc;
        box-shadow: 0 4px 8px rgba(0,122,204,0.2);
    }
}

@container style(--size: large) {
    .card {
        padding: 2rem;
        font-size: 1.125rem;
    }
}

/* Combined size and style queries */
@container style(--theme: dark) and (min-width: 600px) {
    .card {
        background: #1a1a1a;
        padding: 2rem;
    }
}

/* Boolean custom properties */
.container {
    container-type: inline-size;
    --has-image: 0;  /* false */
}

.container.with-image {
    --has-image: 1;  /* true */
}

@container style(--has-image: 1) {
    .card {
        display: grid;
        grid-template-columns: 200px 1fr;
        gap: 1rem;
    }
}

/* Numeric comparisons (experimental) */
@container style(--priority >= 5) {
    .alert {
        background: #dc3545;
        color: white;
        font-weight: bold;
    }
}

@container style(--priority < 5) {
    .alert {
        background: #ffc107;
        color: #1a1a1a;
    }
}

Example: Practical style query patterns

/* Theme-aware component system */
.theme-container {
    container-name: theme;
    container-type: inline-size;
    --bg-color: white;
    --text-color: #1a1a1a;
    --accent-color: #007acc;
}

/* Light theme */
@container theme style(--bg-color: white) {
    .button {
        background: var(--accent-color);
        color: white;
    }
    
    .card {
        background: white;
        box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    }
}

/* Dark theme */
@container theme style(--bg-color: #1a1a1a) {
    .button {
        background: #404040;
        color: white;
    }
    
    .card {
        background: #2d2d2d;
        box-shadow: 0 2px 4px rgba(0,0,0,0.5);
    }
}

/* Density variants */
.app-container {
    container-name: app;
    container-type: inline-size;
    --density: comfortable;
}

@container app style(--density: compact) {
    .list-item {
        padding: 0.25rem 0.5rem;
        font-size: 0.875rem;
    }
    
    .button {
        padding: 0.25rem 0.75rem;
    }
}

@container app style(--density: comfortable) {
    .list-item {
        padding: 0.5rem 1rem;
        font-size: 1rem;
    }
    
    .button {
        padding: 0.5rem 1rem;
    }
}

@container app style(--density: spacious) {
    .list-item {
        padding: 1rem 1.5rem;
        font-size: 1.125rem;
    }
    
    .button {
        padding: 0.75rem 1.5rem;
    }
}

/* Component state management */
.widget {
    container-name: widget;
    container-type: inline-size;
    --state: idle;
}

.widget[data-loading] {
    --state: loading;
}

.widget[data-error] {
    --state: error;
}

@container widget style(--state: loading) {
    .content {
        opacity: 0.5;
        pointer-events: none;
    }
    
    .spinner {
        display: block;
    }
}

@container widget style(--state: error) {
    .content {
        border-left: 4px solid #dc3545;
    }
    
    .error-message {
        display: block;
        color: #dc3545;
    }
}

/* Responsive + style queries */
.grid-container {
    container-name: grid;
    container-type: inline-size;
    --layout: list;
}

@container grid style(--layout: grid) and (min-width: 600px) {
    .items {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
        gap: 1rem;
    }
}

@container grid style(--layout: list) {
    .items {
        display: flex;
        flex-direction: column;
        gap: 0.5rem;
    }
}
Warning: Container style queries are experimental (Chrome 111+ behind flag). Enable at chrome://flags/#enable-container-queries. Fallback to class-based styling for production. Not all property types supported yet.

5. CSS Houdini Worklets and Custom Functions

API Purpose Browser Support Use Case
Paint API Custom paint() function Chrome 65+, Edge Draw custom backgrounds, borders
Layout API EXPERIMENTAL Custom layout algorithms Chrome (flag) Masonry, custom grids
Animation Worklet High-performance animations Chrome 71+ Parallax, scroll-driven effects
Properties & Values API Typed custom properties Chrome 78+, Safari 16.4+ Animatable custom properties
Font Metrics API Access font metrics Limited Precise typography control

Example: CSS Paint API (Houdini)

/* Register paint worklet (JavaScript) */
/*
// checkerboard-paint.js
class CheckerboardPainter {
    static get inputProperties() {
        return ['--checkerboard-size', '--checkerboard-color'];
    }
    
    paint(ctx, geom, properties) {
        const size = parseInt(properties.get('--checkerboard-size').toString()) || 20;
        const color = properties.get('--checkerboard-color').toString() || '#000';
        
        for (let y = 0; y < geom.height / size; y++) {
            for (let x = 0; x < geom.width / size; x++) {
                if ((x + y) % 2 === 0) {
                    ctx.fillStyle = color;
                    ctx.fillRect(x * size, y * size, size, size);
                }
            }
        }
    }
}

registerPaint('checkerboard', CheckerboardPainter);
*/

/* Load the worklet */
/*
CSS.paintWorklet.addModule('checkerboard-paint.js');
*/

/* Use in CSS */
.checkerboard {
    --checkerboard-size: 20;
    --checkerboard-color: #e0e0e0;
    background-image: paint(checkerboard);
}

/* Animated paint worklet */
/*
// ripple-paint.js
class RipplePainter {
    static get inputProperties() {
        return ['--ripple-x', '--ripple-y', '--ripple-radius', '--ripple-color'];
    }
    
    paint(ctx, geom, properties) {
        const x = parseFloat(properties.get('--ripple-x').toString());
        const y = parseFloat(properties.get('--ripple-y').toString());
        const radius = parseFloat(properties.get('--ripple-radius').toString());
        const color = properties.get('--ripple-color').toString();
        
        ctx.fillStyle = color;
        ctx.beginPath();
        ctx.arc(x, y, radius, 0, 2 * Math.PI);
        ctx.fill();
    }
}

registerPaint('ripple', RipplePainter);
*/

.ripple-button {
    --ripple-x: 50;
    --ripple-y: 50;
    --ripple-radius: 0;
    --ripple-color: rgba(255,255,255,0.3);
    background-image: paint(ripple);
    transition: --ripple-radius 0.6s;
}

.ripple-button:active {
    --ripple-radius: 100;
}

/* Complex paint example: gradient border */
/*
// gradient-border-paint.js
class GradientBorderPainter {
    static get inputProperties() {
        return ['--border-width', '--gradient-angle'];
    }
    
    paint(ctx, geom, properties) {
        const borderWidth = parseInt(properties.get('--border-width').toString()) || 2;
        const angle = parseInt(properties.get('--gradient-angle').toString()) || 45;
        
        const gradient = ctx.createLinearGradient(0, 0, geom.width, geom.height);
        gradient.addColorStop(0, '#667eea');
        gradient.addColorStop(1, '#764ba2');
        
        ctx.strokeStyle = gradient;
        ctx.lineWidth = borderWidth;
        ctx.strokeRect(
            borderWidth / 2,
            borderWidth / 2,
            geom.width - borderWidth,
            geom.height - borderWidth
        );
    }
}

registerPaint('gradient-border', GradientBorderPainter);
*/

.gradient-box {
    --border-width: 4;
    --gradient-angle: 45;
    background-image: paint(gradient-border);
    padding: 1rem;
}

Example: Animation Worklet

/* Animation Worklet for scroll-linked animations */
/*
// parallax-animation.js
registerAnimator('parallax', class {
    constructor(options) {
        this.rate = options.rate || 0.5;
    }
    
    animate(currentTime, effect) {
        const scroll = currentTime * this.rate;
        effect.localTime = scroll;
    }
});
*/

/* CSS setup */
/*
@keyframes parallax {
    from {
        transform: translateY(0);
    }
    to {
        transform: translateY(-200px);
    }
}
*/

.parallax-element {
    animation: parallax linear;
    animation-timeline: scroll();
}

/* JavaScript registration */
/*
await CSS.animationWorklet.addModule('parallax-animation.js');

const element = document.querySelector('.parallax-element');
new WorkletAnimation(
    'parallax',
    new KeyframeEffect(element, [
        { transform: 'translateY(0)' },
        { transform: 'translateY(-200px)' }
    ], {
        duration: 1000,
        iterations: 1
    }),
    document.documentElement.scrollTimeline,
    { rate: 0.5 }
).play();
*/

/* Smooth spring animation worklet */
/*
// spring-animation.js
registerAnimator('spring', class {
    animate(currentTime, effect) {
        const spring = (t, damping = 0.7, stiffness = 100) => {
            const w = Math.sqrt(stiffness);
            const e = Math.exp(-damping * w * t);
            return 1 - e * Math.cos(w * t);
        };
        
        effect.localTime = spring(currentTime / 1000) * effect.getTiming().duration;
    }
});
*/
Note: CSS Houdini enables low-level access to CSS engine. Paint API is best supported. Layout and Animation Worklets are experimental. Use feature detection: if ('paintWorklet' in CSS). Fallback to regular CSS for unsupported browsers.

6. CSS @property Declarations

Feature Syntax Browser Support Purpose
@property Rule @property --name { } Chrome 85+, Safari 16.4+ Register typed custom property
syntax syntax: "<color>" Modern browsers Define property type
inherits inherits: true | false Modern browsers Control inheritance
initial-value initial-value: #000 Modern browsers Default fallback value
Animatable Properties Typed custom properties Modern browsers Enable smooth transitions

Example: @property declarations

/* Register a color property */
@property --theme-color {
    syntax: '<color>';
    inherits: true;
    initial-value: #007acc;
}

/* Now it's animatable! */
.button {
    background: var(--theme-color);
    transition: --theme-color 0.3s;
}

.button:hover {
    --theme-color: #005a9e;
}

/* Number property with units */
@property --spacing {
    syntax: '<length>';
    inherits: false;
    initial-value: 1rem;
}

.card {
    padding: var(--spacing);
    transition: --spacing 0.3s;
}

.card:hover {
    --spacing: 2rem;
}

/* Percentage property */
@property --progress {
    syntax: '<percentage>';
    inherits: false;
    initial-value: 0%;
}

.progress-bar {
    width: var(--progress);
    transition: --progress 1s ease-out;
}

.progress-bar.complete {
    --progress: 100%;
}

/* Angle property for gradients */
@property --gradient-angle {
    syntax: '<angle>';
    inherits: false;
    initial-value: 0deg;
}

.gradient-box {
    background: linear-gradient(var(--gradient-angle), #667eea, #764ba2);
    transition: --gradient-angle 0.5s;
}

.gradient-box:hover {
    --gradient-angle: 90deg;
}

/* Number property (no units) */
@property --scale {
    syntax: '<number>';
    inherits: false;
    initial-value: 1;
}

.zoomable {
    transform: scale(var(--scale));
    transition: --scale 0.3s;
}

.zoomable:hover {
    --scale: 1.1;
}

/* Multiple values */
@property --shadow-offset {
    syntax: '<length>+';  /* One or more lengths */
    inherits: false;
    initial-value: 0px 2px;
}

.elevated {
    box-shadow: var(--shadow-offset) 4px rgba(0,0,0,0.1);
    transition: --shadow-offset 0.3s;
}

.elevated:hover {
    --shadow-offset: 0px 8px;
}

/* Integer property */
@property --columns {
    syntax: '<integer>';
    inherits: false;
    initial-value: 3;
}

.grid {
    display: grid;
    grid-template-columns: repeat(var(--columns), 1fr);
}

/* Transform list */
@property --transform-x {
    syntax: '<length-percentage>';
    inherits: false;
    initial-value: 0%;
}

.slider {
    transform: translateX(var(--transform-x));
    transition: --transform-x 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

.slider.active {
    --transform-x: 100%;
}

Example: Advanced @property patterns

/* Animatable gradient positions */
@property --gradient-start {
    syntax: '<percentage>';
    inherits: false;
    initial-value: 0%;
}

@property --gradient-end {
    syntax: '<percentage>';
    inherits: false;
    initial-value: 100%;
}

.animated-gradient {
    background: linear-gradient(
        90deg,
        transparent var(--gradient-start),
        #007acc var(--gradient-start),
        #007acc var(--gradient-end),
        transparent var(--gradient-end)
    );
    transition: --gradient-start 0.3s, --gradient-end 0.3s;
}

.animated-gradient:hover {
    --gradient-start: 20%;
    --gradient-end: 80%;
}

/* Color interpolation */
@property --bg-color {
    syntax: '<color>';
    inherits: false;
    initial-value: white;
}

@property --text-color {
    syntax: '<color>';
    inherits: false;
    initial-value: black;
}

.theme-transition {
    background: var(--bg-color);
    color: var(--text-color);
    transition: --bg-color 0.3s, --text-color 0.3s;
}

.theme-transition[data-theme="dark"] {
    --bg-color: #1a1a1a;
    --text-color: #f0f0f0;
}

/* Numeric calculations */
@property --multiplier {
    syntax: '<number>';
    inherits: false;
    initial-value: 1;
}

.dynamic-sizing {
    font-size: calc(1rem * var(--multiplier));
    padding: calc(0.5rem * var(--multiplier));
    transition: --multiplier 0.3s;
}

.dynamic-sizing.large {
    --multiplier: 1.5;
}

/* Complex animation with multiple properties */
@property --rotate {
    syntax: '<angle>';
    inherits: false;
    initial-value: 0deg;
}

@property --scale-x {
    syntax: '<number>';
    inherits: false;
    initial-value: 1;
}

@property --scale-y {
    syntax: '<number>';
    inherits: false;
    initial-value: 1;
}

.complex-transform {
    transform: 
        rotate(var(--rotate))
        scaleX(var(--scale-x))
        scaleY(var(--scale-y));
    transition: --rotate 0.5s, --scale-x 0.3s, --scale-y 0.3s;
}

.complex-transform:hover {
    --rotate: 15deg;
    --scale-x: 1.1;
    --scale-y: 0.9;
}

/* JavaScript API for registration */
/*
CSS.registerProperty({
    name: '--my-color',
    syntax: '<color>',
    inherits: false,
    initialValue: '#c0ffee'
});

// Now usable in CSS
element.style.setProperty('--my-color', 'rebeccapurple');
*/

/* Syntax types:
   <length>        - 10px, 2em, 50%
   <number>        - 1, 0.5, 100
   <percentage>    - 50%, 100%
   <length-percentage> - length or percentage
   <color>         - #fff, rgb(), hsl()
   <image>         - url(), gradient()
   <url>           - url()
   <integer>       - 1, 2, 3
   <angle>         - 45deg, 1rad
   <time>          - 1s, 200ms
   <resolution>    - 300dpi, 2dppx
   <transform-function> - rotate(), scale()
   <transform-list> - Multiple transforms
   * - Any value (not animatable)
   
   Combinators:
   <length>+      - One or more
   <length>#      - Comma-separated list
   <length> | <percentage> - Either/or
*/

Example: Practical @property use cases

/* Smooth progress bar animation */
@property --progress-value {
    syntax: '<number>';
    inherits: false;
    initial-value: 0;
}

.progress {
    --progress-value: 0;
    transition: --progress-value 1s ease-out;
}

.progress-bar {
    width: calc(var(--progress-value) * 1%);
    background: linear-gradient(
        90deg,
        #667eea calc(var(--progress-value) * 1%),
        #e0e0e0 calc(var(--progress-value) * 1%)
    );
}

.progress[data-value="75"] {
    --progress-value: 75;
}

/* Animated counter */
@property --counter {
    syntax: '<integer>';
    inherits: false;
    initial-value: 0;
}

.counter {
    --counter: 0;
    counter-reset: num var(--counter);
    transition: --counter 2s;
}

.counter::after {
    content: counter(num);
}

.counter.animate {
    --counter: 100;
}

/* Smooth color transitions in gradients */
@property --color-stop-1 {
    syntax: '<color>';
    inherits: false;
    initial-value: #667eea;
}

@property --color-stop-2 {
    syntax: '<color>';
    inherits: false;
    initial-value: #764ba2;
}

.gradient-bg {
    background: linear-gradient(
        135deg,
        var(--color-stop-1),
        var(--color-stop-2)
    );
    transition: --color-stop-1 0.5s, --color-stop-2 0.5s;
}

.gradient-bg:hover {
    --color-stop-1: #f093fb;
    --color-stop-2: #f5576c;
}

/* Responsive scaling with animation */
@property --responsive-scale {
    syntax: '<number>';
    inherits: false;
    initial-value: 1;
}

.responsive-element {
    font-size: calc(1rem * var(--responsive-scale));
    padding: calc(1rem * var(--responsive-scale));
    transition: --responsive-scale 0.3s;
}

@media (min-width: 768px) {
    .responsive-element {
        --responsive-scale: 1.2;
    }
}

@media (min-width: 1024px) {
    .responsive-element {
        --responsive-scale: 1.5;
    }
}

Modern CSS Features Best Practices

  • Use native CSS nesting for cleaner code (Chrome 120+, Safari 17.2+)
  • Organize with @layer for predictable cascade, define order upfront
  • Apply @scope for component encapsulation without Shadow DOM (Chrome 118+)
  • Container style queries enable theme/state management (experimental, use with caution)
  • CSS Houdini Paint API for custom backgrounds, check support with 'paintWorklet' in CSS
  • Register @property for animatable custom properties with type safety
  • Always provide fallbacks for experimental features, use feature detection
  • Test across browsers, progressive enhancement is key
  • Combine modern features: nesting + @layer + @scope for powerful architecture
  • Monitor browser support at caniuse.com, these features are rapidly evolving