Responsive Design Implementation Patterns

1. CSS Grid Flexbox Layout Systems

Property Syntax Description Use Case
CSS Grid display: grid 2D layout system for rows and columns Page layouts, complex grids
grid-template-columns repeat(auto-fit, minmax(250px, 1fr)) Responsive columns without media queries Card grids, galleries
Flexbox display: flex 1D layout for rows or columns Navigation, components
flex-wrap flex-wrap: wrap Items wrap to next line when space runs out Responsive lists
gap gap: 1rem Spacing between grid/flex items Consistent spacing
Grid Areas grid-template-areas Named template areas for semantic layouts Complex page structures

Example: CSS Grid and Flexbox responsive layouts

/* Responsive Grid - Auto-fit with minmax */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 2rem;
  padding: 1rem;
}

/* Responsive without media queries! */
.card {
  background: white;
  padding: 1.5rem;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

/* CSS Grid with named areas */
.page-layout {
  display: grid;
  grid-template-areas:
    "header header header"
    "sidebar main aside"
    "footer footer footer";
  grid-template-columns: 200px 1fr 200px;
  grid-template-rows: auto 1fr auto;
  gap: 1rem;
  min-height: 100vh;
}

.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }

/* Responsive grid areas */
@media (max-width: 768px) {
  .page-layout {
    grid-template-areas:
      "header"
      "main"
      "sidebar"
      "aside"
      "footer";
    grid-template-columns: 1fr;
  }
}

/* Flexbox responsive navigation */
.nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem;
  padding: 1rem;
}

.nav-links {
  display: flex;
  gap: 2rem;
  flex-wrap: wrap;
}

/* Responsive flex direction */
.container {
  display: flex;
  flex-direction: row;
  gap: 2rem;
}

@media (max-width: 768px) {
  .container {
    flex-direction: column;
  }
}

/* Holy Grail Layout with Flexbox */
.holy-grail {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.holy-grail-body {
  display: flex;
  flex: 1;
}

.holy-grail-content {
  flex: 1;
}

.holy-grail-nav,
.holy-grail-ads {
  flex: 0 0 12em;
}

.holy-grail-nav {
  order: -1;
}

@media (max-width: 768px) {
  .holy-grail-body {
    flex-direction: column;
  }
  .holy-grail-nav,
  .holy-grail-ads {
    order: 0;
  }
}

/* Advanced Grid - Masonry-style layout */
.masonry {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  grid-auto-rows: 10px;
  gap: 1rem;
}

.masonry-item {
  grid-row-end: span 20; /* Adjust based on content height */
}

/* Subgrid (modern browsers) */
.parent-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}

.child-grid {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: span 3;
}

2. Tailwind CSS Responsive Utilities

Breakpoint Syntax Min-Width Example
sm sm:text-lg 640px Small devices (tablets)
md md:flex-row 768px Medium devices (small laptops)
lg lg:grid-cols-3 1024px Large devices (desktops)
xl xl:container 1280px Extra large screens
2xl 2xl:px-8 1536px Ultra-wide screens
Custom theme.screens Configurable Custom breakpoints

Example: Tailwind CSS responsive design patterns

// tailwind.config.js - Custom breakpoints
module.exports = {
  theme: {
    screens: {
      'xs': '475px',
      'sm': '640px',
      'md': '768px',
      'lg': '1024px',
      'xl': '1280px',
      '2xl': '1536px',
      '3xl': '1920px',
    },
    extend: {
      spacing: {
        '128': '32rem',
      },
    },
  },
};

{/* Responsive grid with Tailwind */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
  <div className="bg-white p-4 rounded-lg shadow">Card 1</div>
  <div className="bg-white p-4 rounded-lg shadow">Card 2</div>
  <div className="bg-white p-4 rounded-lg shadow">Card 3</div>
</div>

{/* Mobile-first responsive typography */}
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl xl:text-6xl font-bold">
  Responsive Heading
</h1>

{/* Responsive flex direction */}
<div className="flex flex-col md:flex-row gap-4">
  <aside className="w-full md:w-1/4 bg-gray-100 p-4">Sidebar</aside>
  <main className="w-full md:w-3/4 p-4">Main Content</main>
</div>

{/* Responsive visibility */}
<button className="hidden md:block">Desktop Only</button>
<button className="md:hidden">Mobile Only</button>

{/* Responsive padding and margins */}
<div className="px-4 sm:px-6 md:px-8 lg:px-12 xl:px-16">
  <div className="max-w-7xl mx-auto">
    Centered content with responsive padding
  </div>
</div>

{/* Responsive navigation */}
<nav className="bg-white shadow">
  <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
    <div className="flex justify-between h-16">
      <div className="flex">
        <div className="flex-shrink-0 flex items-center">
          Logo
        </div>
        <div className="hidden sm:ml-6 sm:flex sm:space-x-8">
          <a href="#" className="border-b-2 px-3 py-2">Home</a>
          <a href="#" className="px-3 py-2">About</a>
          <a href="#" className="px-3 py-2">Contact</a>
        </div>
      </div>
      <div className="sm:hidden">
        <button>Menu</button>
      </div>
    </div>
  </div>
</nav>

{/* Responsive container with breakpoint-specific max-widths */}
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
  {/* Container automatically adjusts max-width at each breakpoint */}
</div>

{/* Arbitrary values for custom responsive design */}
<div className="grid grid-cols-[repeat(auto-fit,minmax(250px,1fr))] gap-4">
  Custom grid
</div>

{/* Responsive aspect ratios */}
<div className="aspect-video md:aspect-square lg:aspect-[16/9]">
  <img src="image.jpg" className="w-full h-full object-cover" />
</div>

{/* Dark mode + responsive */}
<div className="bg-white dark:bg-gray-800 p-4 sm:p-6 md:p-8">
  <h2 className="text-gray-900 dark:text-white text-lg sm:text-xl md:text-2xl">
    Responsive dark mode content
  </h2>
</div>

3. Container Queries CSS Modern NEW

Property Syntax Description Advantage
container-type container-type: inline-size Establishes containment context Component-level responsiveness
container-name container-name: card Names container for querying Multiple container contexts
@container @container (min-width: 400px) Query container dimensions, not viewport Truly reusable components
cqw/cqh width: 50cqw Container query width/height units Fluid component sizing
container shorthand container: card / inline-size Combined name and type declaration Cleaner syntax

Example: Container queries for component-based responsiveness

/* Container query setup */
.card-container {
  container-type: inline-size;
  container-name: card;
}

/* Component styles based on container width */
.card {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1rem;
  background: white;
  border-radius: 8px;
}

/* When container is at least 400px wide */
@container card (min-width: 400px) {
  .card {
    flex-direction: row;
    align-items: center;
  }

  .card-image {
    width: 200px;
    height: 200px;
  }

  .card-content {
    flex: 1;
  }
}

/* When container is at least 600px wide */
@container card (min-width: 600px) {
  .card {
    padding: 2rem;
  }

  .card-title {
    font-size: 2rem;
  }
}

/* Product card with container queries */
.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 2rem;
}

.product-card {
  container-type: inline-size;
  background: white;
  border-radius: 12px;
  overflow: hidden;
}

.product-content {
  padding: 1rem;
}

.product-details {
  display: none; /* Hidden by default */
}

/* Show details when card is wide enough */
@container (min-width: 350px) {
  .product-details {
    display: block;
  }

  .product-button {
    width: 100%;
  }
}

@container (min-width: 500px) {
  .product-content {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
  }
}

/* Container query units */
.responsive-text {
  container-type: inline-size;
}

.responsive-text h1 {
  font-size: calc(5cqw + 1rem);
  /* Font size relative to container width */
}

/* Named containers with Tailwind (plugin) */
.sidebar {
  container-type: inline-size;
  container-name: sidebar;
}

@container sidebar (min-width: 300px) {
  .sidebar-nav {
    flex-direction: row;
  }
}

/* Nested containers */
.page {
  container-type: inline-size;
  container-name: page;
}

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

/* Query specific container */
@container page (min-width: 1200px) {
  .page-header {
    display: flex;
  }
}

@container section (min-width: 400px) {
  .section-content {
    columns: 2;
  }
}

/* React component with container queries */
function ProductCard({ product }) {
  return (
    <div className="product-card">
      <img src={product.image} alt={product.name} />
      <div className="product-content">
        <h3>{product.name}</h3>
        <p className="product-price">${product.price}</p>
        <p className="product-details">{product.description}</p>
        <button className="product-button">Add to Cart</button>
      </div>
    </div>
  );
}

4. Intersection Observer Lazy Loading

Feature Syntax Description Use Case
IntersectionObserver new IntersectionObserver(callback) Observes element visibility in viewport Lazy loading, infinite scroll
threshold { threshold: 0.5 } Percentage of element visible to trigger Precise loading control
rootMargin { rootMargin: '100px' } Margin around viewport to trigger early Preload before visible
observe() observer.observe(element) Start observing an element Track visibility
unobserve() observer.unobserve(element) Stop observing an element Cleanup after loading
loading="lazy" <img loading="lazy"> Native browser lazy loading Simple image/iframe lazy load

Example: Intersection Observer for lazy loading

// Vanilla JS lazy loading images
const images = document.querySelectorAll('img[data-src]');

const imageObserver = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      img.classList.add('loaded');
      observer.unobserve(img);
    }
  });
}, {
  rootMargin: '50px', // Load 50px before entering viewport
  threshold: 0.1,
});

images.forEach(img => imageObserver.observe(img));

// React lazy loading component
import { useEffect, useRef, useState } from 'react';

function LazyImage({ src, alt, placeholder }) {
  const [isLoaded, setIsLoaded] = useState(false);
  const [isInView, setIsInView] = useState(false);
  const imgRef = useRef<HTMLImageElement>(null);

  useEffect(() => {
    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setIsInView(true);
          observer.disconnect();
        }
      },
      { rootMargin: '100px' }
    );

    if (imgRef.current) {
      observer.observe(imgRef.current);
    }

    return () => observer.disconnect();
  }, []);

  return (
    <img
      ref={imgRef}
      src={isInView ? src : placeholder}
      alt={alt}
      onLoad={() => setIsLoaded(true)}
      style={{
        opacity: isLoaded ? 1 : 0.5,
        transition: 'opacity 0.3s',
      }}
    />
  );
}

// Infinite scroll implementation
function InfiniteScroll() {
  const [items, setItems] = useState([]);
  const [page, setPage] = useState(1);
  const [hasMore, setHasMore] = useState(true);
  const loaderRef = useRef(null);

  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0].isIntersecting && hasMore) {
          loadMore();
        }
      },
      { threshold: 1.0 }
    );

    if (loaderRef.current) {
      observer.observe(loaderRef.current);
    }

    return () => observer.disconnect();
  }, [hasMore, page]);

  const loadMore = async () => {
    const newItems = await fetchItems(page);
    setItems(prev => [...prev, ...newItems]);
    setPage(prev => prev + 1);
    setHasMore(newItems.length > 0);
  };

  return (
    <div>
      {items.map(item => <div key={item.id}>{item.name}</div>)}
      <div ref={loaderRef}>{hasMore && 'Loading...'}</div>
    </div>
  );
}

// Custom hook for intersection observer
function useIntersectionObserver(
  ref: React.RefObject<Element>,
  options: IntersectionObserverInit = {}
) {
  const [isIntersecting, setIsIntersecting] = useState(false);

  useEffect(() => {
    const observer = new IntersectionObserver(([entry]) => {
      setIsIntersecting(entry.isIntersecting);
    }, options);

    if (ref.current) {
      observer.observe(ref.current);
    }

    return () => observer.disconnect();
  }, [ref, options]);

  return isIntersecting;
}

// Usage
function AnimatedSection() {
  const ref = useRef(null);
  const isVisible = useIntersectionObserver(ref, { threshold: 0.5 });

  return (
    <div
      ref={ref}
      style={{
        opacity: isVisible ? 1 : 0,
        transform: isVisible ? 'translateY(0)' : 'translateY(50px)',
        transition: 'all 0.6s ease-out',
      }}
    >
      Content fades in when 50% visible
    </div>
  );
}

// Native lazy loading (simpler approach)
<img
  src="image.jpg"
  alt="Description"
  loading="lazy"
  decoding="async"
/>

<iframe
  src="https://example.com"
  loading="lazy"
></iframe>

// Background image lazy loading
function LazyBackground({ imageUrl, children }) {
  const [isLoaded, setIsLoaded] = useState(false);
  const divRef = useRef(null);

  useEffect(() => {
    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) {
        setIsLoaded(true);
        observer.disconnect();
      }
    });

    if (divRef.current) {
      observer.observe(divRef.current);
    }

    return () => observer.disconnect();
  }, []);

  return (
    <div
      ref={divRef}
      style={{
        backgroundImage: isLoaded ? `url(${imageUrl})` : 'none',
        backgroundColor: '#f0f0f0',
        backgroundSize: 'cover',
      }}
    >
      {children}
    </div>
  );
}

5. Mobile-First Breakpoint Strategy

Breakpoint Device Approach Best Practice
Base (mobile) 320px - 639px Default styles, no media query Single column, stack elements
sm (tablet) 640px+ @media (min-width: 640px) 2 columns, larger text
md (laptop) 768px+ @media (min-width: 768px) Sidebar layouts, 3 columns
lg (desktop) 1024px+ @media (min-width: 1024px) Multi-column grids, hover states
xl (wide) 1280px+ @media (min-width: 1280px) Max content width, more spacing
Touch-first All mobile 44px touch targets, no hover Accessibility, usability

Example: Mobile-first responsive design

/* Mobile-first CSS approach */

/* Base styles (mobile, no media query) */
.container {
  width: 100%;
  padding: 1rem;
}

.grid {
  display: grid;
  grid-template-columns: 1fr; /* Single column on mobile */
  gap: 1rem;
}

.nav {
  flex-direction: column;
}

.button {
  min-height: 44px; /* Touch-friendly target */
  width: 100%;
  font-size: 16px; /* Prevents zoom on iOS */
}

/* Tablet (640px+) */
@media (min-width: 640px) {
  .container {
    padding: 2rem;
  }

  .grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .button {
    width: auto;
    min-width: 120px;
  }
}

/* Laptop (768px+) */
@media (min-width: 768px) {
  .container {
    max-width: 768px;
    margin: 0 auto;
  }

  .grid {
    grid-template-columns: repeat(3, 1fr);
    gap: 2rem;
  }

  .nav {
    flex-direction: row;
    justify-content: space-between;
  }

  /* Show hover states only on larger screens */
  .button:hover {
    background-color: #0056b3;
  }
}

/* Desktop (1024px+) */
@media (min-width: 1024px) {
  .container {
    max-width: 1024px;
  }

  .grid {
    grid-template-columns: repeat(4, 1fr);
  }

  .sidebar {
    display: block; /* Show sidebar on desktop */
  }
}

/* Wide screens (1280px+) */
@media (min-width: 1280px) {
  .container {
    max-width: 1280px;
    padding: 3rem;
  }
}

/* React mobile-first component */
function ResponsiveCard() {
  return (
    <div className="
      /* Mobile base */
      flex flex-col
      p-4
      w-full
      
      /* Tablet */
      sm:flex-row
      sm:p-6
      
      /* Laptop */
      md:max-w-2xl
      md:mx-auto
      
      /* Desktop */
      lg:max-w-4xl
      lg:p-8
    ">
      <div className="
        /* Mobile: full width image */
        w-full
        h-48
        
        /* Tablet: side image */
        sm:w-1/3
        sm:h-auto
        
        /* Laptop: larger */
        md:w-1/4
      ">
        <img src="image.jpg" alt="Card" className="w-full h-full object-cover" />
      </div>
      
      <div className="
        /* Mobile: full width content */
        w-full
        mt-4
        
        /* Tablet: beside image */
        sm:w-2/3
        sm:mt-0
        sm:pl-6
        
        /* Laptop: more space */
        md:w-3/4
        md:pl-8
      ">
        <h2 className="text-xl sm:text-2xl md:text-3xl lg:text-4xl">
          Responsive Title
        </h2>
        <p className="mt-2 text-sm sm:text-base md:text-lg">
          Description text
        </p>
      </div>
    </div>
  );
}

/* Mobile-first typography scale */
:root {
  /* Mobile base sizes */
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.25rem;
  --text-2xl: 1.5rem;
}

@media (min-width: 768px) {
  :root {
    /* Larger text on desktop */
    --text-base: 1.125rem;
    --text-lg: 1.25rem;
    --text-xl: 1.5rem;
    --text-2xl: 2rem;
  }
}

/* Touch-first interactions */
.interactive {
  /* Minimum touch target size */
  min-width: 44px;
  min-height: 44px;
  
  /* No hover effects on touch devices */
  -webkit-tap-highlight-color: transparent;
}

@media (hover: hover) {
  /* Only add hover effects on devices that support hover */
  .interactive:hover {
    background-color: #f0f0f0;
  }
}

/* Mobile-first navigation */
.mobile-nav {
  display: flex;
  flex-direction: column;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: white;
  transform: translateX(-100%);
  transition: transform 0.3s;
}

.mobile-nav.open {
  transform: translateX(0);
}

@media (min-width: 768px) {
  .mobile-nav {
    position: static;
    flex-direction: row;
    width: auto;
    height: auto;
    transform: none;
  }
}

6. Adaptive Loading Network Conditions

API Property Description Use Case
Network Information navigator.connection Access network connection info Adapt to connection quality
effectiveType connection.effectiveType '4g', '3g', '2g', 'slow-2g' Load different assets
saveData connection.saveData User enabled data saver mode Reduce data usage
deviceMemory navigator.deviceMemory Device RAM in GB Load lighter alternatives
hardwareConcurrency navigator.hardwareConcurrency Number of CPU cores Adjust processing tasks
Adaptive Loading react-adaptive-hooks React hooks for adaptive loading Component-level adaptation

Example: Adaptive loading based on network and device

// Check network connection
function getNetworkInfo() {
  const connection = navigator.connection 
    || navigator.mozConnection 
    || navigator.webkitConnection;

  if (!connection) {
    return { effectiveType: '4g', saveData: false };
  }

  return {
    effectiveType: connection.effectiveType,
    saveData: connection.saveData,
    downlink: connection.downlink,
    rtt: connection.rtt,
  };
}

// Adaptive image loading
function AdaptiveImage({ src, alt }) {
  const network = getNetworkInfo();
  
  // Load different image quality based on connection
  const imageSrc = network.effectiveType === '4g' && !network.saveData
    ? src.high
    : network.effectiveType === '3g'
    ? src.medium
    : src.low;

  return <img src={imageSrc} alt={alt} loading="lazy" />;
}

// React hook for network status
import { useEffect, useState } from 'react';

function useNetworkStatus() {
  const [status, setStatus] = useState({
    online: navigator.onLine,
    effectiveType: '4g',
    saveData: false,
  });

  useEffect(() => {
    const connection = navigator.connection;

    const updateNetworkStatus = () => {
      setStatus({
        online: navigator.onLine,
        effectiveType: connection?.effectiveType || '4g',
        saveData: connection?.saveData || false,
      });
    };

    updateNetworkStatus();

    window.addEventListener('online', updateNetworkStatus);
    window.addEventListener('offline', updateNetworkStatus);
    connection?.addEventListener('change', updateNetworkStatus);

    return () => {
      window.removeEventListener('online', updateNetworkStatus);
      window.removeEventListener('offline', updateNetworkStatus);
      connection?.removeEventListener('change', updateNetworkStatus);
    };
  }, []);

  return status;
}

// Usage
function VideoPlayer({ videoUrl }) {
  const { effectiveType, saveData, online } = useNetworkStatus();

  if (!online) {
    return <div>You are offline</div>;
  }

  // Adapt video quality
  const quality = saveData || effectiveType === '2g' ? 'low'
    : effectiveType === '3g' ? 'medium'
    : 'high';

  return (
    <video src={videoUrl[quality]} controls autoPlay={effectiveType === '4g'} />
  );
}

// Device capability detection
function useDeviceCapabilities() {
  return {
    memory: navigator.deviceMemory || 4,
    cores: navigator.hardwareConcurrency || 2,
    platform: navigator.platform,
  };
}

// Adaptive component loading
function Dashboard() {
  const { memory, cores } = useDeviceCapabilities();
  const { effectiveType, saveData } = useNetworkStatus();

  // Load heavy components only on capable devices with good connection
  const shouldLoadHeavyFeatures = 
    memory >= 4 && 
    cores >= 4 && 
    effectiveType === '4g' && 
    !saveData;

  return (
    <div>
      <BasicDashboard />
      {shouldLoadHeavyFeatures && (
        <Suspense fallback={<Skeleton />}>
          <HeavyChart />
          <RealTimeData />
        </Suspense>
      )}
    </div>
  );
}

// Adaptive image component with multiple strategies
function SmartImage({ src, alt, sizes }) {
  const { effectiveType, saveData } = useNetworkStatus();
  const { memory } = useDeviceCapabilities();

  // Preload critical images on fast connections
  useEffect(() => {
    if (effectiveType === '4g' && !saveData) {
      const link = document.createElement('link');
      link.rel = 'preload';
      link.as = 'image';
      link.href = src;
      document.head.appendChild(link);
    }
  }, [src, effectiveType, saveData]);

  // Format based on device capability
  const format = memory >= 4 ? 'webp' : 'jpg';

  return (
    <picture>
      {!saveData && effectiveType === '4g' && (
        <source srcSet={`${src}.${format} 2x`} type={`image/${format}`} />
      )}
      <source srcSet={`${src}.${format}`} type={`image/${format}`} />
      <img src={`${src}.jpg`} alt={alt} loading="lazy" />
    </picture>
  );
}

// react-adaptive-hooks library
import {
  useNetworkStatus,
  useSaveData,
  useHardwareConcurrency,
  useMemoryStatus,
} from 'react-adaptive-hooks';

function AdaptiveApp() {
  const { effectiveConnectionType } = useNetworkStatus();
  const { saveData } = useSaveData();
  const { numberOfLogicalProcessors } = useHardwareConcurrency();
  const { deviceMemory } = useMemoryStatus();

  const isLowEndDevice = deviceMemory < 4 || numberOfLogicalProcessors < 4;
  const isSlowNetwork = effectiveConnectionType === '2g' || effectiveConnectionType === '3g';

  return (
    <div>
      {isLowEndDevice || isSlowNetwork || saveData ? (
        <LightweightComponent />
      ) : (
        <FeatureRichComponent />
      )}
    </div>
  );
}

// Adaptive font loading
if (navigator.connection?.effectiveType === '4g' && !navigator.connection?.saveData) {
  // Load custom fonts
  document.fonts.load('16px CustomFont').then(() => {
    document.body.classList.add('fonts-loaded');
  });
} else {
  // Use system fonts
  document.body.style.fontFamily = 'system-ui, sans-serif';
}

Responsive Design Best Practices

  • Mobile-First - Start with mobile styles, enhance for larger screens with min-width media queries
  • CSS Grid + Flexbox - Use Grid for 2D layouts, Flexbox for 1D components, leverage auto-fit/minmax for responsiveness
  • Container Queries - Component-based responsiveness, truly reusable components independent of viewport
  • Tailwind Utilities - Rapid responsive development with sm/md/lg/xl breakpoint prefixes
  • Lazy Loading - Use Intersection Observer for images, components, infinite scroll; native loading="lazy" for simple cases
  • Adaptive Loading - Detect network conditions (4g/3g/2g), save-data mode, device memory to serve appropriate assets
  • Touch-First - Minimum 44px touch targets, avoid hover-only interactions, use pointer events for unified input handling