How to Use calc() to switch between color values?
Asked Answered
A

2

12

Is it possible to use calc() function in CSS to manipulate hexadecimal color value?

In following CSS snippet I would like to use --enable variable to switch between two hexadecimal color values for background-color property of the MyBtnStyle: --enable-color and --disable-color.

It was possible to accomplish this when using rgb(r,g,b) color format where each color component was computed using calc(), but I would prefer to directly switch between hexadecimal color values.

    :root {
        --enable: 0;
        --disable-color: #ff0000;
        --disable-r: 255;
        --disable-g: 0;
        --disable-b: 0;
        --enable-color: #00ff00;
        --enable-r: 0;
        --enable-g: 255;
        --enable-b: 0;
    }

    .MyBtnStyle {
        width: 100%;
        height: 100%;
        text-align: center;
        border: 2px;
        margin: 1px 1px;
        color: black;
        padding: 1px 1px;
        background-color: calc(var(--enable-color)*var(--enable) + var(--disable-color)*(1 - var(--enable))); 
    }

/* this works */
    /* rgb( calc(var(--enable-r)*var(--enable) + var(--disable-r)*(1 - var(--enable)) ), 
            calc(var(--enable-g)*var(--enable) + var(--disable-g)*(1 - var(--enable)) ), 
            calc(var(--enable-b)*var(--enable) + var(--disable-b)*(1 - var(--enable)) )) */
Atheroma answered 27/6, 2018 at 13:5 Comment(0)
M
23

You cannot multiply hex values like You are doing. A trick is to use gradient and control the percentage of colors. This will work with any color format:

:root {
  --enable: 0;
  --disable-color: red;
  --enable-color: #00ff00;
}

.MyBtnStyle {
  text-align: center;
  margin: 5px;
  color: black;
  padding:20px;
  background:
   linear-gradient(
     var(--enable-color)  calc(100% * var(--enable)),
     var(--disable-color) 0
   );
     
 }
<div class="MyBtnStyle" style="--enable:1">some text</div>

<div class="MyBtnStyle">some text</div>

Here is another syntax where you adjust the background-size:

:root {
  --enable: 0;
  --disable-color: red;
  --enable-color: #00ff00;
}

.MyBtnStyle {
  text-align: center;
  margin: 5px;
  color: black;
  padding:20px;
  background:
   linear-gradient(var(--enable-color) 0 0),
   var(--disable-color);
  background-size:100% calc(100% * var(--enable))
}
<div class="MyBtnStyle" style="--enable:1">some text</div>

<div class="MyBtnStyle">some text</div>

Here is another idea inspired from this answer where you can apply color to text or any other property and not only background. This trick works with hsl() coloration.

:root {
  --enable: 0;
  --disable-color: red;
  --enable-color: #00ff00;
}

.MyBtnStyle {
  text-align: center;
  margin: 5px;
  color: hsl(0,100%, calc((1 - var(--enable))*100%));
  border:3px solid hsl(120,100%, calc((1 - var(--enable))*50%));
  padding:20px;
  background:
   linear-gradient(var(--enable-color),var(--enable-color)),
   var(--disable-color);
  background-size:100% calc(100% * var(--enable))
}
<div class="MyBtnStyle" style="--enable:1">some text</div>

<div class="MyBtnStyle">some text</div>

This can be useful in order to have full control on the contrast. We change the background color and the text color at the same time. It's easy between black and white colors (or two version of the same colors) since we have to only control the lightness.

To express any combination of two colors simply rely on the code in the question where we define rgb() colors


Another related question to get more tricks: How to change the color of <div> Element depending on its height or width?

Micrometry answered 27/6, 2018 at 13:16 Comment(1)
Oh that's so interesting! Yet another hack in my toolbox, and I'm glad I'm just a hobbyist so I don't have to worry too much about support and consistency when I'm the only party involved ^^Shakiashaking
M
4

color-mix can be used to toggle between two colors.

In the below code, the --toggle variable is used to set --color1 as the (default) background color, when --toggle is unset or is 0, and if --toggle is set to 1 then --color2 is used.

This works because color-mix is mixing the 2 colors, but at any given time, only one of them is being mixed at 100% and is the dominant one.

(This method can work on with even more colors if the math is tinkered with a little bit)

label {
  --color1: lightGreen;
  --color2: salmon;
  
  background: color-mix(in srgb, 
    var(--color1) calc(var(--toggle, 0) * 100%), 
    var(--color2) calc(100% - var(--toggle, 0) * 100%)
  );
  
  position: fixed;
  inset: 0;
  cursor: pointer;
}

label:has(:checked) {
  --toggle: 1;
}
<label><input type=checkbox hidden/></label>
Moyers answered 10/7, 2023 at 13:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.