- Semantic HTML and native forms
- Use landmarks (header, nav, main, aside), ordered headings, button for actions and a for navigation. Native forms with label, fieldset, input types and constraint validation (required, pattern, :user-invalid) give you a lot of behavior for free. The dialog element with showModal() and the popover attribute handle focus, the top layer and Esc without custom code.
- Layout: Flexbox, Grid, subgrid
- Flexbox for one-dimensional layout, Grid for two dimensions, and subgrid so child cards align to the parent grid. Learn min(), max(), clamp(), the dvh/svh units and logical properties (margin-inline, padding-block) so layouts also work in RTL languages.
- Container queries and :has()
- Container queries (@container, cqi units) let a component respond to the size of its container instead of the viewport, which fits design systems well. :has() is a parent selector: style a card when it contains an image, or a form when an input is invalid, removing many conditional classes set from JavaScript.
- Cascade layers, nesting and specificity
- @layer lets you declare priority order (reset, base, components, utilities) independently of specificity, so library CSS stops overriding yours in confusing ways. Combine it with native CSS nesting, :where() to keep specificity at zero, and custom properties as design tokens.
- View transitions and scroll-driven animation
- The View Transition API animates state or page changes with document.startViewTransition() and view-transition-name, and same-document transitions now work across the major browsers. Scroll-driven animations and anchor positioning replace many JavaScript libraries; always check Baseline status and respect prefers-reduced-motion.