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 |
|---|---|---|---|
@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.