Skip to content

Responsive techniques

Breakpoints handle the big shifts — stacking columns, hiding elements, changing font sizes. But between breakpoints, your layout still needs to behave well. That is where relative units, fluid sizing, and flexible images come in. These techniques make your design stretch and compress smoothly across every screen width, not just the ones you defined breakpoints for.

Two principles to carry through this page:

  • Fixed values create edges. Relative values create ranges. A heading set to 48px is always 48px. A heading set to 3rem adapts if the user changes their browser font size.
  • The best responsive design needs fewer breakpoints, not more. The more your base styles flex naturally, the less breakpoint-specific overriding you have to do.

Choosing the right unit

Silex supports a wide range of CSS units. Picking the right one is the most impactful responsive decision you will make.

Pixels (px)

Px are absolute. 16px is always 16 pixels on screen. Use them for values that genuinely should not change — a 1px border, a small icon's dimensions, a shadow offset.

The problem: a 960px-wide container overflows on any screen narrower than 960px. For widths, heights, padding, and font sizes, relative units almost always work better.

Percentages (%)

Percentages are relative to the parent element. A div set to Width 50% takes half its parent's width. Resize the parent and the child follows.

Use percentages for:

  • Container widths: width: 90% with a max-width in pixels gives you a fluid container that caps at a readable size.
  • Horizontal Padding and Margin: padding: 0 5% keeps breathing room proportional to the screen.

Watch out: percentage-based vertical padding is calculated from the parent's width, not its height. This is a CSS quirk that catches people off guard.

Em and rem

Em is relative to the element's own Font-size. If an element has a font size of 16px, then 1.5em = 24px. This makes em useful for spacing that should scale with text — padding inside a button, for example, stays proportional to the button's label.

Rem is relative to the root (html) element's font size. The browser default is 16px, so 1rem = 16px unless you change the root. Because rem always references the same base, it is more predictable than em and avoids compounding (where nested em values multiply).

When to use each: - rem for font sizes, global spacing values, and anything that should be consistent across the page. - em for component-internal spacing — padding and margin that should scale with the component's own text size.

Viewport units (vw, vh)

Vw is 1% of the viewport width. Vh is 1% of the viewport height.

Use vw for elements that should be a fraction of the screen width regardless of their container. A hero section set to height: 80vh fills 80% of the visible screen on any device.

Caution: vw includes the scrollbar width on some browsers, which can cause a horizontal scrollbar. Use width: 100% on containers instead of 100vw.

Container query units (cqi, cqb, cqw, cqh, cqmin, cqmax)

These newer units are relative to a container element's size rather than the viewport. They require the parent to be set up as a container query context.

Unit Relative to
cqi Container's inline (horizontal) size
cqb Container's block (vertical) size
cqw Container's width
cqh Container's height
cqmin Smaller of cqi and cqb
cqmax Larger of cqi and cqb

Container query units are powerful for reusable components that need to adapt to their container, not the viewport. A card component with font-size: 2cqi will have text that scales with the card's width, whether that card is in a sidebar or a full-width section.

Fluid typography

Instead of setting a fixed font size and overriding it at each breakpoint, you can make text scale smoothly with the viewport.

The simplest approach: set font sizes in rem on the desktop device, then override with smaller rem values at your mobile breakpoint. Text jumps once at the breakpoint but stays proportional otherwise.

The fluid approach: use vw units to make font sizes scale continuously. For example, a heading at 4vw is always 4% of the viewport width — large on desktop, smaller on mobile, with no jumps.

The risk with pure vw is that text can become too small on phones or too large on ultrawide monitors. Combine vw with a minimum using the CSS clamp() function. Silex supports clamp() in property values — type it directly:

clamp(1.5rem, 4vw, 3rem)

This means: the font size is 4vw, but never smaller than 1.5rem and never larger than 3rem. You get fluid scaling with sensible limits, and zero breakpoints needed for that property.

Fluid spacing

The same technique works for Padding, Margin, Column-gap, and Row-gap.

A section with padding: 5vw has generous spacing on a wide monitor and tight spacing on a phone — automatically.

If you use CSS Variables, define your spacing scale as variables on :root and override them at breakpoints. Every element referencing var(--spacing-large) updates in one place:

--spacing-large: 48px     /* desktop */
--spacing-large: 24px     /* at the mobile breakpoint */

Responsive images

Images are one of the most common sources of responsive problems. A 1200px-wide photo will overflow a 320px phone screen unless you tell it to scale.

The essential rule: set Max-width to 100% on images. This ensures the image never exceeds its container's width but displays at its natural size when space allows.

In the Style panel, select the image and set:

  • Max-width: 100%
  • Height: auto (to maintain aspect ratio)

This is the single most effective responsive image technique. It works without any breakpoints.

For background images: use Background-size set to cover or contain. Cover fills the container and crops if needed. Contain fits the entire image inside the container with possible empty space.

Responsive video and maps

Videos and embedded maps (iframes) need the same treatment as images. Set Max-width to 100% on video elements. For iframes, wrap them in a container div and control sizing through the container.

Building a fluid layout without breakpoints

Combining these techniques, you can create layouts that barely need breakpoints:

  1. Container: width: 90%, max-width: 1200px, centered with margin: 0 auto
  2. Card grid: parent set to Flex, Flex-wrap wrap, Column-gap 2vw, Row-gap 2vw. Each card: Flex-basis 300px, Flex-grow 1
  3. Typography: headings at clamp(1.5rem, 4vw, 3rem), body text at 1rem
  4. Images: Max-width 100%, Height auto

This grid wraps naturally. Text scales smoothly. Images fit their containers. You might only need one breakpoint to switch a navigation bar from horizontal to vertical.

When to use breakpoints anyway

Fluid techniques reduce the need for breakpoints but do not eliminate them. You still need breakpoints when:

  • A horizontal navigation should become a hamburger menu on mobile.
  • A sidebar should move below the main content.
  • An element should be hidden entirely on small screens.
  • Flex-direction needs to change from row to column.

The goal is to handle the smooth scaling with fluid units and save breakpoints for the structural changes. See Breakpoints for how to set those up.

Common mistakes

  • Using px for everything. The layout works on your screen but breaks on every other size. Start with relative units and only use px for small, fixed values.
  • Setting width: 100vw on containers. This includes the scrollbar and causes a horizontal scroll. Use width: 100% instead.
  • Forgetting max-width on images. One oversized image can break the entire layout on mobile.
  • Using em for font sizes in deeply nested elements. Each nested level multiplies: 1.2em inside 1.2em inside 1.2em = much larger than you expected. Use rem for font sizes.
  • Overcomplicating clamp(). Start simple. clamp(1rem, 2.5vw, 2rem) is readable. Adding calculations inside clamp() makes it harder to maintain.

Learn more


Advanced: combining clamp with CSS Variables

Fluid spacing system with variables

You can define a full fluid spacing scale using CSS Variables and clamp():

--spacing-xs:  clamp(4px, 0.5vw, 8px)
--spacing-sm:  clamp(8px, 1vw, 16px)
--spacing-md:  clamp(16px, 2vw, 32px)
--spacing-lg:  clamp(24px, 3vw, 48px)
--spacing-xl:  clamp(32px, 4vw, 64px)

Every element using var(--spacing-md) for padding gets fluid spacing that scales between 16px and 32px. No breakpoints needed for spacing — it scales continuously.

Fluid type scale

Similarly, define a type scale:

--text-sm:   clamp(0.875rem, 1vw, 1rem)
--text-base: clamp(1rem, 1.2vw, 1.125rem)
--text-lg:   clamp(1.25rem, 2vw, 1.5rem)
--text-xl:   clamp(1.5rem, 3vw, 2.25rem)
--text-2xl:  clamp(2rem, 4vw, 3rem)

Apply these through the CSS Variables panel (see Design system) and your entire site's typography responds to the viewport width.

Container queries for component-level responsiveness

Container query units (cqi, cqb, etc.) let a component respond to its own container rather than the viewport. This is useful when the same component appears in different-width contexts — a card in a sidebar vs. a card in a full-width grid.

To use container queries, the parent element needs container-type: inline-size set via custom code or the Style panel. Then children can use cqi-based units.

Reference: unit comparison table
Unit Relative to Best for Avoid for
px Nothing (absolute) Borders, shadows, small fixed values Container widths, font sizes, spacing
% Parent element Container widths, horizontal padding Font sizes (hard to predict)
em Element's font size Component-internal spacing Font sizes in nested contexts
rem Root font size Font sizes, global spacing Values that must match parent size
vw Viewport width Fluid typography, full-bleed layouts Container widths (scrollbar issue)
vh Viewport height Hero sections, full-screen layouts Most other uses (mobile address bar changes vh)
cqi Container inline size Component-level responsive sizing Elements without a query container parent
cqb Container block size Vertical component adaptation Rarely useful in horizontal layouts
cqw Container width Same as cqi in horizontal writing Same as cqi
cqh Container height Same as cqb in horizontal writing Same as cqb
cqmin Smaller of cqi/cqb Square-ish scaling Uncommon — test carefully
cqmax Larger of cqi/cqb Dominant-axis scaling Uncommon — test carefully

Quiz

Q1: You have a heading at font-size: 48px. On a phone, it takes up most of the screen width. What is the best fix?

  • A) Add a breakpoint and set the font size to 24px on mobile
  • B) Change the font size to clamp(1.5rem, 4vw, 3rem) so it scales smoothly
  • C) Set the heading width to 50%
Answer

B) Change the font size to clamp(1.5rem, 4vw, 3rem) so it scales smoothly — This gives you fluid scaling between a minimum and maximum without needing a breakpoint. Option A works but creates a jump at the breakpoint.

Q2: An image overflows its container on mobile. What single property fixes this?

  • A) Width: 100%
  • B) Max-width: 100%
  • C) Display: none
Answer

B) Max-width: 100% — This prevents the image from exceeding its container while allowing it to display at its natural size when space permits. Width 100% would force the image to always fill the container, stretching small images unnecessarily.

Q3: You set padding: 2em on a button inside a card, inside a sidebar. The padding looks too large. What is likely happening?

  • A) The em unit is compounding through nested font sizes
  • B) The button's font size is very large
  • C) Either A or B — em is relative to the element's own font size, which may be inherited from nested contexts
Answer

C) Either A or B — If parent elements have font sizes set in em, the effective font size at the button level could be larger than expected, making 2em of padding larger than intended. Using rem instead would give a predictable value based on the root font size.

Q4: You want a container that is 90% of the screen on mobile but never wider than 1200px on desktop. How do you set this up?

  • A) Width 90% at the mobile breakpoint, width 1200px at desktop
  • B) Width 90% and Max-width 1200px, no breakpoint needed
  • C) Width 1200px and Min-width 90%
Answer

B) Width 90% and Max-width 1200px, no breakpoint needed — The container fills 90% of its parent but caps at 1200px. This is fluid by default and needs zero breakpoints.

Q5: Why should you avoid width: 100vw on a page container?

  • A) It does not include padding
  • B) It includes the scrollbar width, causing a horizontal scrollbar
  • C) It only works on mobile
Answer

B) It includes the scrollbar width, causing a horizontal scrollbar — On browsers that show a scrollbar, 100vw is wider than the visible area. Use width: 100% instead, which respects the available space.

Edit this page on GitLab