Responsive Design and Media Query Management

1. Breakpoint Maps and Responsive Mixins

Component Pattern Description Example
Breakpoint map $breakpoints: (sm: 576px...) Named breakpoint values Centralized configuration
above() mixin @include above(md) Min-width media query Mobile-first
below() mixin @include below(lg) Max-width media query Desktop-first
between() mixin @include between(sm, lg) Range media query Specific ranges
only() mixin @include only(md) Exact breakpoint only Specific size
Custom queries Orientation, hover, etc. Feature detection Enhanced UX

Example: Comprehensive breakpoint system

@use 'sass:map';

// Breakpoint configuration
$breakpoints: (
  xs: 0,
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px,
  xxl: 1400px
) !default;

// Mobile-first: min-width
@mixin above($breakpoint) {
  $value: map.get($breakpoints, $breakpoint);
  
  @if $value {
    @if $value == 0 {
      @content;
    } @else {
      @media (min-width: $value) {
        @content;
      }
    }
  } @else {
    @error "Breakpoint '#{$breakpoint}' not found in $breakpoints map";
  }
}

// Desktop-first: max-width
@mixin below($breakpoint) {
  $value: map.get($breakpoints, $breakpoint);
  
  @if $value {
    @media (max-width: $value - 1px) {
      @content;
    }
  } @else {
    @error "Breakpoint '#{$breakpoint}' not found";
  }
}

// Between two breakpoints
@mixin between($min, $max) {
  $min-val: map.get($breakpoints, $min);
  $max-val: map.get($breakpoints, $max);
  
  @media (min-width: $min-val) and (max-width: $max-val - 1px) {
    @content;
  }
}

// Only at specific breakpoint
@mixin only($breakpoint) {
  $index: list.index(map.keys($breakpoints), $breakpoint);
  
  @if $index {
    $next-bp: list.nth(map.keys($breakpoints), $index + 1);
    @include between($breakpoint, $next-bp) {
      @content;
    }
  }
}

// Usage examples
.container {
  width: 100%;
  padding: 1rem;
  
  // Mobile-first progression
  @include above(sm) {
    max-width: 540px;
    margin: 0 auto;
  }
  
  @include above(md) {
    max-width: 720px;
    padding: 1.5rem;
  }
  
  @include above(lg) {
    max-width: 960px;
    padding: 2rem;
  }
  
  @include above(xl) {
    max-width: 1140px;
  }
  
  @include above(xxl) {
    max-width: 1320px;
  }
}

// Desktop-first approach
.sidebar {
  width: 100%;
  
  @include below(lg) {
    display: none;
  }
  
  @include above(lg) {
    width: 250px;
    position: fixed;
  }
}

// Between breakpoints
.promo-banner {
  display: none;
  
  // Only show between md and lg
  @include between(md, lg) {
    display: block;
    padding: 2rem;
  }
}

// Only at specific size
.tablet-specific {
  @include only(md) {
    // Only applies at md breakpoint
    columns: 2;
  }
}

// Advanced: Breakpoint helpers
@function breakpoint-min($name) {
  @return map.get($breakpoints, $name);
}

@function breakpoint-max($name) {
  $max: map.get($breakpoints, $name);
  @return if($max and $max > 0, $max - 1px, null);
}

@function breakpoint-infix($name) {
  @return if($name == xs, '', '-#{$name}');
}

// Generate responsive utilities
$utilities: (
  display: (none, block, flex, grid),
  text-align: (left, center, right)
);

@each $property, $values in $utilities {
  @each $value in $values {
    @each $bp-name, $bp-value in $breakpoints {
      $infix: breakpoint-infix($bp-name);
      
      .#{$property}#{$infix}-#{$value} {
        @include above($bp-name) {
          #{$property}: $value;
        }
      }
    }
  }
}
// Generates: .display-sm-block, .text-align-md-center, etc.

// Custom media query mixins
@mixin landscape {
  @media (orientation: landscape) {
    @content;
  }
}

@mixin portrait {
  @media (orientation: portrait) {
    @content;
  }
}

@mixin retina {
  @media (-webkit-min-device-pixel-ratio: 2),
         (min-resolution: 192dpi) {
    @content;
  }
}

@mixin hover-supported {
  @media (hover: hover) and (pointer: fine) {
    &:hover {
      @content;
    }
  }
}

@mixin touch-device {
  @media (hover: none) and (pointer: coarse) {
    @content;
  }
}

@mixin prefers-dark {
  @media (prefers-color-scheme: dark) {
    @content;
  }
}

@mixin prefers-light {
  @media (prefers-color-scheme: light) {
    @content;
  }
}

@mixin reduced-motion {
  @media (prefers-reduced-motion: reduce) {
    @content;
  }
}

// Usage
.image {
  width: 100%;
  
  @include retina {
    content: url('image@2x.png');
  }
}

.button {
  background: blue;
  
  @include hover-supported {
    background: darkblue;
  }
  
  @include touch-device {
    padding: 12px 24px; // Larger touch targets
  }
}

.theme {
  background: white;
  
  @include prefers-dark {
    background: #1a1a1a;
  }
}

.animated {
  transition: all 0.3s;
  
  @include reduced-motion {
    transition: none;
  }
}

2. Mobile-first vs Desktop-first Patterns

Approach Query Type Base Styles Best For
Mobile-first min-width Mobile base, enhance up Modern apps, performance
Desktop-first max-width Desktop base, reduce down Legacy sites, admin panels
Hybrid Both min/max Tablet base, both directions Complex layouts
Content-first As needed Break where content dictates Editorial sites

Example: Mobile-first vs Desktop-first comparison

// MOBILE-FIRST (Recommended)
// Start with mobile, enhance for larger screens
.card {
  // Base styles (mobile)
  width: 100%;
  padding: 1rem;
  margin-bottom: 1rem;
  
  // Enhance for tablet
  @include above(md) {
    width: 48%;
    float: left;
    margin-right: 2%;
  }
  
  // Enhance for desktop
  @include above(lg) {
    width: 31.333%;
    margin-right: 2%;
  }
  
  // Enhance for large desktop
  @include above(xl) {
    width: 23%;
    margin-right: 1.5%;
  }
}

// DESKTOP-FIRST
// Start with desktop, reduce for smaller screens
.sidebar {
  // Base styles (desktop)
  width: 300px;
  float: left;
  padding: 2rem;
  
  // Reduce for laptop
  @include below(xl) {
    width: 250px;
    padding: 1.5rem;
  }
  
  // Reduce for tablet
  @include below(lg) {
    width: 200px;
    padding: 1rem;
  }
  
  // Stack on mobile
  @include below(md) {
    width: 100%;
    float: none;
  }
}

// MOBILE-FIRST: Typography
.heading {
  // Mobile base
  font-size: 1.5rem;
  line-height: 1.3;
  margin-bottom: 1rem;
  
  @include above(md) {
    font-size: 2rem;
    line-height: 1.2;
  }
  
  @include above(lg) {
    font-size: 2.5rem;
  }
  
  @include above(xl) {
    font-size: 3rem;
    line-height: 1.1;
  }
}

// DESKTOP-FIRST: Navigation
.nav {
  // Desktop base
  display: flex;
  gap: 2rem;
  
  @include below(md) {
    flex-direction: column;
    gap: 0;
  }
  
  &__item {
    // Desktop
    padding: 0.5rem 1rem;
    
    @include below(md) {
      padding: 1rem;
      border-bottom: 1px solid #ddd;
    }
  }
}

// HYBRID: Best of both
.product-grid {
  display: grid;
  gap: 1rem;
  
  // Mobile base (1 column)
  grid-template-columns: 1fr;
  
  // Tablet (2 columns) - mobile-first
  @include above(sm) {
    grid-template-columns: repeat(2, 1fr);
  }
  
  // Small desktop (3 columns) - mobile-first
  @include above(md) {
    grid-template-columns: repeat(3, 1fr);
    gap: 1.5rem;
  }
  
  // Large desktop (4 columns) - mobile-first
  @include above(lg) {
    grid-template-columns: repeat(4, 1fr);
    gap: 2rem;
  }
  
  // But hide on very small screens - desktop-first concept
  @include below(xs) {
    display: none; // Too small to be useful
  }
}

// CONTENT-FIRST: Break where content needs it
.article {
  font-size: 16px;
  line-height: 1.6;
  max-width: 100%;
  
  // When line length gets too long
  @media (min-width: 600px) {
    max-width: 600px;
    margin: 0 auto;
  }
  
  // Add columns when there's room
  @media (min-width: 900px) {
    columns: 2;
    column-gap: 3rem;
  }
}

// Mobile-first: Progressive enhancement
.feature {
  // Simple mobile version
  background: white;
  padding: 1rem;
  
  @include above(md) {
    // Add complexity on larger screens
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: 2rem;
  }
  
  @include above(lg) {
    // Add more features
    box-shadow: 0 4px 8px rgba(0,0,0,0.1);
    border-radius: 8px;
  }
  
  @supports (backdrop-filter: blur(10px)) {
    @include above(lg) {
      // Modern feature for capable browsers
      backdrop-filter: blur(10px);
      background: rgba(255,255,255,0.9);
    }
  }
}

// Desktop-first: Graceful degradation
.dashboard {
  // Complex desktop layout
  display: grid;
  grid-template-columns: 250px 1fr 300px;
  grid-template-areas: "sidebar main widgets";
  gap: 2rem;
  
  @include below(lg) {
    // Simplify for tablet
    grid-template-columns: 200px 1fr;
    grid-template-areas: "sidebar main";
    
    .widgets {
      display: none;
    }
  }
  
  @include below(md) {
    // Stack for mobile
    grid-template-columns: 1fr;
    grid-template-areas: "main";
    
    .sidebar {
      display: none;
    }
  }
}

// Performance consideration (mobile-first wins)
.heavy-feature {
  // Simple mobile version (fast)
  display: block;
  
  @include above(lg) {
    // Complex desktop version (more resources available)
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 2rem;
    
    &::before,
    &::after {
      // Decorative elements only on desktop
      content: '';
      // ... complex styles
    }
  }
}

3. Container Query Integration

Property Syntax Description Use Case
container-type inline-size | size Define container Enable queries
container-name container-name: sidebar Named containers Target specific
@container @container (min-width) Container query Component responsive
Container units cqw, cqh, cqi, cqb Container-relative units Fluid sizing

Example: Modern container queries

// Container query mixin
@mixin container($min-width) {
  @container (min-width: $min-width) {
    @content;
  }
}

@mixin container-named($name, $min-width) {
  @container #{$name} (min-width: $min-width) {
    @content;
  }
}

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

// Child responds to container size, not viewport
.card {
  padding: 1rem;
  
  // When container is 400px+
  @container (min-width: 400px) {
    display: grid;
    grid-template-columns: 150px 1fr;
    gap: 1rem;
  }
  
  // When container is 600px+
  @container (min-width: 600px) {
    grid-template-columns: 200px 1fr 150px;
    padding: 2rem;
  }
  
  &__title {
    font-size: 1rem;
    
    @container (min-width: 400px) {
      font-size: 1.25rem;
    }
    
    @container (min-width: 600px) {
      font-size: 1.5rem;
    }
  }
}

// Named container queries
.sidebar {
  container-type: inline-size;
  container-name: sidebar;
  
  .widget {
    // Responds to sidebar size
    @container sidebar (min-width: 300px) {
      display: grid;
      grid-template-columns: 1fr 1fr;
    }
  }
}

// Container query with mixin
.component-wrapper {
  container-type: inline-size;
  
  .component {
    display: block;
    
    @include container(500px) {
      display: flex;
      gap: 1rem;
    }
    
    @include container(700px) {
      gap: 2rem;
      padding: 2rem;
    }
  }
}

// Responsive component that works anywhere
.product-card {
  // No media queries needed!
  // Responds to its container
  
  &-container {
    container-type: inline-size;
  }
  
  display: block;
  
  // Small container
  @container (min-width: 250px) {
    &__image {
      aspect-ratio: 16/9;
    }
  }
  
  // Medium container
  @container (min-width: 400px) {
    display: grid;
    grid-template-columns: 40% 1fr;
    
    &__image {
      aspect-ratio: 1;
    }
  }
  
  // Large container
  @container (min-width: 600px) {
    grid-template-columns: 200px 1fr;
    gap: 2rem;
    
    &__title {
      font-size: 1.5rem;
    }
  }
}

// Container query units
.fluid-component {
  container-type: inline-size;
  
  &__heading {
    // Font size relative to container width
    font-size: calc(1rem + 2cqw);
    
    // Padding relative to container
    padding: 1cqi; // inline
  }
  
  &__content {
    // Gap relative to container
    gap: 2cqw;
  }
}

// Fallback for no container query support
.card {
  padding: 1rem;
  
  // Traditional media query fallback
  @media (min-width: 768px) {
    @supports not (container-type: inline-size) {
      display: grid;
      grid-template-columns: 1fr 2fr;
    }
  }
  
  // Modern container query
  @supports (container-type: inline-size) {
    @container (min-width: 400px) {
      display: grid;
      grid-template-columns: 1fr 2fr;
    }
  }
}

// Practical: Responsive card system
.card-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  
  .card {
    // Each card is a container
    container-type: inline-size;
    
    &__layout {
      // Adapts to card size, not viewport
      @container (max-width: 350px) {
        // Narrow card: stack
        display: flex;
        flex-direction: column;
      }
      
      @container (min-width: 351px) and (max-width: 500px) {
        // Medium card: side-by-side
        display: grid;
        grid-template-columns: 100px 1fr;
      }
      
      @container (min-width: 501px) {
        // Wide card: complex layout
        display: grid;
        grid-template-columns: 150px 1fr 100px;
      }
    }
  }
}

// Container queries with style queries (future)
.theme-container {
  container-type: inline-size;
  
  // Style query (experimental)
  // @container style(--theme: dark) {
  //   background: #1a1a1a;
  // }
}

4. Responsive Typography with Fluid Scaling

Technique Formula Description Browser Support
clamp() clamp(min, preferred, max) CSS clamp function Modern browsers
Fluid calc() calc(min + slope * vw) Linear interpolation All browsers
vw units font-size: 2.5vw Viewport width Simple but no limits
Modular scale base * ratio^n Proportional sizing Mathematical harmony

Example: Fluid responsive typography

@use 'sass:math';

// Modern approach: clamp()
.heading {
  // min: 1.5rem, preferred: 5vw, max: 3rem
  font-size: clamp(1.5rem, 5vw, 3rem);
  
  // Line height also fluid
  line-height: clamp(1.2, 1.5vw, 1.5);
}

// Fluid typography function
@function fluid-size($min, $max, $min-vw: 320px, $max-vw: 1200px) {
  $min-val: math.div($min, 1px);
  $max-val: math.div($max, 1px);
  $min-vw-val: math.div($min-vw, 1px);
  $max-vw-val: math.div($max-vw, 1px);
  
  $slope: math.div($max-val - $min-val, $max-vw-val - $min-vw-val);
  $intercept: $min-val - $slope * $min-vw-val;
  
  @return clamp(
    #{$min},
    #{$intercept}px + #{$slope * 100}vw,
    #{$max}
  );
}

// Usage
h1 {
  font-size: fluid-size(24px, 48px);  // 24px to 48px
}

h2 {
  font-size: fluid-size(20px, 36px);
}

p {
  font-size: fluid-size(16px, 18px);
}

// Fluid spacing
@function fluid-space($min, $max) {
  @return fluid-size($min, $max, 320px, 1200px);
}

.container {
  padding: fluid-space(16px, 48px);
  gap: fluid-space(1rem, 3rem);
}

// Modular scale with fluid base
@function modular-scale($level, $base: 16px, $ratio: 1.25) {
  @return $base * math.pow($ratio, $level);
}

// Fluid modular scale
$base-font-size: fluid-size(16px, 20px);

h1 { font-size: modular-scale(4, $base-font-size); }
h2 { font-size: modular-scale(3, $base-font-size); }
h3 { font-size: modular-scale(2, $base-font-size); }
h4 { font-size: modular-scale(1, $base-font-size); }
p  { font-size: $base-font-size; }

// Responsive type scale map
$type-scale: (
  xs: (
    h1: 1.75rem,
    h2: 1.5rem,
    h3: 1.25rem,
    p: 1rem
  ),
  md: (
    h1: 2.5rem,
    h2: 2rem,
    h3: 1.5rem,
    p: 1.125rem
  ),
  xl: (
    h1: 3.5rem,
    h2: 2.75rem,
    h3: 2rem,
    p: 1.25rem
  )
);

@mixin responsive-typography {
  @each $element, $size in map.get($type-scale, xs) {
    #{$element} {
      font-size: $size;
    }
  }
  
  @include above(md) {
    @each $element, $size in map.get($type-scale, md) {
      #{$element} {
        font-size: $size;
      }
    }
  }
  
  @include above(xl) {
    @each $element, $size in map.get($type-scale, xl) {
      #{$element} {
        font-size: $size;
      }
    }
  }
}

// Apply to scope
.article {
  @include responsive-typography;
}

// Viewport-based with constraints
.hero-title {
  font-size: calc(1.5rem + 2vw);
  
  // But add safety constraints
  @media (max-width: 320px) {
    font-size: 1.5rem; // Minimum
  }
  
  @media (min-width: 1920px) {
    font-size: 4rem; // Maximum
  }
}

// Fluid line height
@function fluid-line-height($min, $max) {
  @return clamp($min, calc(#{$min} + (#{$max} - #{$min}) * 0.5vw), $max);
}

.text {
  line-height: fluid-line-height(1.4, 1.8);
}

// Container query typography
.card {
  container-type: inline-size;
  
  &__title {
    // Scales with container, not viewport
    font-size: clamp(1rem, 4cqi, 2rem);
  }
}

// Accessible fluid typography
@function accessible-fluid($min, $max) {
  // Ensure minimum readable size
  $safe-min: math.max($min, 16px);
  @return fluid-size($safe-min, $max);
}

// Practical: Complete typography system
$fluid-typography: (
  display: fluid-size(48px, 96px),
  h1: fluid-size(32px, 48px),
  h2: fluid-size(24px, 36px),
  h3: fluid-size(20px, 28px),
  h4: fluid-size(18px, 24px),
  h5: fluid-size(16px, 20px),
  h6: fluid-size(14px, 18px),
  body: fluid-size(16px, 18px),
  small: fluid-size(14px, 16px)
);

@each $element, $size in $fluid-typography {
  .#{$element} {
    font-size: $size;
  }
}

// Optical sizing (variable fonts)
.variable-font {
  font-size: clamp(1rem, 2vw, 2rem);
  font-variation-settings: 
    'opsz' calc(16 + (32 - 16) * ((100vw - 320px) / (1920 - 320)));

5. Responsive Grid Systems and Layout Mixins

System Approach Example Best For
Fixed columns 12-column grid Bootstrap-style Traditional layouts
Fluid grid Percentage-based Flexible columns Responsive layouts
CSS Grid Native grid grid-template-columns Modern layouts
Flexbox Flexible box flex-basis, flex-grow 1D layouts
Auto-fit Responsive grid repeat(auto-fit, minmax()) Card grids

Example: Responsive grid systems

// 12-column responsive grid system
$grid-columns: 12;
$grid-gutter: 30px;

@mixin make-container {
  width: 100%;
  padding: 0 math.div($grid-gutter, 2);
  margin: 0 auto;
}

@mixin make-row {
  display: flex;
  flex-wrap: wrap;
  margin: 0 math.div($grid-gutter, -2);
}

@mixin make-col($size, $columns: $grid-columns) {
  flex: 0 0 auto;
  width: math.percentage(math.div($size, $columns));
  padding: 0 math.div($grid-gutter, 2);
}

// Usage
.container {
  @include make-container;
}

.row {
  @include make-row;
}

.col-6 {
  @include make-col(6);  // 50%
}

.col-4 {
  @include make-col(4);  // 33.333%
}

// Responsive columns
@mixin make-col-responsive($sizes) {
  @each $bp, $size in $sizes {
    @include above($bp) {
      @include make-col($size);
    }
  }
}

.col-responsive {
  @include make-col-responsive((
    xs: 12,  // Full width mobile
    md: 6,   // Half width tablet
    lg: 4,   // Third width desktop
    xl: 3    // Quarter width large
  ));
}

// Modern CSS Grid system
@mixin grid-columns($mobile: 1, $tablet: 2, $desktop: 3, $wide: 4) {
  display: grid;
  gap: $grid-gutter;
  grid-template-columns: repeat($mobile, 1fr);
  
  @include above(md) {
    grid-template-columns: repeat($tablet, 1fr);
  }
  
  @include above(lg) {
    grid-template-columns: repeat($desktop, 1fr);
  }
  
  @include above(xl) {
    grid-template-columns: repeat($wide, 1fr);
  }
}

.product-grid {
  @include grid-columns(1, 2, 3, 4);
}

// Auto-responsive grid (no media queries!)
.auto-grid {
  display: grid;
  gap: 1rem;
  
  // Automatically responsive
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(300px, 100%), 1fr)
  );
}

// Responsive grid areas
.layout {
  display: grid;
  gap: 1rem;
  
  // Mobile: stacked
  grid-template-areas:
    "header"
    "main"
    "sidebar"
    "footer";
  
  @include above(md) {
    // Tablet: sidebar alongside
    grid-template-columns: 200px 1fr;
    grid-template-areas:
      "header header"
      "sidebar main"
      "footer footer";
  }
  
  @include above(lg) {
    // Desktop: 3-column
    grid-template-columns: 200px 1fr 250px;
    grid-template-areas:
      "header header header"
      "sidebar main widgets"
      "footer footer footer";
  }
}

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

// Flexbox responsive layout
@mixin flex-layout($gap: 1rem) {
  display: flex;
  flex-wrap: wrap;
  gap: $gap;
  
  & > * {
    // Mobile: full width
    flex: 1 1 100%;
    
    @include above(md) {
      // Tablet: half width
      flex: 1 1 calc(50% - #{$gap});
    }
    
    @include above(lg) {
      // Desktop: third width
      flex: 1 1 calc(33.333% - #{$gap});
    }
  }
}

.flex-container {
  @include flex-layout(2rem);
}

// Utility: Responsive columns
@for $i from 1 through 12 {
  @each $bp-name, $bp-value in $breakpoints {
    $infix: if($bp-name == xs, '', '-#{$bp-name}');
    
    .col#{$infix}-#{$i} {
      @include above($bp-name) {
        @include make-col($i);
      }
    }
  }
}
// Generates: .col-1, .col-md-6, .col-lg-4, etc.

// Responsive gap
@mixin responsive-gap($mobile, $tablet, $desktop) {
  gap: $mobile;
  
  @include above(md) {
    gap: $tablet;
  }
  
  @include above(lg) {
    gap: $desktop;
  }
}

.grid {
  @include responsive-gap(1rem, 1.5rem, 2rem);
}

// Holy Grail Layout (responsive)
.holy-grail {
  display: grid;
  min-height: 100vh;
  
  // Mobile: stacked
  grid-template:
    "header" auto
    "main" 1fr
    "left" auto
    "right" auto
    "footer" auto / 1fr;
  
  @include above(lg) {
    // Desktop: classic 3-column
    grid-template:
      "header header header" auto
      "left main right" 1fr
      "footer footer footer" auto
      / 200px 1fr 200px;
  }
}

6. Print Media and Alternative Media Types

Media Type Query Purpose Common Adjustments
print @media print Printing Hide nav, show URLs
screen @media screen Digital displays Default styles
speech @media speech Screen readers Accessibility
all @media all All devices Universal styles

Example: Print styles and alternative media

// Print styles mixin
@mixin print-styles {
  @media print {
    @content;
  }
}

// Global print optimizations
@media print {
  * {
    background: transparent !important;
    color: black !important;
    box-shadow: none !important;
    text-shadow: none !important;
  }
  
  // Page setup
  @page {
    margin: 2cm;
    size: A4 portrait;
  }
  
  // Typography
  body {
    font-size: 12pt;
    line-height: 1.5;
  }
  
  h1 { font-size: 24pt; }
  h2 { font-size: 18pt; }
  h3 { font-size: 14pt; }
  
  // Links
  a {
    text-decoration: underline;
    color: black;
    
    // Show URL after link
    &[href]::after {
      content: " (" attr(href) ")";
      font-size: 10pt;
    }
    
    // Don't show for anchors
    &[href^="#"]::after,
    &[href^="javascript:"]::after {
      content: "";
    }
  }
  
  // Images
  img {
    max-width: 100%;
    page-break-inside: avoid;
  }
  
  // Tables
  table {
    border-collapse: collapse;
    
    th, td {
      border: 1px solid #ddd;
      padding: 8pt;
    }
  }
  
  // Page breaks
  h1, h2, h3, h4, h5, h6 {
    page-break-after: avoid;
    page-break-inside: avoid;
  }
  
  p, blockquote {
    page-break-inside: avoid;
  }
  
  thead {
    display: table-header-group;
  }
  
  tr, img {
    page-break-inside: avoid;
  }
  
  // Hide non-printable elements
  nav,
  .no-print,
  .sidebar,
  .advertisement,
  button,
  video,
  audio {
    display: none !important;
  }
  
  // Show hidden content
  .print-only {
    display: block !important;
  }
}

// Component-specific print styles
.article {
  // Screen styles
  max-width: 800px;
  margin: 0 auto;
  
  @include print-styles {
    // Print styles
    max-width: 100%;
    margin: 0;
    
    &__header {
      border-bottom: 2pt solid black;
      padding-bottom: 1rem;
    }
    
    &__footer {
      border-top: 1pt solid #ccc;
      margin-top: 2rem;
      padding-top: 1rem;
    }
  }
}

// QR code for print
.share-link {
  display: inline-block;
  
  @media print {
    &::after {
      content: "";
      display: block;
      width: 100px;
      height: 100px;
      background: url('/qr-code.png');
      background-size: contain;
    }
  }
}

// Print-specific utilities
.page-break-before {
  @media print {
    page-break-before: always;
  }
}

.page-break-after {
  @media print {
    page-break-after: always;
  }
}

.avoid-break {
  @media print {
    page-break-inside: avoid;
  }
}

// @page rules for different sections
@media print {
  @page :first {
    margin-top: 5cm;
  }
  
  @page :left {
    margin-left: 3cm;
    margin-right: 2cm;
  }
  
  @page :right {
    margin-left: 2cm;
    margin-right: 3cm;
  }
  
  // Named pages
  @page chapter {
    margin: 3cm;
    
    @top-center {
      content: "Chapter " counter(chapter);
    }
  }
}

.chapter {
  @media print {
    page: chapter;
  }
}

// Screen reader / speech styles
@media speech {
  // Control speech rate
  .fast-read {
    voice-rate: fast;
  }
  
  .slow-read {
    voice-rate: slow;
  }
  
  // Pause before headings
  h1, h2, h3 {
    pause-before: 300ms;
    pause-after: 200ms;
  }
  
  // Spell out abbreviations
  abbr {
    speak: spell-out;
  }
}

// Projection media (presentations)
@media projection {
  body {
    font-size: 24pt;
  }
  
  .slide {
    page-break-after: always;
    min-height: 100vh;
  }
}

// High contrast mode
@media (prefers-contrast: high) {
  .card {
    border: 2px solid currentColor;
    background: white;
    color: black;
  }
}

// Inverted colors
@media (inverted-colors: inverted) {
  img, video {
    filter: invert(1);
  }
}

Responsive Design Summary

  • Breakpoints: Use map-based system with above(), below(), between() mixins
  • Mobile-first: Preferred approach using min-width queries (progressive enhancement)
  • Container queries: Component-level responsive design with @container
  • Fluid typography: Use clamp() or fluid-size() for scalable text
  • Grid systems: CSS Grid with auto-fit for truly responsive layouts
  • Print media: Hide nav, show URLs, optimize for paper
  • Modern features: Container queries, clamp(), prefers-* media features
Note: Container queries provide component-level responsiveness, making components truly reusable across different contexts without media queries.