badges / shields

Concise, consistent, and legible badges in SVG and raster format
https://shields.io
Creative Commons Zero v1.0 Universal
23.9k stars 5.51k forks source link

Review contrast for common colour schemes to improve a11y #5497

Open chris48s opened 4 years ago

chris48s commented 4 years ago

:clipboard: Description

Refs #5467

Some of our standard colour schemes score quite poorly on contrast for accessibility and could be improved. For example

Screenshot at 2020-09-06 11-55-53

Screenshot at 2020-09-06 11-56-18

We should review our most commonly used styles from this perspective. We probably can't rely on only brightness to get amazing contrast on every bespoke colour, but we can probably look at 'presets' or a package like color-contrast-checker to ensure all of these have a decent accessibility score.

The 'inactive' style also performs quite badly:

Screenshot at 2020-09-06 20-43-49

runxel commented 4 years ago

This one also performs really bad

badge

chris48s commented 4 years ago

Right yes. and are also part of the standard palette

chris48s commented 3 years ago

Spent a bit of time on this.. basically all of our current standard colour combinations score pretty poorly on contrast:

Screenshot at 2020-12-22 20-08-08

Keeping all the existing backgrounds as they are but switching the text colour from white to black would give greater contrast in all cases and get us up to at least WCAG AA for small (below 18pt) fonts.

Screenshot at 2020-12-22 20-04-29

If we did that on our badges that would take us from

Screenshot at 2020-12-22 20-25-51

to something like

Screenshot at 2020-12-22 20-26-56

which does have more contrast but does seem to 'pop' slightly less. I wonder if tweaking the drop-shadow a bit could improve that? (not really a design person).

ctcpip commented 3 years ago

it would be nice to at least have an option to toggle. so you could preserve the existing behavior, but people could opt-in for WCAG AA compliance if they wanted. alternatively, though not as convenient, would be an additional option to set the text color directly.

dylanatsmith commented 2 years ago

Hi, I’m a designer at GitHub and npm. We’re currently fixing accessibility issues across the npmjs.com site.

One problem that was raised in a recent audit[^1] was the contrast ratio of shields.io badges on package readmes[^2]. We pull these from GitHub readmes and obviously have no control over their styling.

I’d love to offer design help to find a solution to the contrast issues mentioned above in the thread. We have some precedent for solving for this on GitHub issues labels[^3], and it looks like this may be true of the shields users specify a custom colour for as well.

If you’re open to it, I can do some visual explorations that might be useful in moving toward (or ruling out) various directions.

[^1]: Example of contrast issue from our accessibility audit image

[^2]: Example of shields.io badges on axios package readme

[^3]: Examples of issue labels on GitHub where users can choose a background colour and the text colour is dynamically chosen for optimum contrast https://user-images.githubusercontent.com/6905903/183891828-bbbf198a-66d6-4ab7-bd58-10509d718676.mov

calebcartwright commented 2 years ago

If you’re open to it, I can do some visual explorations that might be useful in moving toward (or ruling out) various directions.

That would be fabulous @dylanatsmith, thanks so much :pray: :heart:

ctcpip commented 2 years ago

it's worth noting that WCAG 3 will use a new system APCA (Advanced Perceptual Contrast Algorithm).

as an aside, I ended up creating a11y-badges for exactly this reason. I have yet to update it to use APCA though.

potremblay commented 1 year ago

I also think that it should be addressed. The colour and text should by default be accessible and friendlier without any configuration from the party who using it.

As an example, I use a third party to for my end-to-end testing who return a badge. Should I write to every third party that I use to update the configuration, which will only go to their backlog?

It might seem extreme, but all element on a page should be accessible, not only some.

nvlang commented 1 year ago

Maybe GitHub's own design system could serve as an inspiration for badge colors?

rybak commented 1 year ago

I''ve stumbled upon this issue while trying figure out if text color could be changed. In my example the background color is #00f6eb, for which the brightness calculation from current version of badge-maker/lib/color.js gives 0.67. This results in white text, which is not very readable.

Demo: . This fails Web Content Accessibility Guidelines (WCAG): contrast checker (screenshot).

Spent a bit of time on this.. basically all of our current standard colour combinations score pretty poorly on contrast:

[...]

Keeping all the existing backgrounds as they are but switching the text colour from white to black would give greater contrast in all cases and get us up to at least WCAG AA for small (below 18pt) fonts.

@chris48s, here's a suggestion for WCAG compliance. To choose a compliant foreground color, the contrast ratio of background color with white and black foreground could be calculated. Then choose the color with greater contrast. WCAG website gives formulas for how to calculate the contrast ratio.

JoshuaKGoldberg commented 10 months ago

Coming over from #9890: thinking about how the white foreground text in typical badges has a slight background shadow between it and the background (https://github.com/badges/shields/issues/5497#issuecomment-749769012). That shadow improves its readability a bit. But it's only the pixels below the text. So I think wouldn't be counted as improving contrast unless it surrounds a majority of the pixels around the letters.

Proposal: How about the following somewhat-dynamic contrast system...

  1. Add/keep a badge option to:
    • Manually choose text color between white (default) or black
    • (if white text) Manually choose darker shadow between standard (default) or emphasized
  2. When creating a badge, calculate the contrast of foreground text and background color with APCA
  3. If the contrast isn't enough for body text (Lc-75)...
    1. ...but text color is white and an emphasized shadow would get enough contrast, emphasize the shadow (darken it & have it surround the text)
    2. ...but text color isn't specified and swapping the text to black would get enough contrast, swap text color to black
  4. If the contrast still isn't enough, give a big angry red warning on the website

...along with adjusting all preset colors so that they'd be accessible in the new system with white foreground text?

Examples: The following table shows what that'd look like using myndex.com/APCA to calculate APCA contrast.

Name Current Updated (Default Shadow) Updated (More Shadow)
Color Example Lc Color Example Lc Color Example *
brightgreen #44cc11 Shield with # on a near-black label and 44cc11 on that color background 45.7 #008c14 Shield with # on a near-black label and 008c14 on that color background 75.3
green #97ca00 Shield with # on a near-black label and 97ca00 on that color background 41.6 #618500 Shield with # on a near-black label and 618500 on that color background 75.1 #7ca800 Shield with # on a near-black label and 7ca800 on that color background
yellow #dfb317 Shield with # on a near-black label and dfb317 on that color background 42.5 #917721 Shield with # on a near-black label and 917721 on that color background 75.2 #b8951c Shield with # on a near-black label and B8951C on that color background
yellowgreen #a4a61d Shield with # on a near-black label and a4a61d on that color background 55.9 #7a7f21 Shield with # on a near-black label and 7a7f21 on that color background 75.1 #8f931f Shield with # on a near-black label and 8F931F on that color background
orange #fe7d37 Shield with # on a near-black label and fe7d37 on that color background 54.6 #bd5f26 Shield with # on a near-black label and bd5f26 on that color background 75.1 #de6e2f Shield with # on a near-black label and DE6E2F on that color background
red #e05d44 Shield with # on a near-black label and e05d44 on that color background 68.4 #c9543c Shield with # on a near-black label and c9543c on that color background 75.0
blue #007ec6 Shield with # on a near-black label and 007ec6 on that color background 75.1
grey #555555 Shield with # on a near-black label and 555555 on that color background 90.8
lightgrey #9f9f9f Shield with # on a near-black label and 9f9f9f on that color background 56.7 #7a7a7a Shield with # on a near-black label and 7a7a7a on that color background 75.2

* The actual badge would have more text shadow than this.

I'd be happy to send PRs for this work!

chris48s commented 10 months ago

Thanks for the suggestions @JoshuaKGoldberg Sorry it has taken a few days to reply to this, but I have been thinking about it.

Broadly speaking:

There's a number of other suggestions here about providing extra configuration options and automatic contrast detection. I'm not dismissing them out of hand, but I think if we can start by adjusting the 9 standard named/semantic colours we use on every (non-custom) badge, that would improve accessability in like 99% of cases. So I think that is where I'd like to constrain the scope first. Seems like we can do a lot of good there as a first step without introducing a lot of complexity.

I have a few follow up questions:

  1. Where does the LC-75 value come from? I'm not questioning it, but if we achieved that contrast value, where would get get us? Would that be like WCAG AA standard?
  2. I think I'd really like to see a mockup of your proposal for a drop-shadow that would make a difference to readability/contrast, or maybe more detail that would help me make something we can look at. I think seeing that would really help.
  3. While I agree #008c14 and #7a7a7a don't look bad, presumably if we tweaked the drop shadow for all cases, we could also get away with going lighter on those too. i.e: we could also pick something somewhere between #44cc11 and #008c14 and something between #9f9f9f and #7a7a7a ?

I have made more more notes beyond that, but if we could just focus on those 3 points to start with, that would be great.

JoshuaKGoldberg commented 10 months ago

Where does the LC-75 value come from?

It's the threshold for "body text okay" per APCA (myndex.com/APCA). "This level may be used with non-body text with a font no smaller than 15px/400."

if we achieved that contrast value, where would get get us? Would that be like WCAG AA standard?

It would be compliant for the current WCAG 3 draft that uses APCA^1.

mockup of your proposal ... something somewhere between

You got it! The current text shadow is a 30% opacity #010101 copy of the text just below the text itself. I played around and found I liked the look of adding:

At that point, I think it's safe to compute background colors by:

Here's a table showing those updates:

Name Current Updated (More Shadow)
Original Example Lc Adjusted Perceived Lc Actual Example
brightgreen #44cc11 Shield with # on a near-black label and 44cc11 on that color background 45.7 #11cc45 #0e8c2d 75.1 #10b73d Shield with # on a near-black label and 0fb749 on that color background with more text shadow
green #97ca00 Shield with # on a near-black label and 97ca00 on that color background 41.6 #59ca00 #3f8a00 75.1 #50b500 Shield with # on a near-black label and 50b500 on that color background with more text shadow
yellow #dfb317 Shield with # on a near-black label and dfb317 on that color background 42.5 #dfa717 #9a7410 75.1 #c89615 Shield with # on a near-black label and c89615 on that color background with more text shadow
yellowgreen #a4a61d Shield with # on a near-black label and a4a61d on that color background 55.9 (same) #788014 75.0 #95991a Shield with # on a near-black label and 95991a on that color background with more text shadow
orange #fe7d37 Shield with # on a near-black label and fe7d37 on that color background 54.6 (same) #c25b2a 75.0 ea7233 Shield with # on a near-black label and ea7233 on that color background with more text shadow
red #e05d44 Shield with # on a near-black label and e05d44 on that color background 68.4 #e04444 #d74242 75.0 #dd4343 Shield with # on a near-black label and dd4343 on that color background with more text shadow
blue #007ec6 Shield with # on a near-black label and 007ec6 on that color background 75.1 (same) (same) (>75.1) (same) Shield with # on a near-black label and 007ec6 on that color background with more text shadow
grey #555555 Shield with # on a near-black label and 555555 on that color background 90.8 (same) (same) (>90.8) (same) Shield with # on a near-black label and 555555 on that color background with more text shadow
lightgrey #9f9f9f Shield with # on a near-black label and 9f9f9f on that color background 56.7 (same) #7a7a7a 75.2 #939393 Shield with # on a near-black label and 939393 on that color background with more text shadow

I'd personally probably go with a green color that's darker to make it stand out from yellowgreen. Maybe the #008c14 from before - shield-green-suggestion?

chris48s commented 10 months ago

Thanks for the extra effort you've put into this. Personally I like the direction we're going in.

Thinking about the versions with with the more pronounced drop-shadow, there's definitely more contrast between background and foreground. I feel like they look pretty good large



but down at "normal" size, the additional drop shadow introduces a bit of extra visual noise - I'm not sure if I find it more readable or not. I think it kinda depends on the character.

I was hoping doing this would just be an obvious win. For me, something like the 1 character in c89615 here is actually less clear to me than the 1 in dfb317 here

Would be interested in views from other commenters on this thread.

chris48s commented 10 months ago

Had a bit more of a fiddle with this.

My initial instict was that sharpening up the drop shadow might help, but counter-intuitively (to me), increasing the blur on the drop shadow actually makes things clearer IMO. Going really diffuse (am I using the right word here?) on the drop-shadow could be the way to go.

It is subtle, but to me this gets more readable as I go from left to right at small size.

One additional complication to quickly throw in here is that we also have the flat-square style which is not the default but is also quite popular, and does not use any drop shadow at all. Maybe we just focus on the flat (default) style to start with.

chris48s commented 10 months ago

This seems to have fizzled out a bit, but I'd quite like to not lose momentum on this. Feels like we are fairly close to a solution.

I think we can find a workable drop shadow, even if the exact value is TBC.

There's a couple more things I do want to bring up.

  1. As well as hex values, we also support named CSS colours, so you can do stuff like https://img.shields.io/badge/%23-fuchsia-fuchsia or https://img.shields.io/badge/%23-salmon-salmon - unlike the values in https://github.com/badges/shields/blob/501c53a0b420c144428edccd503f77ab9cd73a22/badge-maker/lib/color.js#L6 those don't work by using an explicit mapping of string to hex value, they just literally insert fill="fuchsia" or whatever in the SVG. Some of the values we've manually aliased are also standard named CSS colours and we've mapped them to different hex values than the standard https://developer.mozilla.org/en-US/docs/Web/CSS/named-color Doing this probably takes us even further from that in some cases. I think we probably just accept that, but I'm noting it.
  2. One of our named colours is brightgreen. This is not a named CSS colour we've overridden. It is just something we've made up at some point, but is now used in a lot of places. I'd describe #008c14 as quite a dark green in the grand scheme of things. Just for the purposes of making the names make sense, it would be nice if the hex value we map brightgreen to was defensibly "bright". Given that, I'm more inclined to go with #10b73d than #008c14 for the brightgreen, but maybe we also tweak the green value to make sure those two are discernably different.
JoshuaKGoldberg commented 10 months ago

This all sounds good to me!

Going really diffuse (am I using the right word here?) on the drop-shadow could be the way to go.

👍 I quite like that, but was nervous to propose a change that touched so much of the visual state. Sounds great 😄.

flat (default) style to start with even if the exact value is TBC

👍 I'd be happy to help with a follow-up too. It strikes me as likely that shipping a first round of them will inevitably cause some users to rush out of the shadows and make noise about the changes. Fast follows are probably going to be asked for.

also support named CSS colours

TIL! Very interesting. Some of the lighter CSS colors show up better than others right now. aqua and beige are very readable thanks to automatic black text. lime isn't getting black text and is not very readable.

aqua badge without shadow beige badge without shadow lime badge without shadow

Proposal: for now, let's only add this new shadow in existing cases where text would be switched to black? I think lime not switching to black is a separate issue.

also tweak the green value to make sure those two are discernably different

👍 how does #009800 strike you?


Aside: I threw together a script to generate a table of comparisons for any particular svg type: https://github.com/JoshuaKGoldberg/badges-shields-shadow-reference.

chris48s commented 10 months ago

how does #009800 strike you?

If you think about green meaning "good" and brightgreen meaning "best", it is not clear to me which is "better" out of #10b73d and #009800. They could be either way round. I think the green colour need to be more yellowey to convey that. I've now opened a PR over in https://github.com/badges/shields/pull/9916 and I've gone with:

Does #67ac09 give enough contrast? I'm slightly unclear how you're accounting for the drop-shadow in the calculations. Anyway, lets carry that conversation on in that PR. I'll mention you on the relevant line.

JoshuaKGoldberg commented 10 months ago

If you think about green meaning "good" and brightgreen meaning "best"

Oh! Fascinating, I hadn't thought of that. I'd thought green meant "good" and brightgreen meant "emphasized good". That makes a lot of sense, and explains green being a bit yellowish. Thanks! Maybe there's a separate docs issue to be filed about what the intended semantics of each preset color are?