通过CSS动态地按百分比更改颜色为较浅或较暗。

565

我们在网站上有一个大型应用程序,有一些链接是蓝色的,就像这个网站上的蓝色链接一样。现在我想创建一些其他链接,但颜色要更浅。显然,我可以通过在CSS文件中添加十六进制代码来简单地实现,但我们的网站允许用户决定他们想要为自定义配置文件/网站使用什么颜色(就像Twitter一样)。

所以,我的问题是:我们能否按百分比减少颜色?

假设以下代码是CSS:

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

或者

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

有没有一种方法可以按百分比减少颜色?


1
我不太懂CSS,但是减少颜色是什么意思呢?是让它更透明吗?还是想要改变颜色的RGB通道? - StampedeXV
不是透明,而是通过十六进制、RGB或HSL减少颜色。 - Basit
1
如果您不想使用默认颜色,您可以手动选择一种颜色,例如使用此在线工具:https://www.hexcolortool.com。 - simhumileco
https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/brightness - Alex L
28个回答

813
你可以在所有现代浏览器中使用CSS滤镜来实现这一点(请参见caniuse兼容性表)。

.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>

这里有更多关于各种过滤器的阅读材料,来自CSS Tricks: https://css-tricks.com/almanac/properties/f/filter/


101
请注意,brightness() 的亮度级别不仅限于 100%。您也可以将其调得比原来更亮。 - Adam Katz
8
滤镜也会应用于与元素相关联的任何背景图片。例如,如果您使用图标来装饰链接,那么该滤镜也会改变图标的亮度。 - Slion
5
根据 http://caniuse.com/#feat=css-filters,IE11 不支持这个功能。根据 https://www.w3counter.com/globalstats.php?year=2017&month=8,IE11 仍然是前十最常用的浏览器之一。虽然我很想使用这个功能,但在 IE11 占据市场份额之前,似乎不太可能实现。 :-( - OldTimeGuitarGuy
25
我能将它应用于background-color吗?我发现它作用于整个元素。https://jsfiddle.net/6trjmaq3/1/ - ADM-IT
4
使用递归(例如嵌套的DIV)处理具有不确定级数/层次的最佳答案,但它会影响整个元素,而不仅仅是背景色或文本颜色。 - posfan12
显示剩余3条评论

519
所有现代浏览器都已经在2020年1月之后完全支持filter。甚至安卓UC浏览器(而不是Chrome,在80美元的手机上)也支持它。
a {
    /* a nice, modern blue for links */
    color: #118bee;
}
a:active {
    /* Darken on click by 15% (down to 85%) */
    filter: brightness(0.85);
}

此外,您可以通过CSS变量动态控制它,大多数浏览器自2017年10月开始支持(不包括QQ)。
:root {
    --color: #118bee;
    --hover-brightness: 1.2;
}
a {
    color: var(--color);
}
a:active {
    /* Darken on click */
    filter: brightness(var(--hover-brightness));
}

这不是我的项目,但它是一个很好的现实世界示例,展示了现代CSS的强大之处。请查看: MVP.css


原始回答

如果你正在使用支持SassLess的堆栈,你可以使用lighten函数:

$linkcolour: #0000FF;

a {
  color: $linkcolour;
}

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

还有一个darken,它执行相同的操作,但在相反的方向上。


7
当背景颜色是在行内动态设置的时候,如何使其在鼠标悬停时始终变暗? - andilabs
2
这个不错的 NPM 模块允许在 JavaScript 中加深/减淡十六进制颜色 - https://www.npmjs.com/package/shader。 - larrydalmeida
如果您想使用CSS3和SVG数据为任何带有悬停效果的按钮动态应用较浅或较深的阴影,请尝试我的答案https://dev59.com/PXI-5IYBdhLWcg3w483k#55828346。 - Watts Epherson
这个能否实时运行,在运行时传递自定义的CSS属性? - Dzintars
这个能用颜色名称吗?比如说 橙色 - chovy
1
这似乎会过滤整个元素。有没有一种方法可以使用 filter 更改背景颜色,同时保持前景颜色不变? - John Y

126

有一个名为"opacity"的属性,可以使背景透过元素显示出来:

opacity: 0.5;

但是我不确定这是否符合您的意思。请定义“减少颜色”: 是使其透明?还是添加白色?


8
“我猜”?你应该知道的。但无论如何,如果你的背景是白色,你可以通过增加透明度来“伪造”亮度——我最近就用这个方法取得了不错的效果。 - Camilo Martin
3
如果背景是黑色,那么“不透明度”技巧也适用(透明度为0.5会使颜色在黑色背景上变暗)。 - Julien Kronegg
如果这是针对CSS的background:而不是foreground:,就涉及到“lighter”或“brighter”的含义和Google搜索,那么这可能是大多数人正在寻找的答案。此外,无需担心支持问题: https://caniuse.com/#feat=css-opacity - JoePC

105

在撰写本文时,以下是我发现的最佳纯CSS颜色操作实现:

使用CSS变量以HSL而非HEX/RGB格式定义您的颜色,然后使用calc()来操作它们。

这里是一个基本示例:

: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>

我还创建了一个提供基本CSS变量支持的CSS框架(仍处于早期阶段),名为root-variables


2
能否使用CSS颜色名称(例如:orange)使其正常工作? - chovy
1
“--link-color-hsl” 是一个好主意,这可能是最好的解决方案,直到我们有 CSS5 的 “color-mix”,干得好。 - run_the_race

86

HSL颜色为我们提供了一个答案,HSL颜色值由以下方式指定:hsl(色相[0,255],饱和度%,亮度%)。

HSL在IE9+、Firefox、Chrome、Safari以及Opera 10+中得到支持。

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

谢谢,这正是我在寻找的。真是个聪明的解决方案! - undefined

42

使用纯CSS属性filter。要了解filter属性函数的完整描述,请阅读这篇精彩文章

我曾经有一个和你一样的问题,我通过使用filter属性的brightness函数解决了它:

.my-class {
  background-color: #18d176;
  filter: brightness(90%);
}

请参见上文。IE11不喜欢那样做。 - Gwyneth Llewelyn
18
2021年8月17日,IE浏览器停止更新。✌️ - amarinediary
@amarinediary IE本身的生命周期将于2022年6月15日结束。2021年8月17日是IE中M365服务支持的结束时间...这是不同的事情。 - TylerH
3
他们在四月份欺骗了我们!这件事就是无法消失!我们都已经等待这一天很久了!@TylerH - amarinediary
@amarinediary IE11的完整故事是它与嵌入式操作系统的生命周期绑定在一起,因此它只会在2022年6月15日开始逐渐退出。任何在此之后到达EoL的内置IE11的操作系统都意味着IE11也将在该操作系统上得到支持,直到这些EoLs。然而,从Web开发的支持角度来看,您可以有效地认为IE已经到了EoL的状态。如果您需要支持IE,您会知道,因为您的客户会明确要求它,即使如此,您也可以在Edge中使用IE模式来解决问题。 - TylerH

24

这是一个老问题,但大多数答案需要使用预处理器或JavaScript进行操作,或者它们不仅会影响元素的颜色,还会影响其中包含的元素的颜色。我将添加一种使用CSS解决的有点复杂的方法来做同样的事情。也许在未来,随着更先进的CSS功能的出现,做这件事情会更容易。

这个想法基于以下几点:

  • RGB 颜色,因此您具有红色,绿色和蓝色的分离值;
  • CSS 变量,用于存储颜色值和暗度;并且
  • calc 函数,用于应用更改。

默认情况下,暗度为 1(表示 100% 原始颜色),如果您将其乘以介于 0 和 1 之间的数字,则会使颜色变暗。例如,如果您将每个值乘以 0.85,则将使颜色变暗 15%(100%-15%= 85%= 0.85)。

这里是一个例子,我创建了三个类:.dark.darker.darkest,分别使原始颜色变暗了 25%、50% 和 75%:

html {
  --clarity: 1;
}

div {
  display: inline-block;
  height: 100px;
  width: 100px;
  line-height: 100px;
  color: white;
  text-align: center;
  font-family: arial, sans-serif;
  font-size: 20px;
  background: rgba(
                  calc(var(--r) * var(--clarity)), 
                  calc(var(--g) * var(--clarity)), 
                  calc(var(--b) * var(--clarity))
                );
}

.dark    { --clarity: 0.75; }
.darker  { --clarity: 0.50; }
.darkest { --clarity: 0.25; }

.red {
  --r: 255;
  --g: 0;
  --b: 0;
}

.purple {
  --r: 205;
  --g: 30;
  --b: 205;
}
<div class="red">0%</div>
<div class="red dark">25%</div>
<div class="red darker">50%</div>
<div class="red darkest">75%</div>

<br/><br/>

<div class="purple">0%</div>
<div class="purple dark">25%</div>
<div class="purple darker">50%</div>
<div class="purple darkest">75%</div>


20
如果你想要更暗的颜色,可以使用低不透明度的rgba黑色:
rgba(0, 0, 0, 0.3);

如果使用较轻的颜色,请选择白色:

rgba(255, 255, 255, 0.3);

66
这取决于背景,因为它会变得半透明,而不是变亮。 - bryc

20

在 LESS 中,您将使用以下变量:

@primary-color: #999;
@primary-color-lighter: lighten(@primary-color, 20%);

这将使用第一个变量并将其减轻20%(或任何其他百分比)。在此示例中,您将得到较浅的颜色:#ccc


15
如果您只需要更改背景颜色,这是一种未来可靠的方法 - 在背景图片上使用线性渐变方法!请查看下面的示例:
document
  .getElementById('colorpicker')
  .addEventListener('change', function(event) {
    document
      .documentElement
      .style.setProperty('--color', event.target.value);
  });
span {
  display: inline-block;
  border-radius: 20px;
  height: 40px;
  width: 40px;
  vertical-align: middle;
}

.red {
  background-color: red;
}

.red-darker {
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.25),
    rgba(0, 0, 0, 0.25)
  ) red;
}

:root {
  --color: lime;
}

.dynamic-color {
  background-color: var(--color);
}

.dynamic-color-darker {
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.25),
    rgba(0, 0, 0, 0.25)
  ) var(--color);
}
<table>
  <tr>
    <td><strong>Static Color</strong></td>
    <td><span class="red"></span></td>
    <td><span class="red-darker"></span></td>
  </tr>
  <tr>
    <td><strong>Dynamic Color</strong></td>
    <td><span class="dynamic-color"></span></td>
    <td><span class="dynamic-color-darker"></span></td>
  </tr>
</table>
<br/>
Change the dynamic color: <input id="colorpicker" value="#00ff00" type="color"/>

制作人员: https://css-tricks.com/css-custom-properties-theming/


3
这是一个非常巧妙的答案。我曾经看过使用这个的生产代码:background-image: linear-gradient(rgba(0,0,0,0.30), rgba(0,0,0,0.30)); - Stubbs
2
很好,与过滤器答案相反,这不会影响我的边框颜色。 - Aeolun
2
太棒了,谢谢!这也不会影响所有的子元素……这正是我所遇到的问题。 - FlorianB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接