Use CSS to dynamically calculate the forground color based on the inherited background color
Asked Answered
D

4

8

We are changing the look and feel of our website. The colors of many elements are changing. Our secondary button is changing from a purple background with white text:

To a red border surrounding an inherited background:

We use this button in hundreds of locations on many pages. It resides in sections with various background colors (and a few background images).

With the old button treatment, I didn't have to worry about the background color when determining the text color. The text color was always white:

.secondary-button {
    color: white;
}

Now the font color is going to have to change based on the background. It either needs to be white or purple depending on how dark the background is. The white just doesn't work on light colored backgrounds:

Because this button is used in so many places, I don't want to have to manually go through all of them and choose on a per button basis. Is there a way in CSS to choose one of two background colors based on the darkness of the background? Something like:

.secondary-button {
    color: calc(background-color>#999?purple:white);
}

I found ways to accomplish this with JavaScript: Change text color based on brightness of the covered background area? and also language agnostic algorithms to calculate how dark a color is: Determine font color based on background color but I was unable to locate a pure CSS solution.

Drama answered 9/8, 2016 at 9:25 Comment(9)
I am not sure if there is a CSS solution and if there is then it will only really work on modern browsers. Like only chrome just now or only firefox. It depends how big a need there is for that function for other browsers to pick it up alsoLysander
What you can have is: .secondary-button {color: white; } and .lightBG .secondary-button {color: black;} you are using the parent which has a lighter background to change the text colour of the buttonLysander
Unfortunately, I don't have any common class for the background color of the parent element. Many of them use custom background colors. Your suggestion would require me to go through and find every instance where the button is used and set a class on the parent element.Drama
If the background can be an image of unknown colours, there is no CSS solution. You will need to use JavaScript, and a robust solution has moderate complexity (canvas).Cuccuckold
A solution based on the background image would be ideal, but there are only a handful of places on the site where that would be the case. 98% of the time, the button is on a solid background color. I'd be happy with a solution that only works based on a solid background color.Drama
you could always apply a RGBA background colour : w3schools.com/cssref/tryit.asp?filename=trycss_color_rgba - you still see behind but you can tweak the colour so you can see the button on every surface. so you could have: background-color:rgba(0,0,0,0.3);Lysander
I'll have to run that by the designer, but that is a good enough solution that I'd upvote it as an answer.Drama
I too would go for the RGBA background, if it can be made to look acceptable. It's still not possible with CSS even if it's just a background colour. The best you can do is to manually add a light-background class to each button that is known to be placed on a light background, (which was already suggested).Cuccuckold
I have added it in as an answerLysander
D
5

It's an alternative approach, but you could use a dark (albeit translucent to some degree) text-shadow which would highlight the button's text on lighter backgrounds and be more or less imperceptible on darker backgrounds.

Eg. text-shadow: 1px 1px rgba(0,0,0,0.5), -1px 1px rgba(0,0,0,0.5), 1px -1px rgba(0,0,0,0.5), -1px -1px rgba(0,0,0,0.5);

Example:

div {
display: inline-block;
width: 280px;
height: 50px;
padding: 45px 5px;
}

div:nth-of-type(1) {
background-color: rgb(70,41,126);
}

div:nth-of-type(2) {
background-color: rgb(235,240,244);
}

.secondary-button {
width: 280px;
height: 50px;
color: white;
font-size: 18px;
font-weight: bold;
text-transform: uppercase;
text-shadow: 1px 1px rgba(0,0,0,0.5), -1px 1px rgba(0,0,0,0.5), 1px -1px rgba(0,0,0,0.5), -1px -1px rgba(0,0,0,0.5);
background-color: transparent;
border: 4px solid rgb(245,69,86);
border-radius: 15px 15px 15px 0;
}
<div>
<button type="button" class="secondary-button">Play the Demo</button>
</div>

<div>
<button type="button" class="secondary-button">Play the Demo</button>
</div>
Defeatism answered 9/8, 2016 at 9:53 Comment(2)
I'm impressed that you recreated the button style in CSS from my screenshot so quickly.Drama
Heh. Thank you, @StephenOstermiller. The truth is, my graphic design sense is very limited, so I have to be good at looking at the graphic designs of others and faithfully reproducing them in CSS.Defeatism
B
5

You can use SASS for this!

@function set-notification-text-color($color) {
  @if (lightness($color) > 50) {
    @return #000000; // Lighter backgorund, return dark color
  } @else {
    @return #ffffff; // Darker background, return light color
  }
}

Here we've used the Sass lightness() function to determine which color is more appropriate for a background. The lightness() function is a built-in Sass function that returns the lightness of a color's RGB value between 0 and 100. Where 0 is the darkest and 100 the lightest.

So in our function we receive a color, and if that color's lightness value is greater than 50, meaning it's a light color, we return a dark value to ensure a good contrast. Otherwise we return a light color.

Source: Change background colors with Sass

Bullough answered 9/8, 2016 at 9:32 Comment(1)
SASS is a CSS generator, correct? That is an interesting solution, but I'm not using SASS.Drama
D
5

It's an alternative approach, but you could use a dark (albeit translucent to some degree) text-shadow which would highlight the button's text on lighter backgrounds and be more or less imperceptible on darker backgrounds.

Eg. text-shadow: 1px 1px rgba(0,0,0,0.5), -1px 1px rgba(0,0,0,0.5), 1px -1px rgba(0,0,0,0.5), -1px -1px rgba(0,0,0,0.5);

Example:

div {
display: inline-block;
width: 280px;
height: 50px;
padding: 45px 5px;
}

div:nth-of-type(1) {
background-color: rgb(70,41,126);
}

div:nth-of-type(2) {
background-color: rgb(235,240,244);
}

.secondary-button {
width: 280px;
height: 50px;
color: white;
font-size: 18px;
font-weight: bold;
text-transform: uppercase;
text-shadow: 1px 1px rgba(0,0,0,0.5), -1px 1px rgba(0,0,0,0.5), 1px -1px rgba(0,0,0,0.5), -1px -1px rgba(0,0,0,0.5);
background-color: transparent;
border: 4px solid rgb(245,69,86);
border-radius: 15px 15px 15px 0;
}
<div>
<button type="button" class="secondary-button">Play the Demo</button>
</div>

<div>
<button type="button" class="secondary-button">Play the Demo</button>
</div>
Defeatism answered 9/8, 2016 at 9:53 Comment(2)
I'm impressed that you recreated the button style in CSS from my screenshot so quickly.Drama
Heh. Thank you, @StephenOstermiller. The truth is, my graphic design sense is very limited, so I have to be good at looking at the graphic designs of others and faithfully reproducing them in CSS.Defeatism
L
1

You can have a transparent background colour using RGBA

.secondary-button {
    color: white;
    background-color:rgba(0,0,0,0.3);
}

Here is an example:

.common{
  width:300px;
  height:300px;
  float:left;
  margin:0px 10px 10px 0px;
}
.purple{
  background:purple;
}
.grey{
  background:#ddd;
}
.blue{
  background:blue;
}
.green{
  background:green;
}
.secondary-button {
    color: white;
    background-color:rgba(0,0,0,0.3);
}
.button{
    margin:40px;
    padding:10px 10px;
    border:solid red 3px;
    display: block;
    text-align:center;
}
<div class="common purple">
<a href="#" class="secondary-button button">Button</a>
</div>
<div class="common grey">
<a href="#" class="secondary-button button">Button</a>
</div>
<div class="common blue">
<a href="#" class="secondary-button button">Button</a>
</div>
<div class="common green">
<a href="#" class="secondary-button button">Button</a>
</div>

In the future there will be transparent hex codes. modern browsers are looking to implement an 8 digit hex code with the last 2 digits adjusting the transparency

Lysander answered 9/8, 2016 at 10:10 Comment(1)
I hope it helps. I don't think your designer would mind it too much. As it still shows the background design just a little darker and of course you can change the opacity as you need it. Its hard to get a button that works on every surface, especially if the background changes.Lysander
G
1

You can use a combination of CSS variables and calc to achieve this as per this answer.

Gheber answered 20/8, 2018 at 6:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.