appsmith
appsmith copied to clipboard
Color tokens structure and rules generation for button and canvas
- [x] #20358
- [x] #20715
- [x] #20716
- [x] #21288
- [x] #21913
- [ ] #22365
- [x] #22424
- [x] #22512
- [x] #22568
- [ ] #22630
- [ ] #22699
- [x] #22713
- [x] #22823
- [x] #22921
Semantic color naming strategy Parametric color schemes Color Generator POC4: Parametric theme from a single seed
Naming hierarchy (type-role-modifiers-state) based on a visual functionality, e.g.:
--bg-accent-light-hover
--fg-onaccent
--border-accent
.
The whole color scheme for widget set can be built from one initial accent color + accompanying grays.
What we have now is some naive generation of colors from a key accent color e.g.:
export const getComplementaryGrayscaleColor = (hex = "#000") => {
const bg = parseColor(hex);
const text = new Color("#fff");
const contrast = bg.contrast(text, "APCA");
// if contrast is less than -35 then the text color should be white
if (contrast < -35) return "#fff";
return "#000";
};
export const calulateHoverColor = (hex = "#000") => {
const color = parseColor(hex);
switch (true) {
case color.get("oklch.l") > 0.35:
color.set("oklch.l", (l) => l + 0.03);
break;
case color.get("oklch.l") < 0.35:
color.set("oklch.l", (l) => l - 0.03);
break;
}
return color.toString({ format: "hex" });
};
This needs to evolve based on the following knowledge.
APCA contrast check returns a number in the range from −107.9
to 106
. Contrast will be negative for light content on a dark background and positive for dark content on light background. In APCA it is important what is a background and what is a foreground, results of measurement differ. The absolute value of the contrast measurement is what defines whether the contrast is good/sufficient. APCA standard recommends taking into the consideration font size and weight for text content and has following guidelines that we can start from as a reference:
60 • The minimum level recommended for content text that is not body[...] The minimums: no smaller than [...] 24px normal weight (400) [...] 16px/700. These values based on the reference font Helvetica.
75 • The minimum level for columns of body text with a font no smaller than 24px/300 weight, 18px/400, 16px/500 and 14px/700. This level may be used with non-body text with a font no smaller than 15px/400. Also, Lc 75 should be considered a minimum for larger for any larger text where readability is important.
These are tough limitations for us considering information-dense widgets with small relatively small type, but no reason not to strive for contrast.
Human-grokable perceptually uniform way to define colors. It follows the pattern of HSL (Hue-Saturation-Lightness) with Lightness-Chroma (roughly equivalent to saturation) and Hue. This makes it neat for operations such as “hover color should be 5% brighter” or “dark mode colors should be 10% less saturated”.
It avoids bugs of HSL color space such as hue rotation (changing hue from 30 to 50 has drastically different visual results from 230 to 250):
… or non-matching visual lightness for different hues:
As a gross oversimplification that still works on the base level direction: we're inverting the background and foreground colors. This only applies to a larger groups and inside the small subgroups (e.g. --bg-accent
+ --bg-accent-hover
+ --bg-accent-pressed
) the applied direction should stay the same: hover becoming lighter to appear closer, and pressed becoming darker to imitate button going down with your press). This is based on human perception of depth:
Shadows shouldn't become white highlights when switching to dark mode:
General saturation / chroma should be lower for dark mode to account for the fact that dark backgrounds accentuate color perception.
Surrounding contrast may affect the perception. e.g. for a light
style button variant we want to use light and less saturated version of the picked color for background and dark version for the foreground. In dark mode the background color keeps the rule of being light, but the foreground does the opposite of that and goes lighter.
- High contrast mode
This generally can be driven by setting higher tolerance for our initial contrast checks, but also by applying higher ratios in derivative colors (e.g. all --color-foreground-onFOO
are X% lighter/darker in regular mode and X*N% ligher/darker in high contrast).