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 tokens - Improving semantic and a11y #2440

Open
Powerplex opened this issue Oct 1, 2024 · 0 comments
Open

Color tokens - Improving semantic and a11y #2440

Powerplex opened this issue Oct 1, 2024 · 0 comments

Comments

@Powerplex
Copy link
Contributor

Powerplex commented Oct 1, 2024

Introduction

Spark decided early on to stick with semantic color token instead of a literal color palette. The reason is Spark must be able to manage multiple themes for a single website (not just a light + dark theme).

Spark color tokens amount to 123 colors to define PER theme. This is enormous when compared to other design system, and means it is almost impossible for someone to create their own themes. Leboncoin (our main consumer) is able to do it thanks to a dedicated team of designers cherry-picking each color one by one.

List of issues with the current color management:

  • human cherry-picking means contrast rules between colors are never consistant.
  • designers are still using an RGB color palette to build the themes. RGB color space is not matching the human eye color space. For this OKLCH is the closer we can use, because it enforces identical contrast for every color hue (LCH stands for "Lightness, Chroma, Hue"). A Figma plugin exists.
  • the person creating the theme must know which color token is meant to be used on top of another one and for what type of content (text VS background, etc).

Current colors semantics/issues

Spark offers 13 color "families" in each theme:

Semantic families:

  • basic => Use Basic colors on fundamental components of the UI that do not require a specific intent, such as form elements like Switch, RadioButton, CheckBox, and ProgressBar. 
  • accent => Highlight important elements in the interface. Draw attention to specific elements and create visual interest while guiding users' focus.
  • main => Emphasize the most relevant components and essential elements on the UI, like primary actions or brand panels
  • support => Complement the main actions or primary elements to provide a sense of hierarchy and visual consistency in the UI.  They are typically darker tones that complement the primary color scheme without overpowering it.

Feedback families:

  • success => Convey success status. For this reason we advise it remains a green hue.
  • alert => Convey alert/warning status. For this reason we advise it remains a orange hue.
  • error => Convey error status. For this reason we advise it remains a red hue.
  • info => Convey info status. For this reason we advise it remains a blue hue.
  • neutral => Convey neutral status. For this reason we advise it remains on a greyscale hue.

Base families:

  • background => The color of the background of your site (ideally very light on light theme, dark on dark themes)
  • surface => Similar to background, but for container elements backgrounds, not the main page background.
  • outline => For strokes and dividers.
  • overlay => Used for transparent background of dialogs and drawers. Ideally remains on a greyscale.

It might seem simple, but each family has it's own set of colors, here is the main family tokens:

main: '#EC5A13',
onMain: '#FFFFFF',
mainHovered: '#F07B42',
mainPressed: '#F07B42',
mainFocused: '#F07B42',
mainContainer: '#FFE9DE',
onMainContainer: '#89380F',
mainContainerHovered: '#FFF2EB',
mainContainerPressed: '#FFF2EB',
mainContainerFocused: '#FFF2EB',
mainVariant: '#B84A14',
onMainVariant: '#FFFFFF',
mainVariantHovered: '#EC5A13',
mainVariantPressed: '#EC5A13',
mainVariantFocused: '#EC5A13',

We notice three blocks: main, mainContainer, mainVariant:

  • main is supposed to be hight contrast.
  • mainContainer is supposed to be a low contrast version (where the background blends in with the surface token
  • mainVariant => Nobody knows what is the logic behind this one, and for some reason it exists only for some families (main, accent, support). Spark itself DO NOT USE those tokens.

For each family token, the *pressed and *focused token are IDENTICAL to the *hovered token. This is very bad, it means Spark do not effectively manage pressed/focused styles for background.

Also, for Leboncoin (main consumer of Spark), Basic and Support colors are identical (not sure we need to keep both).

All this is way too complicated.

The end goal 1 - remove unnecessary tokens

It seems the following tokens are not used by either designers nor developers (their colors are always IDENTICAL to the "hovered" token, so they can all be replaced by this one):

  • *-pressed
  • *-focused

Removing those tokens from themes could take us from 123 colors to 77 colors, making things easier to maintain.

Then, I think all *-variant named token should also be removed:

  • Their semantic is not explained anywhere on ZH nor Figma.
  • The only use-case in Spark is on the Rating, and the reason is "main" color was not accessible.
  • If "variant" token exists only because the base color is not accesible, then the base color must be updated, and these "variant" token must all be removed.

Then we would go from 77 color tokens to 68 colors. This is way easier to maintain is closer to what other semantic design system offers.

The end goal 2 - a11y theme checker

I want to provide a tool (aimed toward spark developers) that check the theme a11y (contrast ratio).
this script could be used on the CI to prevent merging if colors do not satisfy WCAG contrast rule (similar to this, but code-only: https://webaim.org/resources/contrastchecker/)

The end goal 3 - simpler theme generation

Then, I want to provide an alternative/simpler way to create Spark theme that, given a single color code, generates the complementary color tokens for a whole color family, enforcing AA WCAG contrast rules:

// only color provided by the person creating the theme
main: '#EC5A13', => only color provided by the person creating the theme

// token computed from the "main" color provided, enforcing good contrast using OKLCH color space
onMain, Hovered, mainPressed, mainFocused
mainContainer, MainContainer, mainContainerHovered, mainContainerPressed, mainContainerFocused
mainVariant, MainVariant, mainVariantHovered, mainVariantPressed, mainVariantFocused

If we consider that "pressed" and "focused" are unused by designers (they are) -> 9 tokens remains:

// provided
main:  '#EC5A13',

// computed
onMain, mainHovered
mainContainer, mainContainer, mainContainerHovered
mainVariant, mainVariant, mainVariantHovered

If we consider that "variant" should be removed -> 6 tokens remains:

// provided
main:  '#EC5A13',

// computed
onMain, mainHovered
mainContainer, mainContainer, mainContainerHovered

In the end, you could just provide the base color for each family, and a whole accessible theme would be generated for you. Alternatively, we could offer a UI to then tweak the generated theme (sliders for each color, only allowing you to pick color that contrasts well enough)

WIP: DO NOT COMMENT YET

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

No branches or pull requests

1 participant