I'm trying to make a mixin that can detect whether to show dark text (if the colour passed into buttonStyles is light), or light text (for passing darker colours). I remember there was a way to do it with LESS and wondered whether there's a SASS way.
Consider this SCSS:
$white: #fff;
$text: #393939;
$font-std: 18px;
$transition-std: 0.4s ease all;
$primary: #f8e421;
$secondary: #354052;
@mixin buttonStyles($color) {
font-size: $font-std;
color: $text;
padding: 1rem 3rem;
background-color: $color;
color: $white;
transition: $transition-std;
&:hover {
cursor: pointer;
background-color: lighten($color, 15%);
}
&:focus {
background-color: lighten($color, 10%);
}
&:active {
background-color: lighten($color, 25%);
}
}
.btnPrimary {
@include buttonStyles($primary);
}
.btnSecondary {
@include buttonStyles($secondary);
}
And this html:
<button class='btnSecondary'>secondary</button>
<button class='btnPrimary'>primary</button>
The secondary button is far more legible than the primary button. I know that I could pass in a second argument that would set the text colour, but wondered whether there's a cleaner, automatic way as with LESS? (unfortunately I can't remember how it was done with LESS)
Live demo: https://jsfiddle.net/3v0ckeq9/5/
Thank you
EDIT:
I've added this function which almost seems to work:
@function ligthOrDark($color) {
$result: red;
@if (blackness($color) == 50) { // fails with > 50 or < 50
$result: green;
}
@return $result;
}
But the issue is that SASS complains when trying to determine wether the colour is greater than 50 (or less than) but is ok with ==. I just want to be able to determine whether the color provided is dark or light so I can apply the right color of text.
Seems that there should be options to determine the darkness or lightness here: https://sass-lang.com/documentation/modules/color#grayscale
Alternative solutions are welcomed.
As per the documentation, whiteness and blackness are related to HWB color model. If you can work with HSL model then lightness can be used as follows:
$white: #fff;
$text: #393939;
$font-std: 18px;
$transition-std: 0.4s ease all;
$primary: #f8e421;
$secondary: #354052;
@function contrastText($color) {
$result: invert($color);
$lightness: lightness($result);
@if ($lightness < 50) {
$result: black;
}
@return $result;
}
@mixin buttonStyles($color) {
font-size: $font-std;
padding: 1rem 3rem;
background-color: $color;
color: contrastText($color);
transition: $transition-std;
&:hover {
cursor: pointer;
background-color: lighten($color, 15%);
}
&:focus {
background-color: lighten($color, 10%);
}
&:active {
background-color: lighten($color, 25%);
}
}
.btnPrimary {
@include buttonStyles($primary);
}
.btnSecondary {
@include buttonStyles($secondary);
}
.btnTest {
@include buttonStyles(#888);
}
After compilation it'll look like this: jsfiddle
/* CSS compiled from SASS*/
.btnPrimary {
font-size: 18px;
padding: 1rem 3rem;
background-color: #f8e421;
color: black;
transition: 0.4s ease all;
}
.btnPrimary:hover {
cursor: pointer;
background-color: #faed6b;
}
.btnPrimary:focus {
background-color: #faea52;
}
.btnPrimary:active {
background-color: #fcf39d;
}
.btnSecondary {
font-size: 18px;
padding: 1rem 3rem;
background-color: #354052;
color: #cabfad;
transition: 0.4s ease all;
}
.btnSecondary:hover {
cursor: pointer;
background-color: #536480;
}
.btnSecondary:focus {
background-color: #495871;
}
.btnSecondary:active {
background-color: #697d9e;
}
.btnTest {
font-size: 18px;
padding: 1rem 3rem;
background-color: #888;
color: black;
transition: 0.4s ease all;
}
.btnTest:hover {
cursor: pointer;
background-color: #aeaeae;
}
.btnTest:focus {
background-color: #a2a2a2;
}
.btnTest:active {
background-color: #c8c8c8;
}
.testRed {
font-size: 18px;
padding: 1rem 3rem;
background-color: red;
color: cyan;
transition: 0.4s ease all;
}
.testRed:hover {
cursor: pointer;
background-color: #ff4d4d;
}
.testRed:focus {
background-color: #ff3333;
}
.testRed:active {
background-color: #ff8080;
}
.testGreen {
font-size: 18px;
padding: 1rem 3rem;
background-color: green;
color: #ff7fff;
transition: 0.4s ease all;
}
.testGreen:hover {
cursor: pointer;
background-color: #00cc00;
}
.testGreen:focus {
background-color: #00b300;
}
.testGreen:active {
background-color: lime;
}
.testBlue {
font-size: 18px;
padding: 1rem 3rem;
background-color: blue;
color: yellow;
transition: 0.4s ease all;
}
.testBlue:hover {
cursor: pointer;
background-color: #4d4dff;
}
.testBlue:focus {
background-color: #3333ff;
}
.testBlue:active {
background-color: #8080ff;
}
.testOrange {
font-size: 18px;
padding: 1rem 3rem;
background-color: orange;
color: #005aff;
transition: 0.4s ease all;
}
.testOrange:hover {
cursor: pointer;
background-color: #ffc04d;
}
.testOrange:focus {
background-color: #ffb733;
}
.testOrange:active {
background-color: #ffd280;
}
.testPurple {
font-size: 18px;
padding: 1rem 3rem;
background-color: purple;
color: #7fff7f;
transition: 0.4s ease all;
}
.testPurple:hover {
cursor: pointer;
background-color: #cc00cc;
}
.testPurple:focus {
background-color: #b300b3;
}
.testPurple:active {
background-color: magenta;
}
.testYellow {
font-size: 18px;
padding: 1rem 3rem;
background-color: yellow;
color: blue;
transition: 0.4s ease all;
}
.testYellow:hover {
cursor: pointer;
background-color: #ffff4d;
}
.testYellow:focus {
background-color: #ffff33;
}
.testYellow:active {
background-color: #ffff80;
}
<button class='btnSecondary'>secondary</button>
<button class='btnPrimary'>primary</button>
<button class='btnTest'>test</button>
<hr>
<button class='testRed'>Red</button>
<button class='testGreen'>Green</button>
<button class='testBlue'>Blue</button>
<button class='testOrange'>Orange</button>
<button class='testPurple'>Purple</button>
<button class='testYellow'>Yellow</button>
I couldn't figure out why HWB whiteness and blackness are not comparable with numbers like HSL lightness. But it may be possible that you can get them without these functions, because the formula is simple:
You can use red($color) and min max functions.
Using whitness, blackness, and lightness alone won't be sufficient with some colors. I think what you are looking for is relative luminance to get most contrasting color. White has luminance 1 and black has 0. And black-on-gray contrast is more than white-on-gray. To explore more figure out how this website is calculating contrast.
Optional arguments You can make arguments optional by defining default value for the parameter. In our case any non color value will do:
@function contrastText($color, $text:-1) {
$result: invert($color);
$lightness: lightness($result);
@if ($lightness < 47) {
$result: black;
}
@if ($lightness > 46) {
$result: white;
}
@if (type_of($text) == 'color') {
$result: $text;
}
@return $result;
}
@mixin buttonStyles($color) {
color: contrastText($color);
/*color: contrastText($color,);*/
/*color: contrastText($color, red);*/
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With