Mixins

Mixins output reusable declarations: layouts, breakpoints, button variants, focus rings and accessibility helpers. They help you write less, more consistent code.

Create better card component linking by only using the title’s link (and not the whole block). Please visit this article about cards by Heydon Pickering for more information about the technique.

NameDefault ValueDescription
$linkThe selector of the link element.
$at-rootfalseWhether output the link as a child of the parent component or at the root level.

View Source on GitHub

Example(s)

.card {
  @include a11y-card-link('.card__link', true);
  border: 1px solid color('border');
  border-radius: config('border-radius-lg', $display);
  padding: spacer('m');

  &__link {
    color: color('heading');
    font-size: font-size('h3');
    font-weight: 700;
    text-decoration: none;
  }
}

breakpoint

With the breakpoint mixin, you can create a min-width based (mobile-first) breakpoint on a predefined breakpoint from the $breakpoints map.

The predefined breakpoints are the following:

$breakpoints: (
  'xs': 32em,
  'sm': 48em,
  'md': 64em,
  'lg': 80em,
  'xl': 90em,
  'xxl': 110em,
);

Argument(s)

NameDefault ValueDescription
$breakpointThe name of the key from the $breakpoints map.
$logicfalseAny custom logic next to the min-width value connected with the “and” logical operator.

View Source on GitHub

Example(s)

.footer {
  display: block;
  align-items: center;

  @include breakpoint('md') { // @media (min-width: 64em)
    display: flex;
    justify-content: space-between;
  }
}

breakpoint-between

New in v3. A media query between two breakpoints (the lower one inclusive, the upper one exclusive), with the range syntax.

Argument(s)

NameDescription
$minThe name of the lower breakpoint.
$maxThe name of the upper breakpoint.

View Source on GitHub

Example(s)

.sidebar {
  @include breakpoint-between('md', 'xl') { // @media (64em <= width < 90em)
    inline-size: 14rem;
  }
}

breakpoint-down

New in v3. A max-width based (desktop-first) media query: the content applies below the breakpoint.

Argument(s)

NameDescription
$breakpointThe name of the key from the $breakpoints map.

View Source on GitHub

Example(s)

.navigation {
  @include breakpoint-down('md') { // @media (width < 64em)
    display: none;
  }
}

btn-variant

Using the btn-variant mixin, you can create a new button variant. First, you must declare the colors of the new button (the background and the foreground are required) under btn in the $colors map, at the first @use of Spruce.

Argument(s)

NameDefault ValueDescription
$type'primary'The name/prefix of the related colors under the btn map.
$focustrueSet it true if you want to display a focus outline ring.

View Source on GitHub

Example(s)

Declare the colors of the button. The mixin will search for the keys under the btn object.

@use 'sprucecss/scss/spruce' with (
  $colors: (
    'btn': (
      'custom-background': hsl(0deg 0% 95%),
      'custom-foreground': hsl(0deg 0% 10%),
    ),
  ),
);

In many cases, declaring just the background and foreground color is enough. Spruce will generate the rest (hover states). But if you want to control more or use dark mode (where you want to overwrite the color values), you can be more specific.

@use 'sprucecss/scss/spruce' with (
  $colors: (
    'btn': (
      'primary-background': hsl(261deg 52% 59%),
      'primary-background-hover': hsl(261deg 52% 49%),
      'primary-foreground': hsl(0deg 0% 100%),
      'primary-foreground-hover': hsl(0deg 0% 100%),
      'primary-focus-ring': hsl(261deg 52% 59% / 0.25),
    ),
  ),
);
.btn--custom {
  @include btn-variant('custom');
}
<a href="https://conedevelopment.com" class="btn btn--custom btn--lg">Go to Cone</a>

btn-variant-outline

Using the btn-variant-outline mixin, you can create a new outlined button variant. First, you must declare the colors of the new button (the background and the foreground are required) under btn in the $colors map, at the first @use of Spruce.

Argument(s)

NameDefault ValueDescription
$type'primary'The name/prefix of the related colors under the btn map.
$focustrueSet it true if you want to display a focus outline ring.

View Source on GitHub

Example(s)

.btn--outline-primary { @include btn-variant-outline('primary'); }
.btn--outline-secondary { @include btn-variant-outline('secondary'); }

btn-variant-ghost

New in v3. A transparent button that gets a translucent background (a color-mix() of the variant color) on hover. Set the *-ghost-foreground and *-ghost-background-hover colors for full control.

Argument(s)

NameDefault ValueDescription
$type'primary'The name/prefix of the related colors under the btn map.
$focustrueWhether to output the focus ring.

View Source on GitHub

Example(s)

.btn--ghost-brand { @include btn-variant-ghost('brand'); }

New in v3. A button that looks like a link but keeps the button sizing. It uses the link and link-hover colors.

View Source on GitHub

Example(s)

.btn--link { @include btn-variant-link; }

btn-variant-soft

New in v3. A tinted button: a light mix of the variant color as the background and the variant color as the text. Set the *-soft-background, *-soft-background-hover and *-soft-foreground colors for full control.

Argument(s)

NameDefault ValueDescription
$type'primary'The name/prefix of the related colors under the btn map.
$focustrueWhether to output the focus ring.

View Source on GitHub

Example(s)

.btn--soft-brand { @include btn-variant-soft('brand'); }

clear-btn

Clear the default browser button styles.

View Source on GitHub

Example(s)

.remove-button-styles {
  @include clear-btn;
}

clear-list

Remove the list-style, margin, and padding stylings from the element.

View Source on GitHub

Example(s)

ul {
  @include clear-list;
}

container-query

New in v3. A container query (inline-size >) with a breakpoint name or any size. The parent needs container-type: inline-size.

Argument(s)

NameDefault ValueDescription
$sizeA breakpoint name or a size value.
$namenullThe name of the container (optional).

View Source on GitHub

Example(s)

.card-wrapper {
  container-type: inline-size;
}

.card {
  display: grid;

  @include container-query(30rem) {
    grid-template-columns: 10rem 1fr;
  }
}

cover

New in v3. Make an element fill its positioned parent (inset: 0).

Argument(s)

NameDefault ValueDescription
$positionabsoluteThe position value.

View Source on GitHub

Example(s)

.hero__overlay {
  @include cover;
  background-color: color-alpha('heading', 0.5);
}

dark-mode

New in v3. Output styles for the dark mode, based on the dark-mode settings (the selector and the optional prefers-color-scheme media query). Use it at the root level with rules, or inside a rule with declarations.

Argument(s)

NameDefault ValueDescription
$scopenullAn optional scope selector inside the dark mode (used by styles).

View Source on GitHub

Example(s)

.logo {
  filter: none;

  @include dark-mode {
    filter: invert(1);
  }
}

@include dark-mode {
  .illustration { opacity: 0.85; }
}

field-disabled

The field-disabled() is a small internal helper mixin to set up the disabled state on form fields. We call it on the .form-control and .form-check classes.

Argument(s)

NameDescription
$backgroundThe color value of the background.
$borderThe color value of the border.

View Source on GitHub

Example(s)

.form-control:[disabled],
.form-control:[disabled='true'] {
  @include field-disabled(
    color('background-disabled', 'form'),
    color('border-disabled', 'form')
  );
}

field-icon

The field-icon() mixin is a getter function for form input backgrounds. Spruce CSS uses custom images (used as inline SVG) for various inputs (checkbox, radio, select, success, error states).

This mixin first replaces the given color value as a fill value on the SVG image then escapes it.

It is helpful for dark mode because we can’t pass a CSS variable to an inline SVG, so we have to overwrite it.

Argument(s)

NameDescription
$iconThe name of the icon variable.
$colorThe color value of the fill.

View Source on GitHub

Example(s)

select {
  select.form-control:not([multiple]):not([size]) {
    @include field-icon(
      config('select', $form-icon, false),
      color('select-foreground', 'form')
    );
  }
}

focus-ring

The focus-ring() is a small internal helper mixin to set up the focus state of the form fields, buttons (or anything). We call it on the .form-control, .form-check, .form-switch, .form-range, and button variants. For these calls, it works with global, related variables.

Argument(s)

NameDefault ValueDescription
$type'box-shadow'The type of the focus ring: outline or box-shadow.
$border-colornullThe color value of the border. It is needed mostly on inputs.
$ring-colorThe color of the focus ring.
$box-shadow-typeWhere should it place the box-shadow: outside or inside.
$ring-sizeThe width of the focus ring.
$ring-offsetThe offset of the focus ring if the type is outline.

View Source on GitHub

Example(s)

.form-control:focus {
  @include focus-ring(
    $type: config('focus-ring-type', $form-control, false),
    $border-color: color('border-focus', 'form'),
    $ring-color: color('ring-focus', 'form'),
    $box-shadow-type: config('focus-ring-box-shadow-type', $form-control, false),
    $ring-size: config('focus-ring-size', $form-control, false),
    $ring-offset: config('focus-ring-offset', $form-control, false)
  );
}

font-face

The font-face mixin is a helper to generate a @font-face declaration. This is a minimal and modern font-face declaration, so it only supports the .woff2 format (under the $src argument).

Argument(s)

NameDefault ValueDescription
$font-familynullThe name of the font family.
$srcnullThe URL path to the font file.
$font-weight400The weight of the font.
$font-stylenormalThe style of the font.
$font-displayswapThe font-display property value.

View Source on GitHub

Example(s)

@include font-face(
  'Montserrat',
  '../fonts/montserrat-v25-latin-ext_latin-regular.woff2'
);

@include font-face(
  'Montserrat',
  '../fonts/montserrat-v25-latin-ext_latin-700.woff2',
  '700'
);

form-check

The checkbox and radio styles come from the generate-form-check() generator mixin. It accepts three selectors, so you can apply the Spruce look to markup you can’t change.

There are scenarios (unfortunately) where it is easier to modify the CSS code than the HTML markup. For example, we usually style the checkboxes and radios of the Contact Form 7 plugin this way.

Argument(s)

NameDefault ValueDescription
$parentThe selector of the parent element.
$inputThe selector of the input element.
$labelThe selector of the label element.
$has-sizesfalseTurn on the sizes variants (*--sm, *--lg).

View Source on GitHub

Example(s)

@include generate-form-check(
  '.wpcf7-list-item label',
  '.wpcf7-list-item input',
  '.wpcf7-list-item .wpcf7-list-item-label'
);

form-group-stacked

Using the form-group-stacked mixin, you can create a stacked form group with a breakpoint. Under the breakpoint, the items stack vertically.

Argument(s)

NameDefault ValueDescription
$breakpoint'sm'The breakpoint.

View Source on GitHub

.form-group--stacked\:md {
  @include form-group-stacked('md');
}

layout-center

With the help of the layout-center mixin, you can center any element. It is most useful for the generic container element for the main layouts.

Argument(s)

NameDefault ValueDescription
$gap'm'The padding value on either side of the element. The value comes from the $spacers map, use any declared key name for shorthand.
$max-inline-sizeconfig('container-inline-size', $layout)Set the max-inline-size (max-width) value of the element.

View Source on GitHub

Example(s)

.hero {
  &__container {
    @include layout-center(
      spacer-clamp('m', 'l')
    );
  }
}

layout-cluster

New in v3. Inline items that wrap, with a gap: tags, buttons, navigation links.

Argument(s)

NameDefault ValueDescription
$gap's'The gap (a spacer key, a 'm:l' shorthand or any value).
$justifyflex-startThe justify-content value.
$aligncenterThe align-items value.

View Source on GitHub

Example(s)

.tag-list {
  @include layout-cluster('xs');
}

layout-flex

Using the layout-flex mixin, you can create intrinsic flexbox grids with explicit column width.

Argument(s)

NameDefault ValueDescription
$gap'm'The gutter value between the elements. The value comes from the $spacers map, use any declared key name for shorthand.
$inline-size--inline-sizeThe optimal width of the columns.

View Source on GitHub

Example(s)

.form-row--mixed {
  --inline-size: 10rem;

  @include layout-flex;
}

For the $gap you can also use a shorthand like in the spacer() function for setting separate value for the block and inline gap.

.form-row--mixed {
  --inline-size: 10rem;

  @include layout-flex('m:l');
}

layout-grid

With the help of the layout-grid mixin you can create auto-fit grid layouts where you can determine the columns' min-width.

Argument(s)

NameDefault ValueDescription
$gap'm'The gutter value between the elements. The value comes from the $spacers map, use any declared key name for shorthand.
$minimum12.5remThe minimum value of the child elements where it automatically breaks.

View Source on GitHub

Example(s)

.docs-cards {
  &__inner {
    @include layout-grid('l', 20rem);
  }
}

For the $gap you can also use a shorthand like in the spacer() function for setting separate value for the block and inline gap.

.docs-cards {
  &__inner {
    @include layout-grid('m:l', 20rem);
  }
}

layout-reel

New in v3. A horizontally scrollable row with scroll snapping.

Argument(s)

NameDefault ValueDescription
$item-inline-size18remThe width of the items.
$gap'm'The gap between the items.

View Source on GitHub

Example(s)

.product-row {
  @include layout-reel(16rem, 's');
}

layout-sidebar

Using the layout-sidebar mixin, you can create a two-column sidebar layout declaring the sidebar width explicitly.

Argument(s)

NameDefault ValueDescription
$gap'm'The gutter value between the elements. The value comes from the $spacers map, use any declared key name for shorthand.
$inline-size18.75remThe width of the sidebar element.

View Source on GitHub

Example(s)

.docs-template {
  @include layout-sidebar('l', 22rem);
}

For the $gap you can also use a shorthand like in the spacer() function for setting separate value for the block and inline gap.

.docs-template {
  @include layout-sidebar('m:l', 22rem);
}

layout-stack

Using the help of the layout-stack mixin, you can classical stack layout where the elements are stacked under each other.

Argument(s)

NameDefault ValueDescription
$gap'm'The margin value between the elements. The value comes from the $spacers map, use any declared key name for shorthand.
$inline-sizefalseWhether it has explicit width (inline-size).
$alignnoneSet explicit align to the elements(none, left, right).
$importantfalseAdd !important on descendant elements to margin-block-start.
$split0Split the elements vertically from the nth element.

View Source on GitHub

Example(s)

ul {
  @include layout-stack('xs');
}

layout-switcher

New in v3. A row of equal columns that switches to a column under a container width, without media queries. Over the $limit number of items, it is always stacked.

Argument(s)

NameDefault ValueDescription
$threshold30remThe container width where the layout switches.
$gap'm'The gap between the items.
$limit4The maximum number of items in a row.

View Source on GitHub

Example(s)

.features {
  @include layout-switcher(40rem, 'l');
}

motion-reduce

New in v3. Output the content only when the user prefers reduced motion.

View Source on GitHub

Example(s)

.spinner {
  @include motion-reduce {
    animation-duration: 3s;
  }
}

motion-safe

New in v3. Output the content only when the user doesn't prefer reduced motion. Wrap every non-essential animation in it.

View Source on GitHub

Example(s)

.card {
  @include motion-safe {
    transition: translate 0.2s ease;

    &:hover {
      translate: 0 -2px;
    }
  }
}

scrollbar

Create natively styled custom scrollbars.

Argument(s)

NameDefault ValueDescription
$thumb-background-colorcolor(thumb-background, scrollbar)The color of the scrollbar handle.
$thumb-background-color-hovercolor(thumb-background-hover, scrollbar)The color of the scrollbar handle on hover state.
$track-background-colorcolor(track-background, scrollbar)The background color of the scrollbar.
$size0.5remThe width or height of the scrollbar.
$border-radiusconfig('border-radius-sm', $display)The border-radius of the scrollbar and handle.

View Source on GitHub

Example(s)

code {
  @include scrollbar(
    $thumb-background-color: color('primary')
  );
  background-color: transparent;
  border-radius: 0;
  display: block;
  overflow-x: auto;
  padding: spacer('xs') 0;
}

selection

Using the selection mixin, you can simplify the ::selection declarations. Pick a background color value from the base subsection by name and let it calculate the contrast color for the foreground automatically.

Argument(s)

NameDefault ValueDescription
$background'primary'The background color code or the name of the color from the base subsection from $colors map.
$foregroundnullThe foreground color code. It will get a contrasting pair (black or white) if left empty, based on the background value.

View Source on GitHub

Example(s)

.footer {
  // @include selection(hsl(262deg 71% 49%));
  @include selection('secondary');
}

set-css-variable

Declare CSS custom properties through Spruce CSS to add the prefix. To get any CSS variable with prefix use the get-css-variable function.

Argument(s)

NameDescription
$varsA Sass map of key, value pairs.

View Source on GitHub

Example(s)

:root {
  @include set-css-variable((
    --container-gap: spacer-clamp('m', 'l')
  ));
}

short-ring

A shorthand function to get the default focus ring styles for input and button elements.

Argument(s)

NameDefault ValueDescription
$type'input'The type of the focus ring. It can be input or button.
$btn-type'primary'The color - or button type - of the button (if the $type is button) to match the ring color.

View Source on GitHub

Example(s)

.search-form {
  &:focus-visible input[type='search'] {
    @include short-ring('input');
  }
}

.accordion-card {
  &:focus-visible svg {
    @include short-ring('button', 'secondary');
  }
}

text-ellipsis

Crop text and display an ellipsis with multiline support where possible.

Argument(s)

NameDefault ValueDescription
$number-of-lines1Multiline text cropping where supported.

View Source on GitHub

Example(s)

.crop-text {
  @include text-ellipsis(2);
  inline-size: 20rem;
}

Be careful when using the text-ellipsis mixin with flex displays because it will break.

transition

This mixin aims to query the transition variables easier. Usually, you only need the global values (e.g., for anything with a custom hover animation), but you can also overwrite the three basic arguments.

Argument(s)

NameDefault ValueDescription
$durationconfig('duration', $transition)The default duration value is 0.15s.
$propertyallSet the transition-property to all. For multiple value use quotes like 'transition, color'.
$timing-functionconfig('timing-function', $transition)The default timing-function value is ease-in-out.

View Source on GitHub

Example(s)

.custom-link {
  @include transition;

  &:hover {
    background-color: pink;
  }
}

visually-hidden

Hide something from the screen but keep it visible for assistive technology.

View Source on GitHub

Example(s)

.sr-only {
  @include visually-hidden;
}

visually-hidden-focusable

New in v3. Visually hide an element until it, or an element inside it, gets the focus. Use it for skip links.

View Source on GitHub

Example(s)

.skip-link {
  @include visually-hidden-focusable;
}

word-wrap

Break long strings of text.

View Source on GitHub

Example(s)

.break-long-url {
  @include word-wrap;
}

Documentation

Learn about Spruce CSS through our extensive documentation.

Components

Explore our UI library of accessible components built with Spruce CSS.

Blocks and Pages

Full-width page blocks and complete page templates, ready to copy.

Find us on GitHub

Did you find a bug? Have an idea or a question? Please open an issue to help us develop the project.