Skip to content

Sass Colors

Colors are one of the most common things developers manipulate with Sass. This lesson covers color formats Sass understands, how to programmatically adjust colors with the sass:color module, and patterns for building a maintainable color palette.

How Does Sass Represent Colors?

Sass understands every standard CSS color format, hex (#2563eb), functional notation (rgb(37 99 235), hsl(221 83% 53%)), and named colors (rebeccapurple), as a first-class color value you can inspect and transform, not just as opaque text.

$primary: #2563eb;

@use 'sass:color';

.button {
  background: $primary;

  &:hover {
    background: color.adjust($primary, $lightness: -8%);
  }
}

color.adjust() computes a new color at compile time; the browser only ever receives the final, resolved hex or rgb value.

Color Function Syntax

@use 'sass:color';

color.adjust($color, $lightness: 10%);
color.scale($color, $alpha: -50%);
color.mix($color-a, $color-b, 50%);
  • color.adjust() changes a channel by a fixed amount (lightness, saturation, hue, alpha, and more).
  • color.scale() changes a channel proportionally toward its maximum or minimum.
  • color.mix() blends two colors together by a given weight.
  • Legacy global functions like lighten() and darken() still work but are thin wrappers around these module functions.

Sass Color Functions Cheatsheet

The most useful sass:color module functions for building a color system.

Function Example Effect
color.adjust() color.adjust($c, $lightness: 10%) Lightens a color by a fixed amount
color.adjust() color.adjust($c, $alpha: -0.2) Reduces opacity by a fixed amount
color.scale() color.scale($c, $lightness: 20%) Lightens proportionally toward white
color.mix() color.mix($a, $b, 50%) Blends two colors evenly
color.complement() color.complement($c) Returns the color's complement (180° hue shift)
color.lightness() color.lightness($c) Reads a color's lightness channel
color.channel() color.channel($c, 'red', $space: rgb) Reads a specific color channel

Building a Color Palette With Variables and a Map

Rather than scattering raw hex values across a stylesheet, define a single source-of-truth map, then generate variants (hover states, tints, shades) from it using color functions.

$colors: (
  primary: #2563eb,
  success: #16a34a,
  danger: #dc2626,
);

@use 'sass:map';
@use 'sass:color';

@each $name, $value in $colors {
  .btn-#{$name} {
    background: $value;

    &:hover {
      background: color.adjust($value, $lightness: -8%);
    }
  }
}

This generates hover-state variants automatically for every color in the map, without repeating logic per color.

color.adjust() vs color.scale()

color.adjust() changes a channel by an absolute amount, adding or subtracting a fixed percentage or number. color.scale() changes a channel proportionally, moving a percentage of the remaining distance toward the channel's maximum or minimum, which tends to produce more visually consistent results across colors of different starting lightness.

@use 'sass:color';

$light-blue: color.adjust(#2563eb, $lightness: 40%); // fixed +40%
$scaled-blue: color.scale(#2563eb, $lightness: 40%); // 40% of the way to white

Checking Color Contrast

While Sass cannot fully replace real accessibility contrast testing, color.lightness() can drive simple heuristics, like the contrast-color() function shown in the Custom Functions lesson, to automatically pick readable text colors for a given background.

Common Mistakes

  • Hardcoding dozens of one-off hex values instead of deriving variants from a small, central color palette.
  • Confusing color.adjust()'s fixed-amount behavior with color.scale()'s proportional behavior, leading to inconsistent-looking variants.
  • Manually picking hover/focus colors by eye instead of deriving them programmatically, causing inconsistency across components.
  • Forgetting that color.adjust($c, $lightness: -8%) clamps at 0%/100% and won't overshoot even with a larger request.

Key Takeaways

  • Sass treats colors as real values, supporting hex, functional (rgb(), hsl()), and named formats.
  • color.adjust() shifts a channel by a fixed amount; color.scale() shifts it proportionally.
  • color.mix() blends two colors, and color.complement() returns the hue-shifted complement.
  • Deriving colors from a small palette map keeps a design system consistent and easy to update.

Pro Tip

Store only your base brand colors as variables, then generate hover, focus, and disabled-state variants programmatically with color.adjust() or color.scale(), changing one base color then automatically updates every derived state.