Modern Web Fundamentals
Invoker Commands
2024–2025<button commandfor="my-dialog" command="show-modal">
Open Dialog
</button>
<button popovertarget="my-popover">
Toggle Popover
</button>
<dialog id="my-dialog">
<p>Opened declaratively!</p>
<button commandfor="my-dialog" command="close">Close</button>
</dialog>
<div id="my-popover" popover="auto">
Popover content
</div>Declarative UI wiring. Buttons can invoke dialogs and popovers without JavaScript event handlers.
View Transitions (CSS)
2024–2025@view-transition {
navigation: auto;
}
.item {
view-transition-name: item;
}CSS-only view transitions enable smooth animations between DOM states using pure CSS, no JavaScript API required.
Popover API
2024<button popovertarget="my-popover">
Toggle
</button>
<div id="my-popover" popover="auto">
Popover content
</div>Built-in popover functionality with automatic focus management, dismissal behavior, and proper layering without JavaScript.
CSS Nesting
2024.card {
padding: 1rem;
& .title {
font-weight: bold;
&:hover {
color: blue;
}
}
}Native CSS nesting eliminates the need for preprocessors like Sass, allowing you to nest selectors directly in stylesheets.
CSS Anchor Positioning
2024.anchor {
anchor-name: --my-anchor;
}
.tooltip {
position: absolute;
position-anchor: --my-anchor;
bottom: calc(anchor(top) - 0.5rem);
left: anchor(center);
transform: translateX(-50%);
}Position elements relative to other elements using pure CSS. Tooltips, dropdowns, and popovers can be positioned without JavaScript calculations.
Container Queries
2023.container {
container-type: inline-size;
}
@container (min-width: 400px) {
.card { grid-template-columns: 1fr 1fr; }
}Components respond to their container's size instead of the viewport, enabling truly modular responsive components.
inert Attribute
2023<div inert>
<input /> <!-- Cannot be focused -->
<button>Click</button> <!-- Disabled -->
</div>Native focus and interaction suppression for modal dialogs and overlays. Disables all user interaction including focus, clicks, and assistive technology.
Viewport Units
2023.hero {
height: 100dvh; /* Dynamic */
height: 100svh; /* Small */
height: 100lvh; /* Large */
}Dynamic viewport units (dvh, svh, lvh) that account for mobile browser UI, solving the classic mobile viewport height problem.
aspect-ratio
2021.video {
aspect-ratio: 16 / 9;
width: 100%;
}Maintain intrinsic aspect ratios without padding hacks. Perfect for responsive images, videos, and containers.
Native Lazy Loading
2019–2020<img src="image.jpg" loading="lazy" alt="..." />
<iframe src="embed.html" loading="lazy"></iframe>Images and iframes lazy-load automatically without JavaScript, improving page load performance and reducing bandwidth.
:focus-visible
2022button:focus {
outline: none;
}
button:focus-visible {
outline: 2px solid var(--primary);
outline-offset: 2px;
}Keyboard focus styling without ugly mouse outlines. Show focus rings only when users navigate with keyboard, not when clicking with mouse.
:has()
2023/* Style parent when child is checked */
.form:has(input:checked) {
background: var(--primary-light);
border-color: var(--primary);
}
/* Style label when input is focused */
.field:has(input:focus) .label {
color: var(--primary);
}Parent & relational selectors. CSS can finally react to child state. Select elements based on their descendants or siblings.
Preference Queries
2020–2023@media (prefers-color-scheme: dark) {
:root { --bg: #1a1a2e; }
}
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; }
}
@media (prefers-contrast: more) {
.card { border: 2px solid currentColor; }
}Respect user preferences with media queries for color scheme, reduced motion, contrast, and more. Build accessible experiences by default.
Cascade Layers
2022@layer reset, base, components, utilities;
@layer base {
.text { color: gray; }
}
@layer components {
.text { color: black; } /* Wins! */
}Explicit control over the cascade with @layer. Define layer order to manage specificity without fighting selector weights.
Web Components
2019Web Components are a suite of three main web platform APIs that allow you to create custom, reusable, encapsulated HTML elements. The three standards work together to provide a complete solution for building framework-independent components.
Shadow DOM
2019const element = document.querySelector('#host');
const shadow = element.attachShadow({ mode: 'open' });
shadow.innerHTML = `
<style>
.card {
background: linear-gradient(135deg, #667eea, #764ba2);
padding: 1.5rem;
border-radius: 1rem;
color: white;
}
</style>
<div class="card">
<h3>Encapsulated Component</h3>
<p>Styles are isolated from the rest of the page</p>
</div>
`;Shadow DOM provides encapsulation for JavaScript, CSS, and templating. It allows you to attach a hidden, isolated DOM tree to an element, preventing style and script leakage between components.
HTML Templates
2019<template id="card-template">
<div class="card">
<h3><slot name="title">Default Title</slot></h3>
<p><slot>Default content</slot></p>
</div>
</template>
<script>
const template = document.getElementById('card-template');
const clone = template.content.cloneNode(true);
document.body.appendChild(clone);
</script>The <template> element holds HTML that is not rendered immediately but can be cloned and inserted into the document via JavaScript. Templates provide a standard way to declare fragments of markup for later use.
Custom Elements
2019class MyElement extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<div style="padding: 1rem; background: hsl(var(--muted)); border-radius: 0.5rem;">
<strong>👋 Custom Element:</strong> ${this.getAttribute('name') || 'World'}
</div>
`;
}
}
customElements.define('my-element', MyElement);
// Usage in HTML
<my-element name="Modern Web"></my-element>Custom Elements allow you to define your own HTML tags with custom behavior. They have lifecycle callbacks and can be used just like any standard HTML element, providing a way to create reusable components.