Introduction to CSS Presentation Part 1
Updated: March 27, 2026
TL;DR
Modern CSS (2026) is about Container Queries, the :has() selector, Cascade Layers, and native nesting. Grid and Flexbox remain the layout foundations. CSS custom properties manage design tokens. Tailwind CSS 4 adds native nesting and performance improvements, but vanilla CSS can now do much of what Tailwind does.
If your last deep dive into CSS was a few years ago, prepare for surprises. CSS has evolved dramatically. The language that once felt limited—"just styling"—now handles layout complexity, logic (:has()), design tokens, and responsive adaptation that used to require JavaScript or build tools.
This guide covers modern CSS essentials for 2026: the core layout tools you've always needed (Grid, Flexbox), the revolutionary features (Container Queries), and the syntax improvements (native nesting) that make CSS more enjoyable to write. Whether you're starting fresh or catching up, understanding these fundamentals unlocks the rest.
CSS Grid and Flexbox: The Layout Foundation
Grid and Flexbox are not advanced—they're essential. Every modern layout uses one or both.
Flexbox: One-Dimensional Layout
Flexbox arranges items in a single direction (row or column).
/* Navigation bar: items in a row */
.nav {
display: flex;
gap: 1rem;
justify-content: space-between; /* Space between nav items and logo */
align-items: center; /* Vertically centered */
}
/* Form: items in a column */
.form {
display: flex;
flex-direction: column;
gap: 1rem;
}
/* Responsive: row on desktop, column on mobile */
@media (max-width: 768px) {
.nav {
flex-direction: column;
}
}
Key properties:
flex-direction: row | columnjustify-content: Controls spacing along the main axis (row/column direction)align-items: Controls alignment perpendicular to main axisflex-wrap: Wrap items to multiple linesgap: Space between items
CSS Grid: Two-Dimensional Layout
Grid arranges items in rows and columns simultaneously.
/* Dashboard layout */
.dashboard {
display: grid;
grid-template-columns: 250px 1fr 300px; /* Sidebar, main, aside */
grid-template-rows: auto 1fr auto; /* Header, content, footer */
gap: 1rem;
height: 100vh;
}
.header {
grid-column: 1 / -1; /* Span all columns */
}
.sidebar {
grid-column: 1;
grid-row: 2;
}
.main {
grid-column: 2;
grid-row: 2;
}
.footer {
grid-column: 1 / -1;
}
The Difference: When to Use Each
| Layout | Flexbox | Grid |
|---|---|---|
| Navigation bar | ✓ | |
| Product list (1-column) | ✓ | |
| Form inputs | ✓ | |
| Dashboard (2D) | ✓ | |
| Card grid with subgrid | ✓ | |
| Sidebar + main content | ✓ |
Most complex layouts use both:
.dashboard {
display: grid;
grid-template-columns: 250px 1fr;
}
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1rem;
}
.card {
display: flex;
flex-direction: column;
}
Grid handles the page structure, Flexbox handles individual component layouts.
CSS Custom Properties (Variables)
Custom properties store reusable values. They're dynamic (can change at runtime) unlike SASS/LESS variables.
Basic Usage
:root {
--color-primary: #0066ff;
--color-text: #333;
--spacing-base: 1rem;
--radius: 0.5rem;
}
button {
background: var(--color-primary);
padding: var(--spacing-base);
border-radius: var(--radius);
color: white;
}
Dynamic Theming
/* Light theme (default) */
:root {
--bg: #ffffff;
--text: #000000;
}
/* Dark theme */
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a1a;
--text: #ffffff;
}
}
/* User-selected dark mode */
body.dark-mode {
--bg: #1a1a1a;
--text: #ffffff;
}
body {
background: var(--bg);
color: var(--text);
}
Scoped Variables
.card {
--card-bg: #f5f5f5;
--card-padding: 1.5rem;
}
.card-header {
background: var(--card-bg);
padding: var(--card-padding);
}
/* Different card style */
.card.featured {
--card-bg: #ffd700;
--card-padding: 2rem;
/* Header automatically uses new values */
}
Container Queries: Components Adapt to Context
Previously, only media queries existed—they measure the viewport. Container Queries measure the component's container. Size container queries reached Baseline Newly Available in February 2023 and Baseline Widely Available in August 2025, so they're safe for production today.
/* Define a container context */
.card-container {
container-type: inline-size;
}
/* Query the container's width */
@container (min-width: 400px) {
.card-content {
display: grid;
grid-template-columns: 1fr 1fr;
}
}
@container (max-width: 300px) {
.card-content {
display: block;
}
}
A component inside a 250px sidebar displays as a single column. The same component in a 800px main area displays as two columns. Same code, different contexts.
This is revolutionary because components are now truly reusable and context-aware.
The :has() Selector
:has() selects elements based on their children or siblings. It's "parent selection"—something CSS couldn't do before. :has() reached Baseline Newly Available in December 2023 (Firefox 121 was the last to ship) and is widely available across modern browsers.
/* Select card if it contains an image */
.card:has(img) {
display: grid;
grid-template-columns: 200px 1fr;
}
/* Select form if it has an error */
.form:has(.error) {
border: 2px solid red;
}
/* Select heading followed by text */
h2:has(+ p) {
margin-bottom: 0.5rem;
}
/* Style based on input state */
form:has(input:invalid) {
background: #ffe0e0;
}
/* Dark mode: if user prefers dark, select background */
@media (prefers-color-scheme: dark) {
body:has(.dark-mode-toggle:checked) {
--bg: #1a1a1a;
}
}
:has() enables CSS-only responsive behavior without media queries.
Cascade Layers and CSS Nesting
Cascade Layers
Control specificity conflicts with layers:
/* Define layer order */
@layer reset, base, theme, components, utilities;
@layer reset {
* { margin: 0; padding: 0; }
}
@layer base {
body { font-family: system-ui; }
}
@layer theme {
:root {
--color-primary: blue;
}
}
@layer components {
.button { background: var(--color-primary); }
}
@layer utilities {
.text-center { text-align: center; }
}
/* Utilities override components override theme—determined by layer order */
Layers prevent specificity wars. A utility class in the utilities layer always overrides a component in the components layer, regardless of specificity.
Native CSS Nesting
Native nesting reached Baseline Newly Available in August 2023 (Chrome 112, Safari 16.5, Firefox 117). No more repeating selectors:
/* Before: repetition */
.card { border: 1px solid #ccc; }
.card-header { background: #f5f5f5; }
.card-body { padding: 1rem; }
/* After: native nesting */
.card {
border: 1px solid #ccc;
& .header {
background: #f5f5f5;
}
& .body {
padding: 1rem;
}
/* Hover state */
&:hover {
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
/* Media query inside */
@media (max-width: 600px) {
flex-direction: column;
}
}
The & selector refers to the parent. This syntax is now native CSS (no Sass required).
View Transitions API
Same-document View Transitions reached Baseline Newly Available in October 2025 once Firefox 133 shipped support, joining Chrome 111+ and Safari 18+. Cross-document transitions (multi-page apps) work in Chrome 126+ and Safari 18.2+ but are not yet supported in Firefox as of May 2026 — use progressive enhancement.
Animate between page states:
.modal {
view-transition-name: modal;
}
@supports (view-transition-name: modal) {
::view-transition-new(modal) {
animation: slideUp 0.5s;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(50px);
}
}
}
When you transition to a new modal state, the browser automatically animates between the old and new states.
document.startViewTransition(() => {
updateDOM(); // Change the DOM
// Browser automatically animates the transition
});
This creates smooth transitions without manual JavaScript animation logic.
Tailwind CSS 4 vs. Vanilla CSS
Tailwind CSS v4.0 shipped on January 22, 2025; the v4.x line continues to evolve (v4.2 added a webpack plugin and logical-property utilities in February 2026). The v4 architecture brings:
- Native CSS nesting in source files
- CSS custom properties for theme customization (no JS config required)
- A new Oxide engine — full builds up to ~5x faster, incremental builds in microseconds
- One-line setup (
@import "tailwindcss") with automatic template detection
When to use Tailwind:
- Rapid prototyping (pre-built responsive utilities)
- Team standardization (consistent spacing, colors)
- Complex responsive needs (with Container Queries support)
When vanilla CSS is sufficient:
- Simple, static sites
- Design systems that rarely change
- When build tools feel excessive
- Teams comfortable with CSS
Example: Same component in Tailwind vs. vanilla:
Tailwind:
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 p-4">
<div className="border rounded-lg p-4 hover:shadow-lg">
<h3 className="text-lg font-bold mb-2">Title</h3>
<p>Content</p>
</div>
</div>
Vanilla CSS with modern features:
<div className="card-grid">
<article className="card">
<h3>Title</h3>
<p>Content</p>
</article>
</div>
<style>
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1rem;
padding: 1rem;
}
.card {
border: 1px solid #ccc;
border-radius: 0.5rem;
padding: 1rem;
&:hover {
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
}
</style>
Both are valid. Choose based on project needs, not hype.
@starting-style for Transitions
@starting-style reached Baseline Newly Available in August 2024. It defines the values an element transitions from when it is first rendered (or transitions back into the DOM):
.toast {
opacity: 1;
transform: translateX(0);
transition: opacity 0.3s, transform 0.3s;
}
/* The "from" state — applied only on first render */
@starting-style {
.toast {
opacity: 0;
transform: translateX(-100%);
}
}
When a .toast is added to the DOM, the browser applies the @starting-style values first, then transitions to the normal .toast values. This finally makes it possible to animate elements appearing from display: none without JavaScript hacks.
Key Takeaways
Modern CSS (2026) handles what used to require JavaScript or build tools:
- Grid and Flexbox: Master these for any layout
- Custom properties: Dynamic, scoped design tokens
- Container Queries: Context-aware component styles
:has()selector: CSS-only logic based on child elements- Native nesting: Cleaner, DRY syntax
- Cascade Layers: Managed specificity
- View Transitions API: Smooth state transitions
- @starting-style: Entry animations
CSS is no longer just styling. It's a powerful language for layout, logic, and interaction. The more you learn modern CSS, the less JavaScript you need for presentation.