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

Review contrast for common colour schemes to improve a11y #5497

Open
chris48s opened this issue Sep 6, 2020 · 19 comments
Open

Review contrast for common colour schemes to improve a11y #5497

chris48s opened this issue Sep 6, 2020 · 19 comments
Labels
core Server, BaseService, GitHub auth, Shared helpers npm-package Badge generation and badge templates

Comments

@chris48s
Copy link
Member

chris48s commented Sep 6, 2020

📋 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

@chris48s chris48s added core Server, BaseService, GitHub auth, Shared helpers npm-package Badge generation and badge templates labels Sep 6, 2020
@runxel
Copy link

runxel commented Sep 7, 2020

This one also performs really bad

badge

@chris48s
Copy link
Member Author

chris48s commented Sep 7, 2020

Right yes. and are also part of the standard palette

@chris48s chris48s closed this as completed Sep 7, 2020
@chris48s chris48s reopened this Sep 7, 2020
@chris48s
Copy link
Member Author

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
Copy link

ctcpip commented Sep 6, 2021

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
Copy link

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 audit1 was the contrast ratio of shields.io badges on package readmes2. 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 labels3, 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.

Footnotes

  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
Copy link
Member

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 🙏 ❤️

@ctcpip
Copy link

ctcpip commented Aug 11, 2022

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
Copy link

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
Copy link

nvlang commented Apr 2, 2023

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

@rybak
Copy link

rybak commented Oct 28, 2023

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
Copy link

JoshuaKGoldberg commented Jan 10, 2024

Coming over from #9890: thinking about how the white foreground text in typical badges has a slight background shadow between it and the background (#5497 (comment)). 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.

  • Current colors: are from color.js;
    • blue and grey were fine with their current colors, so I left them as is
  • Updated (Default Shadow) colors are roughly from darkening the color on the myindex slider until Lc-75
  • Updated (More Shadow) colors are from meyerweb.com/eric/tools/color-blend for a 50% blend between the old and new colors
    • green, yellow, orange, and red look pretty dark and different, so I tried this for them too
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
Copy link
Member Author

chris48s commented Jan 13, 2024

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:

  • I like the idea of keeping the default white font colour and adjusting the standard palette of background colours to achieve sufficient contrast
  • I am in favour of having a standard palette of semantic colours that all work with the same (white) font colour on both left and right sides of the badge
  • I agree that just darkening the current palette works OK for some cases, but green, yellow, yellowgreen, and orange don't respond well to just darkening. Yellow and yellowgreen in particular are just too brown.

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
Copy link

JoshuaKGoldberg commented Jan 14, 2024

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

  • Note 1: that the current WCAG, 2.1, uses a much simpler algorithm (luminance of the foreground color divided by luminance of the background color)2. In most cases it's better to go with current standards rather than future-facing drafts that might change... but APCA is IMO a much better color contrast algorithm.
  • Note 2: I'm not an accessibility expert. If an actual expert could chime in, that would be better than my opinions. 😄

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:

  • A 5px blurred copy of the existing shadow with 75% opacity
  • A 1.5px stroke of the same color around text at 50% opacity

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

  • Starting with the Original color, except for the following Adjusted colors:
    • brightgreen: I moved the slider much closer to blue so that it looks different from green
    • green: I moved the slider a bit closer to blue / further from yellow, so it doesn't look yellow-ish
    • yellow: I moved the slider a bit closer to yellow, so it doesn't look as green-ish
    • red: I moved the slider a bit closer to red, so it's less orange-y
  • Perceived value: sliding the darkness until it hits 75 Lc
  • Actual value: color blending of the Original and Perceived with 2 midpoints, choosing the lighter midpoint

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?

Footnotes

  1. https://www.w3.org/WAI/GL/WCAG3/2020/how-tos/visual-contrast-of-text/

  2. https://www.w3.org/TR/WCAG20-TECHS/G18.html

@chris48s
Copy link
Member Author

chris48s commented Jan 14, 2024

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
Copy link
Member Author

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
Copy link
Member Author

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
    const namedColors = {
    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
Copy link

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
Copy link
Member Author

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 #9916 and I've gone with:

  • brightgreen: #10b73d
  • green: #67ac09
  • yellowgreen: #95991a

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
Copy link

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Server, BaseService, GitHub auth, Shared helpers npm-package Badge generation and badge templates
Projects
None yet
Development

No branches or pull requests

9 participants