Skip to main contentSkip to docs navigation

Breakpoints

Customizable width thresholds that control how layouts, utilities, and components adapt across viewport sizes in Chassis CSS.

@layer layout
Viewport queries
Scoped tokens

Breakpoints are the minimum widths at which the layout system, responsive utilities, and component variants shift behavior. The framework ships six default breakpoints as a Sass map ($breakpoints); all values are overridable before importing Chassis.

Available breakpoints

The six default breakpoints feed the grid system, responsive utilities, and all breakpoint mixins. Override $breakpoints to change all responsive thresholds at once — see Sass variables for the source declaration.

BreakpointClass prefixDimensions
Extra smallNone<576px
Smallsmall≥576px
Mediummedium≥768px
Largelarge≥1024px
Extra largexlarge≥1280px
Extra extra large2xlarge≥1536px

2xlarge starts with a digit. Chassis CSS CSS-escapes the leading digit automatically when generating class names (e.g. \32 xlarge\:), producing a valid CSS identifier. The naming follows the same scale used across sizing tokens and utility classes throughout the framework.

Media queries

All queries use CSS range syntax, driven by the values in $breakpoints. The system is mobile-first: xsmall has a value of 0, so styles defined at that level apply at all widths and no wrapping query is emitted.

Min-width

media-breakpoint-up() applies styles from a given breakpoint and wider. Calling it with xsmall emits no wrapping query, since xsmall has a value of 0.

SCSS
// No media query for `xsmall` — it targets all viewport widths (value 0)
@include media-breakpoint-up(small) { ... }
@include media-breakpoint-up(medium) { ... }
@include media-breakpoint-up(large) { ... }
@include media-breakpoint-up(xlarge) { ... }
@include media-breakpoint-up(2xlarge) { ... }

// Hide at the smallest size, then reveal at `small` and wider
.custom-class {
  display: none;
}
@include media-breakpoint-up(small) {
  .custom-class {
    display: block;
  }
}

These mixins compile to range queries using the values in $breakpoints:

SCSS
// No media query for `xsmall` — the default in Chassis

// Small devices (landscape phones, 576px and up)
@media (width >= 576px) { ... }

// Medium devices (tablets, 768px and up)
@media (width >= 768px) { ... }

// Large devices (desktops, 1024px and up)
@media (width >= 1024px) { ... }

// X-Large devices (large desktops, 1280px and up)
@media (width >= 1280px) { ... }

// 2X-Large devices (larger desktops, 1536px and up)
@media (width >= 1536px) { ... }

Max-width

media-breakpoint-down() applies styles at a given breakpoint and narrower. Calling it with xsmall emits no wrapping query, since breakpoint-max(xsmall) returns null when the breakpoint's value is 0.

SCSS
// No media query for `xsmall` since its breakpoint value is 0
@include media-breakpoint-down(small) { ... }
@include media-breakpoint-down(medium) { ... }
@include media-breakpoint-down(large) { ... }
@include media-breakpoint-down(xlarge) { ... }
@include media-breakpoint-down(2xlarge) { ... }

// Style from medium and narrower
@include media-breakpoint-down(medium) {
  .custom-class {
    display: block;
  }
}

These mixins compile to width < range queries using the raw breakpoint value as the exclusive upper bound:

SCSS
// `xsmall` emits only a ruleset — no wrapping media query

// `small` — narrower than 576px
@media (width < 576px) { ... }

// `medium` — narrower than 768px
@media (width < 768px) { ... }

// `large` — narrower than 1024px
@media (width < 1024px) { ... }

// `xlarge` — narrower than 1280px
@media (width < 1280px) { ... }

// `2xlarge` — narrower than 1536px
@media (width < 1536px) { ... }

Single breakpoint

media-breakpoint-only() applies styles within a single breakpoint range — from its own minimum width up to, but not including, the next breakpoint's minimum. For xsmall, there is no lower bound, so the mixin falls back to media-breakpoint-down(small). For 2xlarge, there is no upper bound, so the mixin falls back to media-breakpoint-up(2xlarge).

SCSS
@include media-breakpoint-only(xsmall) { ... }
@include media-breakpoint-only(small) { ... }
@include media-breakpoint-only(medium) { ... }
@include media-breakpoint-only(large) { ... }
@include media-breakpoint-only(xlarge) { ... }
@include media-breakpoint-only(2xlarge) { ... }

For example, @include media-breakpoint-only(medium) { ... } compiles to:

SCSS
@media (width >= 768px) and (width < 1024px) { ... }

Between breakpoints

media-breakpoint-between() applies styles across a span of breakpoints — from the first argument's minimum up to, but not including, the second argument's minimum. When the lower bound is xsmall (value 0), the mixin falls back to media-breakpoint-down() on the upper bound.

SCSS
@include media-breakpoint-between(medium, xlarge) { ... }

This compiles to:

SCSS
@media (width >= 768px) and (width < 1280px) { ... }

Container queries

Container query mixins mirror the media query mixins and respond to the inline size of a containing element rather than the viewport. Every mixin accepts an optional $container-name argument to scope the query to a named container.

Setting a container

set-container() establishes an element as a query container. The $type argument sets the container-type property; the optional $name argument produces the container shorthand.

SCSS
@include set-container()                      // => container-type: inline-size
@include set-container(size)                  // => container-type: size
@include set-container(inline-size, sidebar)  // => container: sidebar / inline-size

Container min-width

container-breakpoint-up() applies styles when the container is at least as wide as the given breakpoint. No query is emitted for xsmall.

SCSS
@include container-breakpoint-up(medium) { ... }
// => @container (width >= 768px) { ... }

Container max-width

container-breakpoint-down() applies styles when the container is narrower than the given breakpoint. No query is emitted for xsmall (value 0).

SCSS
@include container-breakpoint-down(medium) { ... }
// => @container (width < 768px) { ... }

Container range

container-breakpoint-only() and container-breakpoint-between() work identically to their media query counterparts, scoped to the container.

SCSS
@include container-breakpoint-only(medium) { ... }
// => @container (width >= 768px) and (width < 1024px) { ... }

@include container-breakpoint-between(small, large) { ... }
// => @container (width >= 576px) and (width < 1024px) { ... }

Named containers

Without a name, a container query always targets the nearest ancestor container. In a nested layout — where a sidebar sits inside an outer main region — a widget inside the sidebar can only respond to the sidebar by default, never to the outer main. Named containers solve this by letting a descendant target any specific ancestor, regardless of nesting depth.

SCSS
// Outer layout region — named "main"
.main {
  @include set-container(inline-size, main);
  // => container: main / inline-size
}

// Sidebar nested inside the main — named "sidebar"
.sidebar {
  @include set-container(inline-size, sidebar);
  // => container: sidebar / inline-size
}

// Widget is a descendant of both containers.
// The name passed to each mixin determines which container drives that query.
.sidebar-widget {
  @include container-breakpoint-up(large, main) { ... }
  // => @container main (width >= 992px) { ... }

  @include container-breakpoint-down(small, sidebar) { ... }
  // => @container sidebar (width < 576px) { ... }
}

The first rule fires when main reaches large; the second fires when sidebar drops below small. The same descendant responds to two independent containers simultaneously.

CSS

The Breakpoint system can be customized through Sass variables at compile time.

Sass maps

Override $breakpoints before importing Chassis CSS to change all responsive thresholds.

$breakpoints: (
  xsmall:       0,
  small:        $breakpoint-small,
  medium:       $breakpoint-medium,
  large:        $breakpoint-large,
  xlarge:       $breakpoint-xlarge,
  2xlarge:      $breakpoint-2xlarge
);

Design tokens

The Breakpoint system consumes design tokens from Chassis Tokens with the $cx- prefix. — See thedesign tokens page.

$breakpoint-2xlarge:      $cx-grid-breakpoint-2xlarge;
$breakpoint-xlarge:       $cx-grid-breakpoint-xlarge;
$breakpoint-large:        $cx-grid-breakpoint-large;
$breakpoint-medium:       $cx-grid-breakpoint-medium;
$breakpoint-small:        $cx-grid-breakpoint-small;

Sass mixins

The media query and container query mixins are both defined in scss/mixins/_breakpoints.scss.

/// Apply styles for screens at least as wide as the given breakpoint.
/// No wrapping media query is emitted for the smallest (`xsmall`) breakpoint —
/// the `@content` block is output unconditionally.
///
/// @param {String} $name - Breakpoint name (e.g., "medium", "large")
/// @param {Map} $breakpoints [$breakpoints] - Breakpoint map
/// @content Styles to apply at this breakpoint and wider
/// @example
///   @include media-breakpoint-up(medium) { ... }
///   // => @media (width >= 768px) { ... }
@mixin media-breakpoint-up($name, $breakpoints: $breakpoints) {
  $min: breakpoint-min($name, $breakpoints);
  @if $min {
    @media (width >= $min) {
      @content;
    }
  } @else {
    @content;
  }
}

/// Apply styles for screens no wider than the given breakpoint.
/// No wrapping media query is emitted for the `xsmall` breakpoint —
/// the `@content` block is output unconditionally.
///
/// @param {String} $name - Breakpoint name (e.g., "small", "medium")
/// @param {Map} $breakpoints [$breakpoints] - Breakpoint map
/// @content Styles to apply at this breakpoint and narrower
/// @example
///   @include media-breakpoint-down(medium) { ... }
///   // => @media (width < 768px) { ... }
@mixin media-breakpoint-down($name, $breakpoints: $breakpoints) {
  $max: breakpoint-max($name, $breakpoints);
  @if $max {
    @media (width < $max) {
      @content;
    }
  } @else {
    @content;
  }
}

/// Apply styles for screens between two breakpoints (inclusive on both ends).
/// Falls back to `media-breakpoint-up` or `media-breakpoint-down` when one bound is null.
///
/// @param {String} $lower - Lower bound breakpoint name
/// @param {String} $upper - Upper bound breakpoint name
/// @param {Map} $breakpoints [$breakpoints] - Breakpoint map
/// @content Styles to apply between the two breakpoints
/// @example
///   @include media-breakpoint-between(small, large) { ... }
///   // => @media (width >= 576px) and (width < 992px) { ... }
@mixin media-breakpoint-between($lower, $upper, $breakpoints: $breakpoints) {
  $min: breakpoint-min($lower, $breakpoints);
  $max: breakpoint-max($upper, $breakpoints);

  @if $min != null and $max != null {
    @media (width >= $min) and (width < $max) {
      @content;
    }
  } @else if $max == null {
    @include media-breakpoint-up($lower, $breakpoints) {
      @content;
    }
  } @else if $min == null {
    @include media-breakpoint-down($upper, $breakpoints) {
      @content;
    }
  }
}

/// Apply styles for a single breakpoint only (min-width and max-width bounded).
/// No media query bounds are emitted for the smallest or largest breakpoints.
///
/// @param {String} $name - Breakpoint name
/// @param {Map} $breakpoints [$breakpoints] - Breakpoint map
/// @content Styles to apply only at this breakpoint
/// @example
///   @include media-breakpoint-only(medium) { ... }
///   // => @media (width >= 768px) and (width < 992px) { ... }
@mixin media-breakpoint-only($name, $breakpoints: $breakpoints) {
  $min:  breakpoint-min($name, $breakpoints);
  $next: breakpoint-next($name, $breakpoints);
  $max:  breakpoint-max($next, $breakpoints);

  @if $min != null and $max != null {
    @media (width >= $min) and (width < $max) {
      @content;
    }
  } @else if $max == null {
    @include media-breakpoint-up($name, $breakpoints) {
      @content;
    }
  } @else if $min == null {
    @include media-breakpoint-down($next, $breakpoints) {
      @content;
    }
  }
}
/// Set an element as a query container.
///
/// @param {String} $type [inline-size] - Container type (`inline-size`, `size`, etc.)
/// @param {String|null} $name [null] - Optional container name
/// @example
///   @include set-container()                      // => container-type: inline-size
///   @include set-container(size)                  // => container-type: size
///   @include set-container(inline-size, sidebar)  // => container: sidebar / inline-size
@mixin set-container($type: inline-size, $name: null) {
  @if $name {
    container: #{$name} / #{$type};
  } @else {
    container-type: #{$type};
  }
}

/// Apply container query styles for containers at least as wide as the given breakpoint.
/// No wrapping query is emitted for the smallest breakpoint — `@content` is output unconditionally.
///
/// @param {String} $name - Breakpoint name (e.g., "medium", "large")
/// @param {String|null} $container-name [null] - Optional named container
/// @param {Map} $breakpoints [$breakpoints] - Breakpoint map
/// @content Styles to apply at this breakpoint and wider within the container
/// @example
///   @include container-breakpoint-up(medium) { ... }
///   // => @container (width >= 768px) { ... }
///   @include container-breakpoint-up(medium, sidebar) { ... }
///   // => @container sidebar (width >= 768px) { ... }
@mixin container-breakpoint-up($name, $container-name: null, $breakpoints: $breakpoints) {
  $min: breakpoint-min($name, $breakpoints);
  @if $min {
    @if $container-name {
      @container #{$container-name} (width >= #{$min}) {
        @content;
      }
    } @else {
      @container (width >= #{$min}) {
        @content;
      }
    }
  } @else {
    @content;
  }
}

/// Apply container query styles for containers no wider than the given breakpoint.
/// No wrapping query is emitted for the `xsmall` breakpoint — `@content` is output unconditionally.
///
/// @param {String} $name - Breakpoint name (e.g., "small", "medium")
/// @param {String|null} $container-name [null] - Optional named container
/// @param {Map} $breakpoints [$breakpoints] - Breakpoint map
/// @content Styles to apply at this breakpoint and narrower within the container
/// @example
///   @include container-breakpoint-down(medium) { ... }
///   // => @container (width < 768px) { ... }
///   @include container-breakpoint-down(medium, sidebar) { ... }
///   // => @container sidebar (width < 768px) { ... }
@mixin container-breakpoint-down($name, $container-name: null, $breakpoints: $breakpoints) {
  $max: breakpoint-max($name, $breakpoints);
  @if $max {
    @if $container-name {
      @container #{$container-name} (width < #{$max}) {
        @content;
      }
    } @else {
      @container (width < #{$max}) {
        @content;
      }
    }
  } @else {
    @content;
  }
}

/// Apply container query styles for containers between two breakpoints (inclusive on both ends).
/// Falls back to `container-breakpoint-up` or `container-breakpoint-down` when one bound is null.
///
/// @param {String} $lower - Lower bound breakpoint name
/// @param {String} $upper - Upper bound breakpoint name
/// @param {String|null} $container-name [null] - Optional named container
/// @param {Map} $breakpoints [$breakpoints] - Breakpoint map
/// @content Styles to apply between the two breakpoints within the container
/// @example
///   @include container-breakpoint-between(small, large) { ... }
///   // => @container (width >= 576px) and (width < 992px) { ... }
///   @include container-breakpoint-between(small, large, sidebar) { ... }
///   // => @container sidebar (width >= 576px) and (width < 992px) { ... }
@mixin container-breakpoint-between($lower, $upper, $container-name: null, $breakpoints: $breakpoints) {
  $min: breakpoint-min($lower, $breakpoints);
  $max: breakpoint-max($upper, $breakpoints);

  @if $min != null and $max != null {
    @if $container-name {
      @container #{$container-name} (width >= #{$min}) and (width < #{$max}) {
        @content;
      }
    } @else {
      @container (width >= #{$min}) and (width < #{$max}) {
        @content;
      }
    }
  } @else if $max == null {
    @include container-breakpoint-up($lower, $container-name, $breakpoints) {
      @content;
    }
  } @else if $min == null {
    @include container-breakpoint-down($upper, $container-name, $breakpoints) {
      @content;
    }
  }
}


/// Apply container query styles for a single breakpoint only (min-width and max-width bounded).
/// No query bounds are emitted for the smallest or largest breakpoints.
///
/// @param {String} $name - Breakpoint name
/// @param {String|null} $container-name [null] - Optional named container
/// @param {Map} $breakpoints [$breakpoints] - Breakpoint map
/// @content Styles to apply only at this breakpoint within the container
/// @example
///   @include container-breakpoint-only(medium) { ... }
///   // => @container (width >= 768px) and (width < 992px) { ... }
///   @include container-breakpoint-only(medium, sidebar) { ... }
///   // => @container sidebar (width >= 768px) and (width < 992px) { ... }
@mixin container-breakpoint-only($name, $container-name: null, $breakpoints: $breakpoints) {
  $min:  breakpoint-min($name, $breakpoints);
  $next: breakpoint-next($name, $breakpoints);
  $max:  breakpoint-max($next, $breakpoints);

  @if $min != null and $max != null {
    @if $container-name {
      @container #{$container-name} (width >= #{$min}) and (width < #{$max}) {
        @content;
      }
    } @else {
      @container (width >= #{$min}) and (width < #{$max}) {
        @content;
      }
    }
  } @else if $max == null {
    @include container-breakpoint-up($name, $container-name, $breakpoints) {
      @content;
    }
  } @else if $min == null {
    @include container-breakpoint-down($next, $container-name, $breakpoints) {
      @content;
    }
  }
}