Responsive Web Design Best Practices in 2025

Website Code

Why “responsive” still matters (and what’s new)

In 2025, we still design mobile-first—but with better tools:

  • Logical CSS pixels (ignore physical resolution/DPI; design to content).
  • Dynamic viewport units (dvh, svh, lvh) fix mobile address-bar jumps.
  • Container queries adapt components by their own width, not the window.
  • Modern image formats (AVIF/WebP) and image-set() for responsive background images.

Media queries: content-based breakpoints

Pick breakpoints where your layout needs them—not by device names.

/* Mobile-first breakpoints */
@media (min-width: 600px)  { /* tablet */ }
@media (min-width: 900px)  { /* small laptop */ }
@media (min-width: 1200px) { /* desktop */ }

Container queries (progressive enhancement)

.card { container-type: inline-size; container-name: card; }

@container card (min-width: 28rem) {
  .card--media-right { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
}

Tip: Keep your typography and spacing fluid with clamp() and size components using %, rem, vw, cqw (container query units), not fixed px.

Fluid layouts: Grid & Flex done right

  • Use CSS Grid for page and card layouts; Flexbox for navs/rows.
  • Constrain line length for readability (45–75ch).
  • Set an explicit content width and center with:
    width: min(100% - 2rem, 68rem); margin-inline: auto;
img, video { max-width: 100%; height: auto; }     /* intrinsic sizing */
:root { --content: 68rem; }                        /* ~1088px */
.wrapper { width: min(100% - 2rem, var(--content)); margin-inline: auto; }

Images: AVIF/WebP/JPG/PNG—what to use & how

Use AVIF when possible (best compression), WebP as a widely-supported modern default, JPG for photo fallback, PNG for transparency/UI art (only when SVG isn’t suitable).

Responsive <picture> with srcset + sizes

<picture>
  <source type="image/avif"
          srcset="/img/card-400.avif 400w, /img/card-800.avif 800w, /img/card-1200.avif 1200w">
  <source type="image/webp"
          srcset="/img/card-400.webp 400w, /img/card-800.webp 800w, /img/card-1200.webp 1200w">
  <img src="/img/card-800.jpg" alt="Responsive demo" width="800" height="533"
       sizes="(max-width:600px) 92vw, (max-width:1200px) 50vw, 600px"
       loading="lazy" decoding="async">
</picture>

Best practice

  • Include explicit width/height to avoid CLS.
  • Use loading="lazy" for non-critical images; consider fetchpriority="high" for the LCP/hero image.
  • Prefer AVIF/WebP for photos; use SVG or lossless PNG for pixel-perfect UI if vectors aren’t possible.

Background images with image-set()

.hero {
  min-height: 60vh;
  background: center/cover no-repeat image-set(
    url("/img/hero-m.webp") 1x, url("/img/hero-m@2x.webp") 2x
  );
}
@media (min-width: 48rem) {
  .hero { background: center/cover no-repeat image-set(
    url("/img/hero-d.webp") 1x, url("/img/hero-d@2x.webp") 2x
  );}
}

Sizing guidance (backgrounds)

  • Mobile: ~1200×800
  • Desktop: ~1920×1080 (2×: 3840×2160 if the image is your hero/LCP)
  • Keep files as small as quality allows; target <300–500 KB for hero.

SVG: when, where, why

Use SVG for logos, icons, and diagrams:

  • Infinite resolution; crisp on any DPI.
  • Style with CSS via fill/stroke or inherit currentColor.
  • Small transfer size for geometric art; gzips well.
  • Accessible: add <title> and ARIA; inline when you need stateful styling.

Do not use SVG for photographs or complex textured art (raster is better).

Sprite include + icon usage

<!-- once per page (server/layout include), hidden off-layout -->
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true"
     style="position:absolute;width:0;height:0;overflow:hidden">
  <symbol id="icon-check" viewBox="0 0 24 24">
    <path d="M20.3 5.7a1 1 0 0 1 0 1.4l-10 10a1 1 0 0 1-1.4 0l-5-5a1 1 0 1 1 1.4-1.4L9.3 15l9.3-9.3Z"/>
  </symbol>
</svg>

<button class="btn">
  <span class="icon" aria-hidden="true">
    <svg width="1em" height="1em"><use href="#icon-check"/></svg>
  </span>
  Save
</button>

Frameworks: Bootstrap, Tailwind, “no framework,” and size control

Pick the tool that fits your team and UI, then ship only what you use.

  • Bootstrap 5+ – Rapid scaffolding, utilities, components. Import partial SCSS only:
// app.scss
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/utilities";
  • Tailwind CSS – Utility-first; excellent purging/JIT. Keep content paths tight to avoid bloat.
// tailwind.config.js
module.exports = { content: ["./**/*.{html,md,js}"], theme:{}, plugins:[] }
  • Just CSS (Grid/Flex + utilities) – For simple sites/components, native CSS is smallest and cleanest.

CDN vs. self-hosting frameworks

Choice Use when Pros Cons
CDN Prototypes, internal tools, quick spikes Zero setup, edge-cached, simple version pinning + SRI Third-party dependency, privacy/logging, cache partitioning weakens cross-site reuse
Self-host Production sites/apps, compliance, perf budgets Deterministic builds, tree-shaking/purge, full CSP, no third-party outages CI setup, you own caching/versioning

Rule of thumb: marketing sites & apps → self-host and purge. Demos and PoCs → CDN with SRI and pinned versions.

<link rel="stylesheet"
  href="https://cdn.example.com/bootstrap/5.3.3/css/bootstrap.min.css"
  integrity="sha384-…"
  crossorigin="anonymous">

Performance & testing checklist (2025)

  • Core Web Vitals: LCP ≤2.5s, CLS ≤0.1, INP ≤200ms.
  • Images: AVIF/WebP + explicit dimensions; lazy-load non-LCP; compress aggressively.
  • CSS: purge/treeshake; inline critical if needed; avoid blocking fonts.
  • JS: bundle split, defer modules; avoid shipping unused libs.
  • Accessibility: color contrast, focus states, keyboard nav, prefers-reduced-motion.
  • QA: Chrome/Edge/Firefox DevTools device modes, throttled networks; Playwright/Cypress multi-viewport tests.

Drop-in starter you can use today

  • CSS: /assets/css/responsive-starter.css with fluid type/spacing, helpers, and container queries.
  • SVG include: _includes/svg-sprite.html with icons (<use href="#icon-…">).
  • Demo page: index.md shows <picture>/srcset and background image-set() patterns.

Live demo & repo:
Starter → https://michalferber.me/responsive-starter-repo/
GitHub → https://github.com/MichalAFerber/responsive-starter-repo

Final thought

Don’t chase devices. Build fluid components, test across ranges, and ship only what users need on the network they have. That’s responsive design in 2025.

Share: