|
@function is-color($color) { |
|
@if (type-of($color) == color) { |
|
@return true; |
|
} |
|
@return false; |
|
} |
|
|
|
@function count-occurrences($string, $search) { |
|
$searchIndex: str-index($string, $search); |
|
$searchCount: 0; |
|
@while $searchIndex { |
|
$searchCount: $searchCount + 1; |
|
$string: str-slice($string, $searchIndex + 1); |
|
$searchIndex: str-index($string, $search); |
|
} |
|
@return $searchCount; |
|
} |
|
|
|
@function str-is-between($string, $first, $last) { |
|
$firstCount: count-occurrences($string, $first); |
|
$lastCount: count-occurrences($string, $last); |
|
@return $firstCount == $lastCount; |
|
} |
|
|
|
@function recursive-color($color, $index: 0) { |
|
$indices: ( |
|
0: h, |
|
1: s, |
|
2: l, |
|
3: a |
|
); |
|
// find end of part |
|
$end: str-index($color, ','); |
|
@while ($end and not str-is-between(str-slice($color, 0, $end - 1), '(', ')')) { |
|
$newEnd: str-index(str-slice($color, $end + 1), ','); |
|
@if (not $newEnd) { |
|
$newEnd: 0; |
|
} |
|
$end: 2 + $end + $newEnd; |
|
} |
|
@if ($end) { |
|
$part: str-slice($color, 0, $end - 1); |
|
$value: map-merge( |
|
( |
|
map-get($indices, $index): $part |
|
), |
|
recursive-color(str-slice($color, $end + 1), $index + 1) |
|
); |
|
@return $value; |
|
} |
|
@return (); |
|
} |
|
|
|
@function to-hsl($color) { |
|
$c: inspect($color); |
|
|
|
$h: 0; |
|
$s: 0; |
|
$l: 0; |
|
$a: 1; |
|
|
|
@if (is-color($color)) { |
|
// std color |
|
$h: hue($color); |
|
$s: saturation($color); |
|
$l: lightness($color); |
|
$a: alpha($color); |
|
|
|
@return (h: $h, s: $s, l: $l, a: $a); |
|
} |
|
|
|
@if (str-slice($c, 0, 3) == 'var') { |
|
// var(--color) |
|
$commaPos: str-index($c, ','); |
|
$end: -2; |
|
@if ($commaPos) { |
|
$end: $commaPos - 1; |
|
} |
|
$var: str-slice($c, 7, $end); |
|
|
|
$h: var(--#{$var}-h); |
|
$s: var(--#{$var}-s); |
|
$l: var(--#{$var}-l); |
|
$a: var(--#{$var}-a, 1); |
|
|
|
@return (h: $h, s: $s, l: $l, a: $a); |
|
} |
|
|
|
@if ($c == '0') { |
|
@return (h: $h, s: $s, l: $l, a: $a); |
|
} |
|
|
|
// color is (maybe complex) calculated color |
|
// e.g.: hsla(calc((var(--white-h) + var(--primary-h)) / 2), calc((var(--white-s) + var(--primary-s)) / 2), calc((var(--white-l) + var(--primary-l)) / 2), calc((var(--white-a, 1) + var(--primary-a, 1)) / 2)), hsla(calc((var(--white-h) + var(--primary-h)) / 2), calc((var(--white-s) + var(--primary-s)) / 2), calc((var(--white-l) + var(--primary-l)) / 2), calc((var(--white-a, 1) + var(--primary-a, 1)) / 2)) |
|
$startPos: str-index($c, '('); |
|
$c: str-slice($c, $startPos + 1, -2); // 3 or 4 comma-separated vomplex values |
|
@return recursive-color($c); |
|
// $hEnd: str-index($c, ','); |
|
// @if ($hEnd) { |
|
// $h: str-slice($c, 0, $hEnd - 1); |
|
// $c: str-slice($c, $hEnd + 1); |
|
// $sEnd: str-index($c, ','); |
|
// @if ($hEnd) { |
|
// $h: str-slice($c, 0, $hEnd - 1); |
|
// $c: str-slice($c, $hEnd + 1); |
|
// $sEnd: str-index($c, ','); |
|
// } |
|
// } |
|
|
|
// @return (h: $h, s: $s, l: $l, a: $a); |
|
} |
|
|
|
@function render-hsla($h, $s, $l, $a: 1) { |
|
@return hsla($h, $s, $l, $a); |
|
} |
|
|
|
@function lighten($color, $amount) { |
|
@if (is-color($color)) { |
|
@return scale-color($color: $color, $lightness: $amount); |
|
} |
|
|
|
$c: to-hsl($color); |
|
$h: map-get($c, h); |
|
$s: map-get($c, s); |
|
$l: map-get($c, l); |
|
$a: map-get($c, a); |
|
@return render-hsla($h, $s, calc(#{$l} + #{$amount}), $a); |
|
} |
|
|
|
@function darken($color, $amount) { |
|
@return lighten($color, $amount * -1); |
|
} |
|
|
|
@function rgba($red, $green, $blue: false, $alpha: false) { |
|
$color: $red; |
|
|
|
@if (not $blue and not $alpha) { |
|
$alpha: $green; |
|
$color: $red; |
|
} |
|
|
|
$c: to-hsl($color); |
|
$h: map-get($c, h); |
|
$s: map-get($c, s); |
|
$l: map-get($c, l); |
|
@return render-hsla($h, $s, $l, $alpha); |
|
} |
|
|
|
@function rgb($red, $green, $blue) { |
|
@return rgba($red, $green, $blue, 1); |
|
} |
|
|
|
@function mix($color-1, $color-2, $weight: 50%) { |
|
$c1: to-hsl($color-1); |
|
$c2: to-hsl($color-2); |
|
|
|
$h1: map-get($c1, h); |
|
$s1: map-get($c1, s); |
|
$l1: map-get($c1, l); |
|
$a1: map-get($c1, a); |
|
|
|
$h2: map-get($c2, h); |
|
$s2: map-get($c2, s); |
|
$l2: map-get($c2, l); |
|
$a2: map-get($c2, a); |
|
|
|
$h: calc((#{$h1} + #{$h2}) / 2); |
|
$s: calc((#{$s1} + #{$s2}) / 2); |
|
$l: calc((#{$l1} + #{$l2}) / 2); |
|
$a: calc((#{$a1} + #{$a2}) / 2); |
|
|
|
@return render-hsla($h, $s, $l, $a); |
|
} |
|
|
|
@function fade-in($color, $amount) { |
|
$c: to-hsl($color); |
|
|
|
$h: map-get($c, h); |
|
$s: map-get($c, s); |
|
$l: map-get($c, l); |
|
$a: map-get($c, a); |
|
@if (not $a) { |
|
$a: 1; |
|
} |
|
|
|
@return render-hsla($h, $s, $l, $a + $amount); |
|
} |
|
|
|
@function color-yiq($color, $dark: $yiq-text-dark, $light: $yiq-text-light) { |
|
@if (is-color($color)) { |
|
$r: red($color); |
|
$g: green($color); |
|
$b: blue($color); |
|
|
|
$yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000; |
|
|
|
@if ($yiq >= $yiq-contrasted-threshold) { |
|
@return $dark; |
|
} @else { |
|
@return $light; |
|
} |
|
} @else { |
|
$c: to-hsl($color); |
|
$l: map-get($c, l); |
|
|
|
$th: $yiq-contrasted-threshold / 2.56; // convert hex to dec |
|
$lightness: calc(-100 * calc(#{$l} - #{$th * 1%})); |
|
|
|
// ignoring hue and saturation, just a light or dark gray |
|
@return render-hsla(0, 0%, $lightness, 1); |
|
} |
|
} |
All colors are converted to HSL to be able to easily change lightness etc on the
--var
s. The code should work for rgba and hsla values, not for named colors. You can check out what the values of the variables are at the error by using the @debug sass function. It is also possible we are encountering an untested or unforeseen use case 😄.