Files
agents/plugins/ui-design/skills/responsive-design/references/breakpoint-strategies.md
Seth Hobson 1e54d186fe feat(ui-design): add comprehensive UI/UX design plugin v1.0.0
New plugin covering mobile (iOS, Android, React Native) and web
applications with modern design patterns, accessibility, and design systems.

Components:
- 9 skills: design-system-patterns, accessibility-compliance, responsive-design,
  mobile-ios-design, mobile-android-design, react-native-design,
  web-component-design, interaction-design, visual-design-foundations
- 4 commands: design-review, create-component, accessibility-audit, design-system-setup
- 3 agents: ui-designer, accessibility-expert, design-system-architect

Marketplace updated:
- Version bumped to 1.3.4
- 102 agents (+3), 116 skills (+9)
2026-01-19 16:22:13 -05:00

10 KiB

Breakpoint Strategies

Overview

Effective breakpoint strategies focus on content needs rather than device sizes. Modern responsive design uses fewer, content-driven breakpoints combined with fluid techniques.

Mobile-First Approach

Core Philosophy

Start with the smallest screen, then progressively enhance for larger screens.

/* Base styles (mobile first) */
.component {
  display: flex;
  flex-direction: column;
  padding: 1rem;
}

/* Enhance for larger screens */
@media (min-width: 640px) {
  .component {
    flex-direction: row;
    padding: 1.5rem;
  }
}

@media (min-width: 1024px) {
  .component {
    padding: 2rem;
  }
}

Benefits

  1. Performance: Mobile devices load only necessary CSS
  2. Progressive Enhancement: Features add rather than subtract
  3. Content Priority: Forces focus on essential content first
  4. Simplicity: Easier to reason about cascading styles

Common Breakpoint Scales

Tailwind CSS Default

/* Tailwind breakpoints */
/* sm: 640px  - Landscape phones */
/* md: 768px  - Tablets */
/* lg: 1024px - Laptops */
/* xl: 1280px - Desktops */
/* 2xl: 1536px - Large desktops */

@media (min-width: 640px) { /* sm */ }
@media (min-width: 768px) { /* md */ }
@media (min-width: 1024px) { /* lg */ }
@media (min-width: 1280px) { /* xl */ }
@media (min-width: 1536px) { /* 2xl */ }

Bootstrap 5

/* Bootstrap breakpoints */
/* sm: 576px */
/* md: 768px */
/* lg: 992px */
/* xl: 1200px */
/* xxl: 1400px */

@media (min-width: 576px) { /* sm */ }
@media (min-width: 768px) { /* md */ }
@media (min-width: 992px) { /* lg */ }
@media (min-width: 1200px) { /* xl */ }
@media (min-width: 1400px) { /* xxl */ }

Minimalist Scale

/* Simplified 3-breakpoint system */
/* Base: Mobile (< 600px) */
/* Medium: Tablets and small laptops (600px - 1024px) */
/* Large: Desktops (> 1024px) */

:root {
  --bp-md: 600px;
  --bp-lg: 1024px;
}

@media (min-width: 600px) { /* Medium */ }
@media (min-width: 1024px) { /* Large */ }

Content-Based Breakpoints

Finding Natural Breakpoints

Instead of using device-based breakpoints, identify where your content naturally needs to change.

/* Bad: Device-based thinking */
@media (min-width: 768px) { /* iPad breakpoint */ }

/* Good: Content-based thinking */
/* Breakpoint where sidebar fits comfortably next to content */
@media (min-width: 50rem) {
  .layout {
    display: grid;
    grid-template-columns: 1fr 300px;
  }
}

/* Breakpoint where cards can show 3 across without crowding */
@media (min-width: 65rem) {
  .card-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

Testing Content Breakpoints

// Find where content breaks
function findBreakpoints(selector) {
  const element = document.querySelector(selector);
  const breakpoints = [];

  for (let width = 320; width <= 1920; width += 10) {
    element.style.width = `${width}px`;

    // Check for overflow, wrapping, or layout issues
    if (element.scrollWidth > element.clientWidth) {
      breakpoints.push({ width, issue: 'overflow' });
    }
  }

  return breakpoints;
}

Design Token Integration

Breakpoint Tokens

:root {
  /* Breakpoint values */
  --breakpoint-sm: 640px;
  --breakpoint-md: 768px;
  --breakpoint-lg: 1024px;
  --breakpoint-xl: 1280px;
  --breakpoint-2xl: 1536px;

  /* Container widths for each breakpoint */
  --container-sm: 640px;
  --container-md: 768px;
  --container-lg: 1024px;
  --container-xl: 1280px;
  --container-2xl: 1536px;
}

.container {
  width: 100%;
  max-width: var(--container-lg);
  margin-inline: auto;
  padding-inline: var(--space-4);
}

JavaScript Integration

// Breakpoint constants
export const breakpoints = {
  sm: 640,
  md: 768,
  lg: 1024,
  xl: 1280,
  '2xl': 1536,
} as const;

// Media query hook
function useMediaQuery(query: string): boolean {
  const [matches, setMatches] = useState(false);

  useEffect(() => {
    const media = window.matchMedia(query);
    setMatches(media.matches);

    const listener = () => setMatches(media.matches);
    media.addEventListener('change', listener);
    return () => media.removeEventListener('change', listener);
  }, [query]);

  return matches;
}

// Breakpoint hook
function useBreakpoint() {
  const isSmall = useMediaQuery(`(min-width: ${breakpoints.sm}px)`);
  const isMedium = useMediaQuery(`(min-width: ${breakpoints.md}px)`);
  const isLarge = useMediaQuery(`(min-width: ${breakpoints.lg}px)`);
  const isXLarge = useMediaQuery(`(min-width: ${breakpoints.xl}px)`);

  return {
    isMobile: !isSmall,
    isTablet: isSmall && !isLarge,
    isDesktop: isLarge,
    current: isXLarge ? 'xl' : isLarge ? 'lg' : isMedium ? 'md' : isSmall ? 'sm' : 'base',
  };
}

Feature Queries

@supports for Progressive Enhancement

/* Feature detection instead of browser detection */
@supports (display: grid) {
  .layout {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  }
}

@supports (container-type: inline-size) {
  .card-container {
    container-type: inline-size;
  }

  @container (min-width: 400px) {
    .card {
      flex-direction: row;
    }
  }
}

@supports (aspect-ratio: 16/9) {
  .video-container {
    aspect-ratio: 16/9;
  }
}

/* Fallback for older browsers */
@supports not (gap: 1rem) {
  .flex-container > * + * {
    margin-left: 1rem;
  }
}

Combining Feature and Size Queries

/* Only apply grid layout if supported and screen is large enough */
@supports (display: grid) {
  @media (min-width: 768px) {
    .layout {
      display: grid;
      grid-template-columns: 250px 1fr;
    }
  }
}

Responsive Patterns by Component

Navigation

.nav {
  /* Mobile: vertical stack */
  display: flex;
  flex-direction: column;
}

@media (min-width: 768px) {
  .nav {
    /* Tablet+: horizontal */
    flex-direction: row;
    align-items: center;
  }
}

/* Or with container queries */
.nav-container {
  container-type: inline-size;
}

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

Cards Grid

.cards {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: 1fr;
}

@media (min-width: 640px) {
  .cards {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .cards {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 1280px) {
  .cards {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* Better: auto-fit with minimum size */
.cards-auto {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
}

Hero Section

.hero {
  min-height: 50vh;
  padding: var(--space-lg) var(--space-md);
  text-align: center;
}

.hero-title {
  font-size: clamp(2rem, 5vw + 1rem, 4rem);
}

.hero-subtitle {
  font-size: clamp(1rem, 2vw + 0.5rem, 1.5rem);
}

@media (min-width: 768px) {
  .hero {
    min-height: 70vh;
    display: flex;
    align-items: center;
    text-align: left;
  }

  .hero-content {
    max-width: 60%;
  }
}

@media (min-width: 1024px) {
  .hero {
    min-height: 80vh;
  }

  .hero-content {
    max-width: 50%;
  }
}

Tables

/* Mobile: cards or horizontal scroll */
.table-container {
  overflow-x: auto;
}

.responsive-table {
  min-width: 600px;
}

/* Alternative: transform to cards on mobile */
@media (max-width: 639px) {
  .responsive-table {
    min-width: 0;
  }

  .responsive-table thead {
    display: none;
  }

  .responsive-table tr {
    display: block;
    margin-bottom: 1rem;
    border: 1px solid var(--border);
    border-radius: 0.5rem;
    padding: 1rem;
  }

  .responsive-table td {
    display: flex;
    justify-content: space-between;
    padding: 0.5rem 0;
    border: none;
  }

  .responsive-table td::before {
    content: attr(data-label);
    font-weight: 600;
  }
}

Print Styles

@media print {
  /* Remove non-essential elements */
  .nav,
  .sidebar,
  .footer,
  .ads {
    display: none;
  }

  /* Reset colors and backgrounds */
  * {
    background: white !important;
    color: black !important;
    box-shadow: none !important;
  }

  /* Ensure content fits on page */
  .container {
    max-width: 100%;
    padding: 0;
  }

  /* Handle page breaks */
  h1, h2, h3 {
    page-break-after: avoid;
  }

  img, table {
    page-break-inside: avoid;
  }

  /* Show URLs for links */
  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 0.8em;
  }
}

Preference Queries

/* Dark mode preference */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1a1a1a;
    --text: #f0f0f0;
  }
}

/* Reduced motion preference */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* High contrast preference */
@media (prefers-contrast: high) {
  :root {
    --text: #000;
    --bg: #fff;
    --border: #000;
  }

  .button {
    border: 2px solid currentColor;
  }
}

/* Reduced data preference */
@media (prefers-reduced-data: reduce) {
  .hero-video {
    display: none;
  }

  .hero-image {
    display: block;
  }
}

Testing Breakpoints

// Automated breakpoint testing
async function testBreakpoints(page, breakpoints) {
  const results = [];

  for (const [name, width] of Object.entries(breakpoints)) {
    await page.setViewportSize({ width, height: 800 });

    // Check for horizontal overflow
    const hasOverflow = await page.evaluate(() => {
      return document.documentElement.scrollWidth > document.documentElement.clientWidth;
    });

    // Check for elements going off-screen
    const offscreenElements = await page.evaluate(() => {
      const elements = document.querySelectorAll('*');
      return Array.from(elements).filter(el => {
        const rect = el.getBoundingClientRect();
        return rect.right > window.innerWidth || rect.left < 0;
      }).length;
    });

    results.push({
      breakpoint: name,
      width,
      hasOverflow,
      offscreenElements,
    });
  }

  return results;
}

Resources