Dynamically change color to lighter or darker by percentage CSS

We have a big application on the site and we have a few links which are, let's say blue color like the blue links on this site. Now I want to make some other links, but with lighter color. Obviously I can just do simply by the hex code adding in the CSS file, but our site lets user decide what colors they want for their customized profile/site (like Twitter).

So, my question is: can we reduce the color by percentage?

Let's say the following code is CSS:

a {
  color: blue;
}

a.lighter {
  color: -50%; // obviously not correct way, but just an idea
}

OR

a.lighter {
  color: blue -50%;  // again not correct, but another example of setting color and then reducing it
}

Is there a way to reduce a color by a percentage?


Solution 1:

You can do this with CSS filters in all modern browsers (see the caniuse compatibility table).

.button {
  color: #ff0000;
}

/* note: 100% is baseline so 85% is slightly darker, 
   20% would be significantly darker */
.button:hover {
  filter: brightness(85%);
}
<button class="button">Foo lorem ipsum</button>

Here's more reading from CSS Tricks about the various filters you can use: https://css-tricks.com/almanac/properties/f/filter/

Solution 2:

All modern browsers have had 100% filter support since January 2020. Even UC Browser for Android (instead of Chrome, on the $80 phones) supports it.

a {
    /* a nice, modern blue for links */
    color: #118bee;
}
a:active {
    /* Darken on click by 15% (down to 85%) */
    filter: brightness(0.85);
}

Additionally, you can control this dynamically with CSS variables, which have been supported by most browsers since October 2017 (excluding QQ):

:root {
    --color: #118bee;
    --hover-brightness: 1.2;
}
a {
    color: var(--color);
}
a:active {
    /* Darken on click */
    filter: brightness(var(--hover-brightness));
}

Not my project, but one that's great to look at for a real-world example of how great modern CSS can be, check out: MVP.css


Original Answer

If you're using a stack which lets you use Sass or Less, you can use the lighten function:

$linkcolour: #0000FF;

a {
  color: $linkcolour;
}

a.lighter {
  color: lighten($linkcolour, 50%);
}

There's also darken which does the same, but in the opposite direction.

Solution 3:

There is "opacity" which will make the background shine through:

opacity: 0.5;

but I'm not sure this is what you mean. Define "reduce color": Make transparent? Or add white?

Solution 4:

HSL Colors provide an answer, a HSL color value is specified with: hsl(hue [0,255], saturation %, lightness %).

HSL is supported in IE9+, Firefox, Chrome, Safari, and in Opera 10+

a
{
color:hsl(240,65%,50%);
}
a.lighter 
{
color:hsl(240,65%,75%);
}

Solution 5:

At the time of writing, here's the best pure CSS implementation for color manipulation I found:

Use CSS variables to define your colors in HSL instead of HEX/RGB format, then use calc() to manipulate them.

Here's a basic example:

:root {
  --link-color-h: 211;
  --link-color-s: 100%;
  --link-color-l: 50%;
  --link-color-hsl: var(--link-color-h), var(--link-color-s), var(--link-color-l);

  --link-color: hsl(var(--link-color-hsl));
  --link-color-10: hsla(var(--link-color-hsl), .1);
  --link-color-20: hsla(var(--link-color-hsl), .2);
  --link-color-30: hsla(var(--link-color-hsl), .3);
  --link-color-40: hsla(var(--link-color-hsl), .4);
  --link-color-50: hsla(var(--link-color-hsl), .5);
  --link-color-60: hsla(var(--link-color-hsl), .6);
  --link-color-70: hsla(var(--link-color-hsl), .7);
  --link-color-80: hsla(var(--link-color-hsl), .8);
  --link-color-90: hsla(var(--link-color-hsl), .9);

  --link-color-warm: hsl(calc(var(--link-color-h) + 80), var(--link-color-s), var(--link-color-l));
  --link-color-cold: hsl(calc(var(--link-color-h) - 80), var(--link-color-s), var(--link-color-l));

  --link-color-low: hsl(var(--link-color-h), calc(var(--link-color-s) / 2), var(--link-color-l));
  --link-color-lowest: hsl(var(--link-color-h), calc(var(--link-color-s) / 4), var(--link-color-l));

  --link-color-light: hsl(var(--link-color-h), var(--link-color-s), calc(var(--link-color-l) / .9));
  --link-color-dark: hsl(var(--link-color-h), var(--link-color-s), calc(var(--link-color-l) * .9));
}

.flex {
  display: flex;
}

.flex > div {
  flex: 1;
  height: calc(100vw / 10);
}
<h3>Color Manipulation (alpha)</h3>

<div class="flex">
  <div style="background-color: var(--link-color-10)"></div>
  <div style="background-color: var(--link-color-20)"></div>
  <div style="background-color: var(--link-color-30)"></div>
  <div style="background-color: var(--link-color-40)"></div>
  <div style="background-color: var(--link-color-50)"></div>
  <div style="background-color: var(--link-color-60)"></div>
  <div style="background-color: var(--link-color-70)"></div>
  <div style="background-color: var(--link-color-80)"></div>
  <div style="background-color: var(--link-color-90)"></div>
  <div style="background-color: var(--link-color)"></div>
</div>

<h3>Color Manipulation (Hue)</h3>

<div class="flex">
  <div style="background-color: var(--link-color-warm)"></div>
  <div style="background-color: var(--link-color)"></div>
  <div style="background-color: var(--link-color-cold)"></div>
</div>

<h3>Color Manipulation (Saturation)</h3>

<div class="flex">
  <div style="background-color: var(--link-color)"></div>
  <div style="background-color: var(--link-color-low)"></div>
  <div style="background-color: var(--link-color-lowest)"></div>
</div>

<h3>Color Manipulation (Lightness)</h3>

<div class="flex">
  <div style="background-color: var(--link-color-light)"></div>
  <div style="background-color: var(--link-color)"></div>
  <div style="background-color: var(--link-color-dark)"></div>
</div>

I also created a CSS framework (still in early stage) to provide basic CSS variables support called root-variables.