HC

Responsive Design

HTML & CSS · 8 entries

Media Queries

syntax
@media (condition) { ... }
example
/* Mobile-first approach */
.grid {
  display: grid;
  grid-template-columns: 1fr;
}

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

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

Note Mobile-first (min-width) is the recommended approach: start with small screens and add complexity at wider breakpoints. Common breakpoints: 640px (small), 768px (medium), 1024px (large), 1280px (extra large).

Media Query Features

syntax
@media (prefers-color-scheme: dark) { }
@media (prefers-reduced-motion: reduce) { }
@media (hover: hover) { }
@media (orientation: portrait) { }
example
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0f172a;
    --text: #e2e8f0;
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

@media (hover: hover) {
  .card:hover { transform: translateY(-2px); }
}

Note prefers-color-scheme detects dark/light mode system preference. prefers-reduced-motion is critical for accessibility. hover: hover avoids applying hover styles on touch devices where hover is awkward.

Container Queries

syntax
.parent {
  container-type: inline-size;
  container-name: name;
}
@container name (condition) { ... }
example
.card-wrapper {
  container-type: inline-size;
}

.card {
  display: grid;
  grid-template-columns: 1fr;
}

@container (min-width: 400px) {
  .card {
    grid-template-columns: 150px 1fr;
  }
}

@container (min-width: 600px) {
  .card {
    grid-template-columns: 200px 1fr auto;
  }
}

Note Container queries respond to the size of a parent container rather than the viewport. This makes components truly self-contained. Set container-type on the parent to opt in. Use container-name when you need to target a specific ancestor.

Clamp Function

syntax
clamp(minimum, preferred, maximum)
example
.container {
  width: clamp(320px, 90%, 1200px);
  padding: clamp(16px, 4vw, 48px);
}

h1 {
  font-size: clamp(1.5rem, 2.5vw + 1rem, 3.5rem);
}

Note clamp() eliminates the need for many media queries. It sets a preferred value that flexes between a minimum and maximum. The preferred value usually includes a viewport unit so it scales fluidly. Ideal for typography and spacing.

Viewport Units

syntax
vw | vh | vmin | vmax | dvh | svh | lvh | dvw | svw | lvw
example
.hero {
  min-height: 100dvh; /* accounts for mobile browser chrome */
}

.full-width-banner {
  width: 100vw;
  margin-left: calc(50% - 50vw);
}

.square {
  width: min(80vw, 80vh);
  height: min(80vw, 80vh);
}

Note On mobile browsers, 100vh is taller than the visible area because it does not account for the URL bar. Use 100dvh (dynamic viewport height) which updates as the browser chrome appears and disappears. svh is the smallest possible viewport, lvh is the largest.

Min & Max Functions

syntax
min(value1, value2, ...)
max(value1, value2, ...)
example
.container {
  width: min(90%, 1200px);
  /* same as: width: 90%; max-width: 1200px; */
}

.sidebar {
  width: max(200px, 20%);
  /* at least 200px, grows with container */
}

.padding-responsive {
  padding: max(16px, 3vw);
}

Note min() picks the smallest value, acting like a max-width. max() picks the largest, acting like a min-width. You can mix units freely inside these functions. They often replace media queries for simple responsive adjustments.

Media Query Range Syntax

syntax
@media (width >= 768px) { }
@media (768px <= width <= 1024px) { }
example
@media (width >= 768px) {
  .sidebar { display: block; }
}

@media (768px <= width <= 1024px) {
  .content { padding: 24px; }
}

@media (width < 640px) {
  .desktop-only { display: none; }
}

Note Range syntax is more readable than the traditional min-width/max-width approach. It is supported in all modern browsers. You can use <, <=, >, and >= operators. This replaces awkward constructs like (max-width: 1023.98px).

Container Query Units

syntax
cqw | cqh | cqi | cqb | cqmin | cqmax
example
.card-wrapper {
  container-type: inline-size;
}

.card-title {
  font-size: clamp(1rem, 4cqi, 1.5rem);
}

.card-image {
  height: 30cqi;
}

Note Container query units (cqi for inline, cqb for block) are relative to the container's dimensions, not the viewport. 1cqi equals 1% of the container's inline size. They allow truly component-relative sizing.