Miroslav Radojević
Miroslav Radojević

Reputation: 517

How to Use calc() to switch between color values?

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

Upvotes: 13

Views: 23848

Answers (2)

vsync
vsync

Reputation: 130750

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>

Upvotes: 5

Temani Afif
Temani Afif

Reputation: 274236

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?

Upvotes: 24

Related Questions