Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Color combinations that fail WCAG 2 AA 4.5:1 contrast ratio #25126

Closed
patrickhlauke opened this issue Dec 29, 2017 · 20 comments
Closed

Color combinations that fail WCAG 2 AA 4.5:1 contrast ratio #25126

patrickhlauke opened this issue Dec 29, 2017 · 20 comments

Comments

@patrickhlauke
Copy link
Member

Doubt that all of these will be tackled, but for reference (following #25123 which at least fixed one of the badly borked ones):

From http://getbootstrap.com/docs/4.0/getting-started/theming/

Blue
Foreground: #FFFFFF
Background: #007BFF
The contrast ratio is: 4.0:1
Text failed at Level AA

Indigo
Foreground: #FFFFFF
Background: #6610F2
The contrast ratio is: 7.2:1
Text passed at Level AA

Purple
Foreground: #FFFFFF
Background: #6F42C1
The contrast ratio is: 6.5:1
Text passed at Level AA

Pink
Foreground: #FFFFFF
Background: #E83E8C
The contrast ratio is: 3.8:1
Text failed at Level AA

Red
Foreground: #FFFFFF
Background: #DC3545
The contrast ratio is: 4.5:1
Text passed at Level AA

Orange
Foreground: #212529
Background: #FD7E14
The contrast ratio is: 6.0:1
Text passed at Level AA

Yellow
Foreground: #212529
Background: #FFC107
The contrast ratio is: 9.5:1
Text passed at Level AA

Green
Foreground: #FFFFFF
Background: #28A745
The contrast ratio is: 3.1:1
Text failed at Level AA

Teal
Foreground: #FFFFFF
Background: #20C997
The contrast ratio is: 2.1:1
Text failed at Level AA

Cyan
Foreground: #FFFFFF
Background: #17A2B8
The contrast ratio is: 3.0:1
Text failed at Level AA

From http://getbootstrap.com/docs/4.0/utilities/colors/

.text-primary
Foreground: #007BFF
Background: #FFFFFF
The contrast ratio is: 4.0:1
Text failed at Level AA

.text-secondary
Foreground: #6C757D
Background: #FFFFFF
The contrast ratio is: 4.7:1
Text passed at Level AA

.text-success
Foreground: #28A745
Background: #FFFFFF
The contrast ratio is: 3.1:1
Text failed at Level AA

.text-danger
Foreground: #DC3545
Background: #FFFFFF
The contrast ratio is: 4.5:1
Text passed at Level AA

.text-warning
Foreground: #FFC107
Background: #FFFFFF
The contrast ratio is: 1.6:1
Text failed at Level AA

.text-info
Foreground: #17A2B8
Background: #FFFFFF
The contrast ratio is: 3.0:1
Text failed at Level AA

.text-light
Foreground: #F8F9FA
Background: #343A40
The contrast ratio is: 10.9:1
Text passed at Level AA

.text-dark
Foreground: #343A40
Background: #FFFFFF
The contrast ratio is: 11.5:1
Text passed at Level AA

.text-muted
Foreground: #6C757D
Background: #FFFFFF
The contrast ratio is: 4.7:1
Text passed at Level AA

.text-white
Foreground: #FFFFFF
Background: #343A40
The contrast ratio is: 11.5:1
Text passed at Level AA

.bg-primary
Foreground: #FFFFFF
Background: #007BFF
The contrast ratio is: 4.0:1
Text failed at Level AA

.bg-secondary
Foreground: #FFFFFF
Background: #6C757D
The contrast ratio is: 4.7:1
Text passed at Level AA

.bg-success
Foreground: #FFFFFF
Background: #28A745
The contrast ratio is: 3.1:1
Text failed at Level AA

.bg-danger
Foreground: #FFFFFF
Background: #DC3545
The contrast ratio is: 4.5:1
Text passed at Level AA

.bg-warning
Foreground: #343A40
Background: #FFC107
The contrast ratio is: 7.1:1
Text passed at Level AA

.bg-info
Foreground: #FFFFFF
Background: #17A2B8
The contrast ratio is: 3.0:1
Text failed at Level AA

.bg-dark
Foreground: #FFFFFF
Background: #343A40
The contrast ratio is: 11.5:1
Text passed at Level AA

.bg-white
Foreground: #343A40
Background: #FFFFFF
The contrast ratio is: 11.5:1
Text passed at Level AA

@mdo
Copy link
Member

mdo commented Dec 29, 2017

Are you using a Chrome extension for this?

@patrickhlauke
Copy link
Member Author

https://developer.paciellogroup.com/resources/contrastanalyser/ on windows (note: when using color picker, rather than entering hex values directly, CCA - at least on Win - doesn't account for color management / profiles, meaning that picking from Chrome gets false results)

@patrickhlauke
Copy link
Member Author

(and yes, i did collate that list manually, as i know how to party on a friday night ;) )

@knoobie
Copy link

knoobie commented Dec 31, 2017

@patrickhlauke I would recommend you http://khan.github.io/tota11y/ - it's super easy to use and really efficient for finding contrast problems.

@AlessandroVecchi
Copy link

I suggest:
Blue #0069D9
Pink #C53577
Green #1E7D34
Teal #148060
Cyan #117A8A

@michaelwayneharris87
Copy link

In our extension of Bootstrap, we've added functions to lighten or darken colors until they meet minimum contrast, and updated the mixins to use those functions.

I'd love to see an option for $enable-force-accessible-contrast that would automatically generate accessible versions of components if set to true, regardless of what color was passed into the relevant mixins.

If that's of interest, I'll share some of our code.

@XhmikosR
Copy link
Member

@michaelwayneharris87: I'm definitely interested. BTW we were recently discussing how to proceed with this because it's clearly an issue.

My main concern is that we can't know of all the combinations the users might use, so we need to make the assumption that everything will have a white background color.

@michaelwayneharris87
Copy link

michaelwayneharris87 commented Mar 21, 2019

I'm pressed for time at the moment, but I'll try to write something longer this weekend.

This function is doing a lot of the work for us:

/**
 * Incrementally darkens or lightens a color to  meet color contrast requirements
 */
@function find-contrasting-color($color, $base: $body-bg, $minimum-contrast-ratio: 7) {
  $output-color: $color;
  $color-mix: choose-contrast-color($base); // returns white or black
  $contrast-ratio: contrast($output-color, $base); // custom function to calculate contrast ratio

  @while $contrast-ratio < $minimum-contrast-ratio {
    $output-color: mix($color-mix, $output-color, 1%);
    $contrast-ratio: contrast($output-color, $base);
  }

  @return $output-color;
}

We've written our own alert mixin like so:

@mixin custom-alert-variant($color) {
  $bg-color: color-level($color, $alert-bg-level);
  $txt-color: find-contrasting-color($color, $bg-color, 4.5);
  $border-color: find-contrasting-color($color, $bg-color, 3);

  @include gradient-bg($bg-color);
  color: $txt-color;
  border-color: $border-color;

  hr {
    border-top-color: $border-color;
  }

  .alert-link {
    color: $txt-color;
  }
}

This should force all of the alert variants to be accessible no matter what color is picked in the theme. Out of the box, the .alert-light styles don't have enough contrast. Here's the output for the out of the box theme value for .alert-light using our mixin instead:

.alert-light {
  background-color: #fefefe;
  color: #757576;
  border-color: #949495; }
  .alert-light hr {
    border-top-color: #949495; }
  .alert-light .alert-link {
    color: #757576; }

We're expecting to have a lot of our developers throwing God knows what colors into the theme, so this the basic approach for how we're trying to protect them from themselves.

@michaelwayneharris87
Copy link

michaelwayneharris87 commented Mar 21, 2019

You could imagine something really elaborate like looping through every permutation of .bg-#{$color} .text-#{$color} and calculating an accessible version. We're wrestling with whether it's actually worth the trouble to do that; I have a gut reaction to worry that that kind of thing might be too much.

It's probably more feasible to filter to pass some basic rules through some kind of accessibility function like this:

body {
color: find-contrasting-color($body-color, $body-bg, 4.5) // we don't trust your ability to pick variables at all whatsoever, not even for your default font color
}

As I suggested above, it's really easy to go overboard with this approach, and we're kind of overwhelmed at the opportunities to apply it. But applying it in a few places may provide the framework with some value.

@XhmikosR
Copy link
Member

I think for the time being I'll do this manually. I just need to automate the checks somehow, and perhaps have all components in one page for testing this if needed manually.

But I think I'll just set up some tool for this. Any suggestions welcome. And if the changes are not huge, we can probably backport it to v4.

@michaelwayneharris87
Copy link

I'd love to help in any way I can — this has been a big sticking point for us, so if you would find any of the work we've done to be helpful, we'd be happy to share it back.

@XhmikosR
Copy link
Member

I added this in my short-term TODO for v5, so hopefully I'll start a PR by next week. I'm gonna ping you there, thanks.

@evilaliv3
Copy link

Is there any small css for fixing bootstrap4 in relation to do this?

@michaelwayneharris87: is you code public? we would love to use it within the GlobaLeaks for better usability of the app and be able to reach any possible whistleblower!

@XhmikosR
Copy link
Member

You can backport the related v5 patch which is only for blue and pink though. I don't think the other colors will change because the difference is pretty huge.

@michaelwayneharris87
Copy link

@evilaliv I based my code on https://medium.com/dev-channel/using-sass-to-automatically-pick-text-colors-4ba7645d2796, so it should be easy to adapt from there.

I've also recently been experimenting with https://github.com/hsluv/hsluv-sass, which seems like a more sophisticated way of doing things (though I haven't implemented it)

@xi
Copy link
Contributor

xi commented Feb 26, 2020

I can pitch in with yet another library that does contrast calculation: https://github.com/xi/sass-planifolia/ (supports alpha channels, automatic shading/tinting, warning on insufficient contrast, …). I guess you wouldn''t want to depend on it, but I would be happy to implement the relevant subset in bootstrap itself (e.g. as a relplacement for color-yiq).

Then again, many frontend people I have met don't really like it when colors are selected or even adapted automatically. Maybe the better approach is to set colors explicitly and then run automatic checks on the result.

@XhmikosR
Copy link
Member

@patrickhlauke @ffoodd @mdo didn't we address this in v5?

@patrickhlauke
Copy link
Member Author

I think most of these are now resolved. I have a few stragglers left over that I recently filed separately #32053 #31360

this can be closed now I think

@aaronbauman
Copy link

Sorry if I'm misunderstanding how the process works or what was addressed here, but I'm still running into issues with colors failing minimum 4.5 contrast.

Specifically, the first example in this post, $blue #007BFF , persists into version 4.6.0 and is failing all my a11y tests.
Are these hex values locked for 4.x?
Do I need to move to 5.x to address?

Thanks in advance for your guidance

@patrickhlauke
Copy link
Member Author

Yes sorry, should have been clearer when closing - a lot of the combos were fairly "locked" for v4, and it would have been too much of a breaking change. We opted to focus on v5 for the full fixes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants