Theme Builder Generation Logic #1018
aaronreed708
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Color Generation
Theme Builder Creates 10 shades from any color added to the design system in light and in dark mode in both WCAG AA and AAA.
The shade naming taxonomy reflects Material Design's.
![] (TODO: missing image)
Shade 050 - has a lightness between 95 and 100
Shade 100 - has a lightness 85 and 95
Shade 200 - has a lightness 75 and 85
Shade 300 - has a lightness 65 and 75
Shade 400 - has a lightness 55 and 65
Shade 500 - has a lightness 45 and 55
Shade 600 - has a lightness 35 and 45
Shade 700 - has a lightness 25 and 35
Shade 800 - has a lightness 15 and 25
Shade 900 - has a lightness 0 and 15
For each shade of a color we assign an "on-color", which is either light or dark text that can used for any typography on top of the shade while meeting the required small text contrast requirement (4.5 for AA and 7.1 for AAA).
WCAG AA
Light Mode
Light text is by default pure white.
Dark text is by default #121212 and can be modified by the user.
Note in dark mode light text is not pure white but has an opacity, set by default to .6. The user can modify this opacity.
To generate the color scales in light mode we take the following steps.
We determine the lightness of the color the user enters into theme builder. We calculate the lightness using chroma.js. https://gka.github.io/chroma.js/#chroma-oklab
lightness = chroma.rgb(rgbArray).lch()[0]
Based on the lightness we then build calculate the number of lighter shades we need to create and the number of darker shades we need to create. Lets say the provide color has a lightness of 58. We would assign that to shade 4 and then we would need to create lighter shades 0-3 an darker shades 5-9. We use chroma scale to create those shades. We create two arrays "lightscale" and a "darkscale".
For the "lightscale" we use chroma to generate colors between pure white and the hex value the user provided.
lightscale = chroma.scale([( '#FFFFFF') ,color]).correctLightness(true).colors(lightColors);
Before we calculate the array of colors for "darkscales" we first calculate what the darkest shade of the color. To calculate the darkest shade in light mode we mix the given color with pure black with an opacity of .95. To calculate the darkest shade in light mode we mix the given color with pure black with an opacity of .98.
Next to generate "darkscale" we use chroma to generate colors between the hex value the user provided and the calculated darkest shade of the color.
A total of 10 shades is created by merging the two arrays.
We do need to adjust the first color, as we do not want the first shade of all colors to be pure white.
Next, we will adjust the chroma for each color to create a richer more compelling scale of colors. Chroma, short for "chrominance", is a color term that refers to a color's purity, intensity, or clarity.
Here is an example of a color palette scale with constant vs triangular chroma values applied.
![](TODO: missing image)
You can learn more about color palettes and chroma at: https://colorspace.r-forge.r-project.org/articles/hcl_palettes.html.
Rather than applying chroma in a constant or a linear manner we apply chroma in the triangle manner. With the chroma increasing up to shade 7 and then deminishing again.
![](TODO: missing image)
Before we are done with the light mode palette we will test each shade to see if light or dark text has a higher contrast. Then we check if the contrast between the shade and the chosen text color meets WCAG's contrast requirements. Note not all colors will meet the contrast requirement with light or dark, some indeed fail to meet both.
If a shade color fails we adjust the lightness of the shade until it meets the WCAG contrast requirements with dark text and then adjust the darkness shade until it meets the WCAG contrast requirements with light text. Which ever method produces a color closest to the orginal shade is the process we choose to adjust the shade.
As a result you now have a pallete or color scale where each shade and their corrresponding "on-color" meet the selected WCAG contrast requirements.
Dark Mode
In dark mode we start by rendering the light mode palette, but for each shade we increase the darkness by 20%. In theme builder you can also ajust the chroma of the generated light and dark mode colors. We suggest setting the dark mode chroma 20% lower than the light mode chroma. Reducing the chroma reduces the intensity or satutation of colors and you need desaturated colors in dark mode so as not to strain the eyes.
In dark mode, white text is no longer pure white, but rather white with an opaacity. By default we set the opacity to .06 but the user can adjust that.
We set the "on-color" and adjust eash shade to meet WCAG color contrast requirements just as we did in light mode.
Because white is no longer pure white it is harder to meet the WCAG contrast requirements for dark shades. As a result you see a jump when the shades transition from having a dark "on-color" to a light "on-color".
In order to minimize the jump we adjust the colors and rescale the colors. First, we identify the last color in the color scale to use a dark "on-color" and we adjust it to be as dark as possible, while still maintaining the WCAG requirments. Next, we find the first color to use a light "on-color" and lighten is as much as possible, while still maintaining the WCAG requirments. This minimizes the jump between these two colors. We then rescale between the 050 shade and the adjusted last color to use a dark "on-color" and between the first color to use a light "on-color" and the 900 shade. This eases the changes and makes the scale more smooth.
WCAG AAA
The way we generate colro scales in WCAG AAA is the same for both light and dark mode except that we adjust and rescale the colors for WCAG AAA light and dark mode just as we do in for WCAG AA dark mode.
Backgrounds
Once a user has added colors to their Theme Builder Design System they can add backgrounds.
By default we will have white (#ffffff) and black (#121212) backgrounds.
When the user builds a theme and selects a primary, secondary and teriary color for their design system we automatically add the selected colors as backgrounds.
The user can choose to add additional background colors.
For each background color we will generate the following variables for light mode and dark mode.
The following value are calculated to work on with any elevation applied to a background:
The logic to determin the color values assigned to each of these values is outliend in the Colored Icons and Text section below.
Colored Icons
Colored Text
By default we each design system has the following colored icons and text:
Adding Colored Icons
Additional colored icons and colored text can be added to a design system.
When a user selects a color for an icon - they are limited to the shades which have the required contrast against the default lightmode background. We then move down from that shade towards the 050 shade until we find a color that works on the default darkmode background that has a contrast of contrast of 3.1 or higher.
For the shades 100-800 by default we set the icon color equal to the On-Color.
User can go in and change these setting manually to override this to another shade of the color if it meets the color contrast requirements against the background and all elevations background colors for that mode.
We recommend against applying colored icons of colored text to colors in the 300-600 range because even if the color meets color contrast requirements, the mixing of colors can cause color vibrations.
Adding Colored Text
When add color for an icon - they are limited to the shades which have the a 4.5:1 AA or 7.1:1 AAA, contrast against the default lightmode background. We then move down from that shade towards the 050 shade until we find a color that works on the default darkmode background that has a contrast of contrast of 4.5:1 AA or 7.1:1 or higher.
For the shades 100-800 by default we set the icon color equal to the On-Color.
User can go in and change these setting manually to override this to another shade of the color if it meets the color contrast requirements at all elevations and levels for that mode.
We recommend against applying colored icons of colored text to colors in the 300-600 range because even if the color meets color contrast requirements against the background and all elevations background colors for that mode.
Elevations or Surface Containers?
In light mode and dark mode there are two systems for depicting depth to the end user, Elevations used by material 2 or tonal Surface Containers used in material 3.
Elevations
In light mode all elevations have a white background and as the elevations raise dropshadows increased
In darkmode the background becomes increasingly light. The following adjustments are made to the background.
elevation-0: At elevation +1 components with surface color containers receive a surface-tint color overlay with 0% opacity.
elevation-1: At elevation +1 components with surface color containers receive a surface-tint color overlay with 5% opacity.
elevation-2: At elevation +2 components with surface color containers receive a surface-tint color overlay with 8% opacity.
elevation-3: At elevation +3 components with surface color containers receive a surface-tint color overlay with 11% opacity.
elevation-4: Surface 4: At elevation +4 components with surface color containers receive a surface-tint color overlay with 12% opacity.
elevation-5: At elevation +5 components with surface color containers receive a surface-tint color overlay with 14% opacity.
Surface Containers
In Material 3, elevations were depricated and surface containers were introduced. Surface containers apply tonal values to the background color for 5 different levels.
The tones (lightnesss) are differently adjusted for light and dark modes.
![](TODO: missing image)
Please NOTE: We will use the same naming taxonomy as we did for elevations, elevation-0 to elevation-5 for these values.
Therefor in lightmode the elevation values will modify the background in the following manner:
elevation-0: it is the background color with no adjustments
elevation-1: it is the background color with a lightness of 100
elevation-2 and elevation-1: it is the background color with a lightness of 96
elevation-3 and elevation-1: it is the background color with a lightness of 94
elevation-4 and elevation-1: it is the background color with a lightness of 92
elevation-5 and elevation-1: it is the background color with a lightness of 90
This introduces colors to the surface color in light mode, where it used to be white with varying dropshadows, in Material 2.0.
Again in dark mode the change in surface lightness means that things that were compliant in the lowest surface container may no longer be contrast compliant at the other levels.
To address elevations or surface containers the following calculations will be rendered for each background color at each elevation.
On-Color (Standard Text)
On-Quiet (Quiet Text)
Border (Border Colors)
Surface Background
To account for the styling that should be used on the surface or elevation we create a background called, "surface"
We then generate the following to make sure they work on all 5 elevation levels for all background colors. In light mode the colors all have a lightness of (coming soon) and in dark mode the colors all have a lightness above (coming soon).
Colored Icons
Colored Text
If the method to express depth is Elevations/Dropshadows then in
light mode
We mix the default background with
mode.elevation.mixer = #ffffff
The following are:
mode.elevations.mix.0 = 1
mode.elevations.mix.1 = 1
mode.elevations.mix.2 = 1
mode.elevations.mix.3 = 1
mode.elevations.mix.4 = 1
mode.elevations.mix.5 = 1
dark mode
We mix the the default background with
mode. elevation.mixer = #ffffff
The following are:
mode.elevations.mix.0 = 1
mode.elevations.mix.1 = .05
mode.elevations.mix.2 = .08
mode.elevations.mix.3 = .11
mode.elevations.mix.4 = .11
mode.elevations.mix.5 = .14
Screenshot 2024-07-18 at 9.15.21 AM.png (TODO: missing image)
If the method is surface containers then:
If the method to express depth is Tonal Surfaces then
light mode
We mix the primary color with
mode. elevation.mixer = #ffffff
The following are:
mode.elevations.mix.0 = .98
mode.elevations.mix.1 = 1
mode.elevations.mix.2 = .96
mode.elevations.mix.3 = .94
mode.elevations.mix.4 = .92
mode.elevations.mix.5 = .90
dark mode
default background = #000000 mixed with primary color with .6 opacity
We mix #000000 primary color with
mode. elevation.mixer = primary color
The following are:
mode.elevations.mix.0 = .6
mode.elevations.mix.1 = .4
mode.elevations.mix.2 = .10
mode.elevations.mix.3 = .94
mode.elevations.mix.4 = .92
mode.elevations.mix.5 = .78
Themes
Themes allow users to create consistent look and feel across a platform but allow the coloring of the components and styles to vary based on theme.
Currenlty, Theming is restricted to colors, but we may introduce the ability to adjust other settins such as spacing to accomidate styles desirec for different users.
Users can select unique primary, secondary and tertiary colors and defaul backgrounds for light and dark modes for each theme.
When the user selects a primary color by the following values are created.
When a user selects a secondary and tertiary color the following values are created.
If a user creates multiple themes then can simply change the theme to see the values update across the design system.
JSON
Theme Builder will generate JSON and use style dictionary to transform the JSON to css.
One JSON file will be generated with the following architecture.
core
mode.aa-light
mode.aa-dark
mode.aaa-light
mode.aaa-dark
theme.default
(theme....) any additional themes
platform.default
platform.ios-mobile
platform.ios-tablet
platform.andriod
spacing.standard
spacing.extended
cognative.none
cognative.dyslexic
cognative.adhd
motion-sensative.off
motion-sensative.on
backgrounds.default (black or white)
backgrounds.primary
backgrounds.secondary
backgrounds.tertiary
backgrounds.black (inverse of default)
backgrounds.success
backgrounds.warning
backgrounds.error
backgrounds.info
backgrounds....(any additional backgrounds added by the user)
gradients.primary
gradients.secondary
gradients.tertiary
gradients.neutral
gradients....(any additional backgrounds added by the user)
charting.default
charting.red-weak
charting.green-weak
charting.blue-weak
charting.red-blind
charting.green-blind
charting.blue-blind
charting.blue-cone
charting.monochromatic
device.mobile-328x982
device.mobile-360x800
device.mobile-390x844
device.mobile-393x873
device.mobile-414x896
device.tablet-768x1024
device.tablet-800x1180
device.tablet-810x1080
device.tablet-962x601
device.tablet-1280x800
device.desktop-1366x768
device.desktop-1440x900
device.desktop-1536x864
device.desktop-1600x900
device.desktop-1920x1080
elevation.0
elevation.1
elevation.2
elevation.3
elevation.4
elevations.5
typography
shadows
NOTE: The italisized json listed above is fixed, only the bolded json is unique and updated based on the users input.
Here are example of the required code that theme builder generates.
Core: https://hedgedoc-hedgedoc.apps.aws-useast1-apps-dev-1.ocpdev.us-east-1.ac.discoverfinancial.com/RItOM_BrSFi_GF899saZ6A?both
For each mode generated: (aa-light, aa-dark, aaa-light and aaa-dark)
Mode: https://hedgedoc-hedgedoc.apps.aws-useast1-apps-dev-1.ocpdev.us-east-1.ac.discoverfinancial.com/FR4lp0ORT7WFhEszHLYcMA?both
Themes
https://hedgedoc-hedgedoc.apps.aws-useast1-apps-dev-1.ocpdev.us-east-1.ac.discoverfinancial.com/GOb8pRfnSrGk27zhoF3LwQ
Backgrounds: https://hedgedoc-hedgedoc.apps.aws-useast1-apps-dev-1.ocpdev.us-east-1.ac.discoverfinancial.com/1-r1KS9cTvqtbzwuWXOE2g
Here is the rest of the JSON code, which is fixed.
(coming soon)
Also the device json is only used in Figma and will not be transformed to css.
CSS
Theme Builder will no longer output both JSON and CSS for the end user, but just JSON. One source of truth.
When a design system is saved within theme builder, code is pushed from theme builder to a git repo, provided by the end user.
GitHub automations will run Style Dictionary Transforms when the there is a PR. The transforms will generate CSS code.
The CSS will use data-sets to update values in a dynamic fashion.
The css code can be read by Storybook or Chromatic to render the UI styles and components.
The GithUb repo can also be connected to Figma Tokens which can render any changes in the JSON into our existing Figma Design System.
The following css files will be generated from the JSON using Style Dictionary:
core.css (containing core, typography and shadows JSON)
mode.css
theme.css
platform.css
cognative.css
spacing.css
backgrounds.css (containing both backgrounds and gradients JSON)
elevations.css
charting.css
styles.css (applying above to styled and components)
Data Sets
Data sets will be used in the css to render the dynamic styles according to device, user and coder input.
For each of the italized css files listed above the formating will utilized to assign variables.
For the appropriate styles to be applied to the ui only the name of the data attribute needs to be updated. The following data attributes include:
data-wcag="aa" (aa of aaa)
data-mode="light" (light or dark)
data-platform = "adroid" (default, ios-tablet, ios-mobile or android)
data-cognative = "none" (none, adhd or dyslexia)
data-motion-sensative = "off" (off or on)
data-spacing = "standard" (standard or exteneded)
data-elevation = "0" (0-5)
data-charting = "none" (none, red-weak, blue-weak, green-weak, etc)
Javascript can be used to apply modes and platforms.
In user settings we could allow users to update cognative, motion-sensative and charting (colorblind) settings, which could be applied to the application using javascript.
CSS Performance
Using 5000 CSS variables on 10 000 HTML nodes is only 0.7% slower than raw CSS. The final rendererd components and styles use only 155 universal and component variables and 112 typography variables.
Using dynamic variables is better than creating more than 10,000 times the amount of css needed to render the 51,840 different combinations of:
2 wcag levels
2 modes
4 platforms
1 theme (at least)
3 cognative modes
2 motion sensitivity
12 backgrounds minimum
5 elevations
9 colorblind / charting modes
CSS Variables
All the logic generated above is solidified into the following (98) universal variables. These css variables dynamically update to keep everything wcag accessible compliant in regards to contrast, target are and focus state, which account to 90% of all failures. Note engineering still needs to apply aria tags, alt tags and make sure the user can tab through the interface
Universal Variables
Colors (10):
Becoming familiar with the color variable is critical to creating accessible components.
Hotlink Underline (2)
Icons (9):
Colored Text (7):
Size (13):
NOTE: all clickable components should sit inside a parent container with a min-width and weight set to {--min-target}.
Space (12):
Radius (7):
Border (7):
Shadows (27):
Micro Animation (5):
Component Variables (47)
We use component variables to efficently update all component variables types. For example, you may have 100 variant of a button, but they all have the same radius, height, min-width, etc. So you change one component vairable and updates are made across all component varients.
Avatars(3)
Buttons(5)
Cards(5)
Chip(5)
Dropdown(2)
Hero(3)
Images(3)
Inline or List Images(2)
Modals (4)
Popovers (2)
Switches and Sliders (4)
**Sections(1) **
Tables(2)
Toast (3)
Tooltips (3)
Typography Variables (4)
In order to apply typography styles to a component you need to at a mimum 4 varilables; the typography name, typography text-decoration, text-transform and character spacing.
The various typography names are:
Body Styles
Small Text Styles
How to assign typography variables?
In order to apply all the styles for the "overline" you would use the following 4 variables.
(which includes the font family, size, weight, and line-height)
Beta Was this translation helpful? Give feedback.
All reactions