Search code examples
htmlcsscolorsconditional-formatting

Is there a way to interpolate the colour of an element using css, based on a value?


Is there a way, using only CSS, to change the background colour of cells based on the value in them?

To illustrate this, I'm trying to replicate the effect of Excel conditionally formated values:

Excel conditional formated values

If possible, it would be great to be able to interpolate between 2 or 3 colours.


Solution

  • Absolutely!

    As long as you're okay with using CSS variables, it is more than possible to have 2 or 3 colour gradients.

    You can use CSS color-mix and CSS variables to achieve a color mix based on a variable value.

    Use the following CSS:

    .highlight-color {
      --min: 0;
      --max: 1;
      --incs: oklch;
      --value: 0.5;
      --high-color: #F8696B;
      --middle-color: #FFEB84;
      --low-color: #63BE7B;
    }
    
    .highlight-color .highlightme {
      /* This is where the magic happens */
      --normed: calc(100% * (var(--value) - var(--min))/(var(--max) - var(--min)));
    }
    
    .highlight-color.highlight-2color .highlightme {
      background-color: color-mix(
        in var(--incs),
        var(--high-color) var(--normed),
        var(--low-color)
      );
    }
    
    .highlight-color.highlight-3color .highlightme {
      --n1: calc((var(--normed) - 50%) * 2);
      --n2: calc(var(--normed)*2);
      background-color: color-mix(
        in var(--incs),
        color-mix(in var(--incs), var(--high-color) var(--n1), var(--middle-color)) var(--normed),
        color-mix(in var(--incs), var(--middle-color) var(--n2), var(--low-color))
      );
    }
    

    and then the following HTML:

    <table>
        <tbody>
            <tr class="highlight-color highlight-3color" style="--min: 0; --max: 1;">
                <td class="highlightme" style="--value: 0.00;">0.00</td>
                <td class="highlightme" style="--value: 0.07;">0.07</td>
                <td class="highlightme" style="--value: 0.14;">0.14</td>
                <td class="highlightme" style="--value: 0.21;">0.21</td>
                <td class="highlightme" style="--value: 0.29;">0.29</td>
                <td class="highlightme" style="--value: 0.36;">0.36</td>
                <td class="highlightme" style="--value: 0.43;">0.43</td>
                <td class="highlightme" style="--value: 0.50;">0.50</td>
                <td class="highlightme" style="--value: 0.57;">0.57</td>
                <td class="highlightme" style="--value: 0.64;">0.64</td>
                <td class="highlightme" style="--value: 0.71;">0.71</td>
                <td class="highlightme" style="--value: 0.79;">0.79</td>
                <td class="highlightme" style="--value: 0.86;">0.86</td>
                <td class="highlightme" style="--value: 0.93;">0.93</td>
                <td class="highlightme" style="--value: 1.00;">1.00</td>
            </tr>
        </tbody>
    </table>
    

    And you should get the following:

    Table cells highlighted based on value using only CSS like excel's conditional formatting

    You can also use the following Javascript to automatically set the CSS values:

    document.querySelectorAll('.autohighlight').forEach(el => {
        const values = [];
        const els = el.querySelectorAll('.highlightme');
        els.forEach(vel => {
            values.push(vel.innerText / 1);
            vel.style.setProperty('--value', vel.innerText / 1);
        });
        const max = Math.max(...values);
        const min = Math.min(...values);
        el.style.setProperty('--min', min);
        el.style.setProperty('--max', max);
    });
    

    You can find an example codepen demonstrating this here