Design system stays DRY — no second hand-picked gray.
Example 4 — Sass Color vs CSS Filter
Use both APIs in one stylesheet — know which is which.
SCSS
@use "sass:color";
.chip {
// Sass: compile-time gray color value
color: color.grayscale(#336699);
}
.photo.is-muted {
// CSS: runtime filter on the element (not a Sass color helper)
filter: grayscale(1);
}
Gray twin: same lightness, no saturation / chroma.
Load@use "sass:color" and prefer the module name.
Not CSS filter — this emits a finished color.
Partial mute? Use color.scale, not grayscale.
One line:color.grayscale is how modern Sass derives a same-lightness gray token from any brand color.
Compile
Compile Notes
Conceptual flow:
flow.txt
1. @use "sass:color"
2. Resolve $color
3. Legacy → HSL saturation 0% | Modern → Oklch chroma 0%
4. Keep lightness (and space)
5. Emit a finished gray CSS color — no grayscale() left
Frequently Asked Questions
color.grayscale($color) returns a gray color with the same lightness as $color. Example: color.grayscale(#6b717f) is #757575.
Add @use "sass:color"; then call color.grayscale($brand). Prefer the module form in new SCSS. The global alias is grayscale().
Official docs: for legacy colors it sets HSL saturation to 0%. For non-legacy colors it sets Oklch chroma to 0%.
No. Sass color.grayscale() compiles to a finished gray color (hex/rgb). CSS filter: grayscale() is a runtime visual effect on an element or image.
color.adjust($c, $saturation: -100%) can also mute legacy colors, but color.grayscale() is the dedicated helper and also covers modern spaces by zeroing Oklch chroma.
The module form needs Dart Sass with @use (about 1.23+). LibSass/Ruby Sass may expose a global grayscale() but lack the modern module API.