-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Simplified color naming for accessibility #6180
Conversation
…o color-a11y-i18n
Build successful! 🎉 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested various combinations in Safari with VO and this seems much better!
} | ||
|
||
let hue: string; | ||
[hue, l] = this.getOklchHue(l, c, h, locale); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see l
change as a result of this calculation, but I don't quite understand why. I know it's for orange because it dips into brown very quickly, but wouldn't the l
already be correct because it's one of the channels returned by the conversion to OKLCH?
if we just got this from the sample conversion code, that's fine, I might've missed it while reading through
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It comes from this line: https://github.com/adobe/react-spectrum/pull/6180/files/c05e757846a4745b9e80cb2ec9fbf54e595abb77#diff-2737484a486e2634802c43f60406fc1231698480673f4268bd1e8f029448bcccR185
Basically, if the hue is orange, we need to adjust the lightness so that "dark orange" comes before "brown", so we split the lightness range in half. Otherwise orange would always be considered light/very light.
Build successful! 🎉 |
## API Changes
unknown top level export { type: 'any' } @react-stately/colorColorchanged by:
Color {
+ clone: () => Color
formatChannelValue: (ColorChannel, string) => string
getChannelName: (ColorChannel, string) => string
getChannelRange: (ColorChannel) => ColorChannelRange
getChannelValue: (ColorChannel) => number
getColorChannels: () => [ColorChannel, ColorChannel, ColorChannel]
+ getColorName: (string) => string
getColorSpace: () => ColorFormat
getColorSpaceAxes: ({
xChannel?: ColorChannel
yChannel?: ColorChannel
}) => ColorAxes
+ getHueName: (string) => string
toFormat: (ColorFormat) => Color
toHexInt: () => number
toString: (ColorFormat | 'css') => string
withChannelValue: (ColorChannel, number) => Color
it changed:
|
@devongovett Curious why pure yellow Note that "Arctic Blue", "Cornflower Blue", "Cobalt Blue", and "Persian Blue" are named colors in CSS 4, but I agree that they may not be useful when providing an accessibility name. |
Good question. Might need to adjust the thresholds a bit: #6210 |
Closes #5792, closes #4110, closes #4111.
This implements an alternative color naming strategy to the one proposed in #5792 (and #1732 before that). The previous proposal used fairly complex color names that I'm not sure would be understandable for everyone, or easily translated to different languages. For example, I'm not sure I would know the difference between "Arctic Blue", "Cornflower Blue", "Cobalt Blue", or "Persian Blue" without looking at them. These names also resulted in the need for over 250 new strings that would need to be translated into different languages, and increase the bundle size.
This proposal uses a simplified strategy that requires only 26 additional strings, in various combinations. This includes 13 main hues (pink, red, orange, brown, yellow, green, cyan, blue, purple, magenta, gray, white, and black), along with the halfway points between them (e.g. red orange, yellow green, and blue purple), combined with modifiers for lightness (very dark, dark, light, and very light), and chroma (pale, grayish, and vibrant). These combine together to form a description for any color. In addition to reducing the number of strings we need, these descriptions are also simpler, more universally understood, and more easily translated to other languages. This proposal is inspired by how the native iOS color picker works in VoiceOver.
The algorithm used to generate the description works in the OKLCH color space, recently standardized by CSS. This color space has the advantage of having uniform lightness across all hues, unlike HSL/HSV for which some hues such as blue are much darker than others. As shown below, you can see the difference between HSL and OKLCH.
It also avoids a shift in hue based on lightness, as can be seen in HSL for blue (which shifts toward purple).
These properties mean we can produce a perceptually accurate description for any color. The algorithm first converts the color to OKLCH, and uses the manually picked thresholds along the l, c, and h channels to produce descriptions for the hue, lightness, and chroma. If a color is partially transparent, that is also prepended (I used percent transparent rather than percent opaque here because I thought it seemed more easily understandable).
In order to localize these color names, the strings for each channel are externalized, and a "colorName" string combines them together. For example in English, the string is "{transparency} {lightness} {chroma} {hue}", but in other languages, the words may be in a different order. In French, I believe the hue would come first, followed by the lightness and chroma, and in Chinese there would be no spaces between the words. The halfway points between hues (e.g. yellow orange) are also included as separate strings rather than combining the individual hues because I believe in some languages there are single words for these colors rather than combining the two words like in English. We will need to somehow explain the way this works to translators so they can accurately produce strings in each language.
To easily test, I've added the color name to the stories for ColorArea, ColorSlider, and ColorWheel, but they should also be read by screen readers.