SASS 检测颜色暗度以确定样式

Posted

技术标签:

【中文标题】SASS 检测颜色暗度以确定样式【英文标题】:SASS detect colour darkness to determine styles 【发布时间】:2022-01-21 10:34:43 【问题描述】:

我正在尝试制作一个可以检测是否显示深色文本(如果传递给 buttonStyles 的颜色是浅色的)或浅色文本(用于传递深色)的 mixin。我记得有一种方法可以用 LESS 来做,我想知道是否有 SASS 方法。

考虑这个 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);

还有这个html

<button class='btnSecondary'>secondary</button>
<button class='btnPrimary'>primary</button>

辅助按钮比主按钮更易读。我知道我可以传入第二个参数来设置文本颜色,但想知道是否有与 LESS 一样更清洁、更自动的方式? (不幸的是,我不记得它是如何使用 LESS 完成的)

现场演示:https://jsfiddle.net/3v0ckeq9/5/

谢谢

编辑:

我已经添加了这个似乎几乎可以工作的功能:

@function ligthOrDark($color) 
    $result: red;

    @if (blackness($color) == 50)  // fails with > 50 or < 50
        $result: green;
    

    @return $result;

但问题是 SASS 在尝试确定颜色是否大于 50(或小于)时会抱怨,但可以使用 ==。我只想能够确定提供的颜色是深色还是浅色,以便应用正确的文本颜色。

看来这里应该有判断明暗的选项:https://sass-lang.com/documentation/modules/color#grayscale

欢迎使用替代解决方案。

【问题讨论】:

【参考方案1】:

根据documentation、whitenessblackness 与HWB color model 相关。如果您可以使用 HSL 模型,则可以使用 lightness,如下所示:

$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);


编译后如下: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>

我不明白为什么 HWB whitenessblackness 无法与 HSL lightness 这样的数字相提并论。但有可能不用这些函数也能搞定,因为公式很简单: 您可以使用red($color) 和min max 函数。


仅使用whitnessblacknesslightness 不足以处理某些颜色。我认为您正在寻找的是relative luminance 以获得最具对比的颜色。白色的亮度为 1,黑色的亮度为 0。灰底黑对比度大于灰底白。探索更多,了解this website 是如何计算对比度的。


可选参数您可以通过定义参数的默认值来生成arguments optional。在我们的例子中,任何非颜色值都可以:

@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);*/

【讨论】:

谢谢 - 看起来这可能是最接近的选项。但是是否可以使用 SASS 函数传入可选参数?我希望能够传入一个可选的文本变量,因为黄色按钮有点偏离,就像我刚刚制作的这个演示一样:jsfiddle.net/xytuj739 - 这可能吗?第 17 行似乎打破了它 是的,由于缺少参数,它在第 27 行 color: contrastText($color) 失败。您可以将参数设为可选。查看更新后的答案。 太好了,谢谢!

以上是关于SASS 检测颜色暗度以确定样式的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 SASS 动态切换颜色主题?

如何在 Bootstrap 4 和 Sass 中设置自定义按钮文本颜色?

Sass Mixin 使用 SVG 作为背景并改变颜色

less以及sass两者啥区别

Sass 颜色函数

如何在 IE 中检测/定位“忽略网页上指定的颜色”设置?