CSS Nesting
Native CSS Nesting allows writing nested style rules directly in CSS, without requiring a preprocessor like Sass or Less.
The Old Way
Section titled “The Old Way”// Sass/SCSS nesting.card { padding: 16px; background: white; border-radius: 8px;
&:hover { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); }
.card-header { font-weight: bold; margin-bottom: 8px; }
.card-body { color: #666;
p { margin-bottom: 1em;
&:last-child { margin-bottom: 0; } } }
&.card-featured { border: 2px solid gold; }}/* Compiled CSS output */.card { padding: 16px; background: white; border-radius: 8px;}.card:hover { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);}.card .card-header { font-weight: bold; margin-bottom: 8px;}.card .card-body { color: #666;}.card .card-body p { margin-bottom: 1em;}.card .card-body p:last-child { margin-bottom: 0;}.card.card-featured { border: 2px solid gold;}Problems:
- Requires build step and preprocessor
- Different syntax from native CSS
- Build tool configuration overhead
- Debugging maps compiled code to source
- Team needs to learn preprocessor syntax
The Modern Way
Section titled “The Modern Way”/* Native CSS Nesting */.card { padding: 16px; background: white; border-radius: 8px;
&:hover { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); }
.card-header { font-weight: bold; margin-bottom: 8px; }
.card-body { color: #666;
p { margin-bottom: 1em;
&:last-child { margin-bottom: 0; } } }
&.card-featured { border: 2px solid gold; }}Benefits:
- No build step required
- Works directly in browsers
- Familiar syntax for Sass users
- Better developer experience
- Standard CSS feature
Nesting Syntax
Section titled “Nesting Syntax”Basic Nesting
Section titled “Basic Nesting”.parent { color: blue;
.child { color: red; }}
/* Equivalent to: */.parent { color: blue;}.parent .child { color: red;}The & Selector
Section titled “The & Selector”.button { background: blue;
/* & represents the parent selector */ &:hover { background: darkblue; }
&:focus { outline: 2px solid orange; }
&:active { transform: scale(0.98); }
/* Compound selectors */ &.primary { background: green; }
&.disabled { opacity: 0.5; pointer-events: none; }}Nesting with Combinators
Section titled “Nesting with Combinators”.nav { /* Direct child */ > li { display: inline-block; }
/* Adjacent sibling */ + .content { margin-top: 20px; }
/* General sibling */ ~ .footer { border-top: 1px solid #ccc; }}Nested Media Queries
Section titled “Nested Media Queries”.container { padding: 16px;
@media (min-width: 768px) { padding: 24px; }
@media (min-width: 1024px) { padding: 32px; }}
/* Components stay together */.card { display: block; padding: 16px;
@media (min-width: 600px) { display: flex; padding: 24px; }
.card-image { width: 100%;
@media (min-width: 600px) { width: 200px; } }}Nested Container Queries
Section titled “Nested Container Queries”.widget { container-type: inline-size; padding: 16px;
@container (min-width: 400px) { padding: 24px; display: grid; grid-template-columns: 1fr 1fr; }}Practical Examples
Section titled “Practical Examples”Component Styles
Section titled “Component Styles”.button { display: inline-flex; align-items: center; gap: 8px; padding: 8px 16px; border: none; border-radius: 4px; font: inherit; cursor: pointer; background: var(--color-primary); color: white;
&:hover { background: var(--color-primary-dark); }
&:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
&:disabled { opacity: 0.6; cursor: not-allowed; }
/* Variants */ &.secondary { background: transparent; color: var(--color-primary); border: 1px solid currentColor;
&:hover { background: var(--color-primary-light); } }
&.small { padding: 4px 8px; font-size: 0.875rem; }
&.large { padding: 12px 24px; font-size: 1.125rem; }
/* Icon inside button */ svg { width: 1em; height: 1em; }}Form Component
Section titled “Form Component”.form-group { margin-bottom: 1rem;
label { display: block; margin-bottom: 0.5rem; font-weight: 500; }
input, textarea, select { width: 100%; padding: 0.5rem; border: 1px solid #ccc; border-radius: 4px;
&:focus { border-color: var(--color-primary); outline: none; box-shadow: 0 0 0 3px var(--color-primary-light); }
&:invalid { border-color: red; } }
.error-message { color: red; font-size: 0.875rem; margin-top: 0.25rem; }
/* Has error state */ &:has(:invalid) { label { color: red; } }}Navigation
Section titled “Navigation”.nav { display: flex; gap: 1rem; list-style: none; padding: 0; margin: 0;
li { position: relative;
a { display: block; padding: 0.5rem 1rem; color: inherit; text-decoration: none;
&:hover { background: #f0f0f0; }
&[aria-current='page'] { font-weight: bold; color: var(--color-primary); } }
/* Dropdown */ ul { position: absolute; top: 100%; left: 0; display: none; min-width: 200px; background: white; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); }
&:hover ul { display: block; } }
@media (max-width: 768px) { flex-direction: column;
li ul { position: static; box-shadow: none; } }}Card with States
Section titled “Card with States”.card { padding: 1rem; border: 1px solid #ddd; border-radius: 8px; background: white; transition: all 0.2s;
&:hover { border-color: var(--color-primary); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); }
&.selected { border-color: var(--color-primary); background: var(--color-primary-light); }
&.disabled { opacity: 0.6; pointer-events: none; }
.card-title { font-size: 1.25rem; font-weight: bold; margin-bottom: 0.5rem; }
.card-content { color: #666; }
.card-footer { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid #eee; display: flex; gap: 0.5rem; }}Browser Support
Section titled “Browser Support”Supported in all modern browsers. See caniuse.com/css-nesting.
Performance Considerations
Section titled “Performance Considerations”- Parsed at load time like regular CSS
- No runtime performance difference
- Produces same result as flat CSS
- May improve authoring performance (easier to maintain)
When to Use
Section titled “When to Use”Use CSS Nesting when:
- Writing component-scoped styles
- Grouping related selectors logically
- Managing pseudo-classes and pseudo-elements
- Writing responsive styles inline with components
- You don’t need other preprocessor features
Consider preprocessors when:
- You need mixins, functions, or loops
- Working on projects requiring older browser support
- Your build pipeline already includes preprocessing
- You need features beyond what native CSS offers