iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Color Functions

Sass’s sass:color module gives you precise programmatic control over colors — lighten, darken, mix, adjust hue, derive accessible contrasts. Pair with CSS custom properties at runtime for theming and you cover both compile-time palettes and runtime dark mode.

color.adjust, mix, contrast, palettes

EXAMPLE
// 1) Modern modular Sass — always @use, not @import
@use 'sass:color';
@use 'sass:math';
@use 'sass:list';

// 2) Color formats
$hex   : #4f46e5;
$rgb   : rgb(79, 70, 229);
$rgba  : rgba(79, 70, 229, 0.5);
$hsl   : hsl(244, 76%, 59%);
$hsla  : hsla(244, 76%, 59%, 0.5);
$named : indigo;

// All interchangeable in Sass operations.

// 3) Channel access
color.red  ($hex)               // 79
color.green($hex)               // 70
color.blue ($hex)               // 229
color.hue       ($hex)          // 244deg
color.saturation($hex)          // 76%
color.lightness ($hex)          // 59%
color.alpha     ($hex)          // 1

// 4) color.adjust — fine-tune by absolute amounts
color.adjust($hex, $lightness: 10%)                 // lighten by 10 points
color.adjust($hex, $lightness: -10%)                 // darken
color.adjust($hex, $saturation: -20%, $hue: 30deg)
color.adjust($hex, $alpha: -0.2)                     // opacity drop

// 5) color.scale — proportional (better than adjust for big swings)
color.scale($hex, $lightness: 50%)                   // halfway to white
color.scale($hex, $lightness: -50%)                  // halfway to black
color.scale($hex, $alpha: -50%)                       // half as opaque

// scale is multiplicative; adjust is additive. Reach for scale for tints/shades.

// 6) color.mix — blend two colors
color.mix(red, blue)                                  // 50/50
color.mix(red, blue, 25%)                              // 25% red, 75% blue
color.mix($hex, white, 90%)                           // very light tint of $hex
color.mix($hex, black, 90%)                           // deep shade

// 7) Generate a 11-step palette from a single seed
@function palette($base) {
    $out: ();
    $out: map-merge($out, ( '50':  color.mix(white, $base, 90%) ));
    $out: map-merge($out, ( '100': color.mix(white, $base, 80%) ));
    $out: map-merge($out, ( '200': color.mix(white, $base, 65%) ));
    $out: map-merge($out, ( '300': color.mix(white, $base, 45%) ));
    $out: map-merge($out, ( '400': color.mix(white, $base, 20%) ));
    $out: map-merge($out, ( '500': $base ));
    $out: map-merge($out, ( '600': color.mix(black, $base, 15%) ));
    $out: map-merge($out, ( '700': color.mix(black, $base, 30%) ));
    $out: map-merge($out, ( '800': color.mix(black, $base, 50%) ));
    $out: map-merge($out, ( '900': color.mix(black, $base, 70%) ));
    $out: map-merge($out, ( '950': color.mix(black, $base, 85%) ));
    @return $out;
}

$indigo: palette(#4f46e5);
.btn { background: map-get($indigo, '500'); }
.btn:hover { background: map-get($indigo, '600'); }

// 8) Emit as CSS custom properties — runtime theming
@use 'sass:map';
@mixin emit-palette($name, $palette) {
    @each $shade, $value in $palette {
        --\#{$name}-\#{$shade}: #{$value};
    }
}

:root {
    @include emit-palette('indigo', $indigo);
}

.btn {
    background: var(--indigo-500);
    color: white;
}
.btn:hover { background: var(--indigo-600); }

// 9) Contrast helpers — pick black/white text for accessibility
@function readable-color($bg, $light: white, $dark: black, $threshold: 60%) {
    @if color.lightness($bg) > $threshold {
        @return $dark;
    }
    @return $light;
}

.btn-primary {
    background: $hex;
    color: readable-color($hex);
}

// 10) WCAG contrast — proper calculation
@function luminance($c) {
    $r: math.div(color.red($c),   255);
    $g: math.div(color.green($c), 255);
    $b: math.div(color.blue($c),  255);
    $r: if($r <= 0.03928, math.div($r, 12.92), math.pow(math.div($r + 0.055, 1.055), 2.4));
    $g: if($g <= 0.03928, math.div($g, 12.92), math.pow(math.div($g + 0.055, 1.055), 2.4));
    $b: if($b <= 0.03928, math.div($b, 12.92), math.pow(math.div($b + 0.055, 1.055), 2.4));
    @return 0.2126 * $r + 0.7152 * $g + 0.0722 * $b;
}

@function contrast-ratio($a, $b) {
    $la: luminance($a) + 0.05;
    $lb: luminance($b) + 0.05;
    @return if($la > $lb, math.div($la, $lb), math.div($lb, $la));
}

// Pass WCAG AA for body text: ratio >= 4.5

// 11) Modern CSS color-mix() at runtime
.btn:hover {
    background: color-mix(in srgb, var(--accent), white 10%);   // 10% white blend
}
.btn:active {
    background: color-mix(in oklab, var(--accent), black 12%);
}

// color-mix() in oklab/oklch gives perceptually uniform blends — better than srgb for design systems.

// 12) Dark mode palette inversion (smart-ish)
@function dark-palette($palette) {
    $keys: list.reverse(map.keys($palette));
    $values: map.values($palette);
    $out: ();
    @for $i from 1 through length($keys) {
        $key: list.nth($keys, $i);
        $val: list.nth($values, $i);
        $out: map.set($out, $key, $val);
    }
    @return $out;
}

// 13) Theming variants
$light: (
    'bg':    white,
    'fg':    #0f172a,
    'border': #e2e8f0,
    'accent': #4f46e5,
);
$dark: (
    'bg':    #0f172a,
    'fg':    #f8fafc,
    'border': #1e293b,
    'accent': #818cf8,
);

@mixin theme($map) {
    @each $k, $v in $map {
        --\#{$k}: #{$v};
    }
}

:root             { @include theme($light); }
[data-theme='dark'] { @include theme($dark); }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme='light']) { @include theme($dark); }
}

// 14) Common bugs
// • Using lighten()/darken() — deprecated in modern Sass; use color.scale / color.adjust
// • @import — deprecated; use @use
// • Hard-coded hex everywhere — bypass design tokens; centralise + reference
// • Adjusting alpha with color.adjust($alpha: 0.5) — that's absolute; use scale for proportional
// • Mixing 'in srgb' for design accents — non-uniform; try 'in oklab' for perceptual blending
// • Generated palette has inconsistent contrast — verify each step meets WCAG AA at intended use
// • Computing colors at runtime via JS instead of CSS color-mix — extra JS for a CSS feature

Why it matters

Use Sass’s color module for build-time palette generation (mix toward white/black for tints/shades), emit the palette as CSS custom properties, and lean on runtime color-mix(in oklab, ...) for perceptual hover states. Always verify WCAG contrast for every shade you ship.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
color: lighten(#04AA6D, 10%);
background: darken(#04AA6D, 10%);
// Modern: color: color.scale($base, $lightness: 10%);
Try it Yourself »

Discussion

Loading…