UNPKG

11.1 kBMarkdownView Raw
1# `@adobe/leonardo-contrast-colors`
2
3[![npm version](https://badge.fury.io/js/%40adobe%2Fleonardo-contrast-colors.svg)](https://badge.fury.io/js/%40adobe%2Fleonardo-contrast-colors)
4![Libraries.io dependency status for latest release, scoped npm package](https://img.shields.io/librariesio/release/npm/@adobe/leonardo-contrast-colors) [![license](https://img.shields.io/github/license/adobe/leonardo)](https://github.com/adobe/leonardo/blob/master/LICENSE) [![Pull requests welcome](https://img.shields.io/badge/PRs-welcome-blueviolet)](https://github.com/adobe/leonardo/blob/master/.github/CONTRIBUTING.md)
5
6This package contains all the functions for generating colors by target contrast ratio.
7
8## Using Leonardo Contrast Colors
9
10### Install the package:
11
12```
13npm i @adobe/leonardo-contrast-colors
14```
15
16### Import the package:
17
18#### CJS (Node 12.x)
19
20```js
21const { generateAdaptiveTheme } = require('@adobe/leonardo-contrast-colors');
22```
23
24#### ESM (Node 13.x)
25
26```js
27import { generateAdaptiveTheme } from '@adobe/leonardo-contrast-colors';
28```
29
30### Pass your colors and desired ratios (see additional options below):
31
32```js
33// returns theme colors as JSON
34let myTheme = generateAdaptiveTheme({
35 colorScales: [
36 {
37 name: 'gray',
38 colorKeys: ['#cacaca'],
39 ratios: {
40 'GRAY_LOW_CONTRAST': 2,
41 'GRAY_LARGE_TEXT': 3,
42 'GRAY_TEXT': 4.5,
43 'GRAY_HIGH_CONTRAST': 8
44 }
45 },
46 {
47 name: 'blue',
48 colorKeys: ['#5CDBFF', '#0000FF'],
49 ratios: {
50 'BLUE_LARGE_TEXT': 3,
51 'BLUE_TEXT': 4.5
52 }
53 },
54 {
55 name: 'red',
56 colorKeys: ['#FF9A81', '#FF0000'],
57 ratios: {
58 'RED_LARGE_TEXT': 3,
59 'RED_TEXT': 4.5
60 }
61 }
62 ],
63 baseScale: 'gray',
64 brightness: 97
65});
66```
67
68## API Reference
69
70### `generateAdaptiveTheme`
71
72Function used to create a fully adaptive contrast-based color palette/theme using Leonardo. Parameters are destructured and need to be explicitly called, such as `colorKeys: ["#f26322"]`. Parameters can be passed as a config JSON file for modularity and simplicity.
73
74```js
75generateAdaptiveTheme({colorScales, baseScale}); // returns function
76generateAdaptiveTheme({colorScales, baseScale, brightness}); // returns color objects
77```
78
79Returned function:
80```js
81myTheme(brightness, contrast);
82```
83
84#### `colorScales` *[array of objects]*:
85Each object contains the necessary parameters for [generating colors by contrast](#generateContrastColors) with the exception of the `name` and `ratios` parameter. For `generateAdaptiveTheme`, [ratios can be an array or an object](#ratios-array-or-object).
86
87Example of `colorScales` object with all options:
88
89```js
90 {
91 name: 'blue',
92 colorKeys: ['#5CDBFF', '#0000FF'],
93 colorSpace: 'LCH',
94 ratios: {
95 'blue--largeText': 3,
96 'blue--normalText': 4.5
97 }
98 }
99```
100
101#### `baseScale` *string (enum)*:
102String value matching the `name` of a `colorScales` object to be used as a [base scale](#generateBaseScale) (background color). This creates a scale of values from 0-100 in lightness, which is used for `brightness` parameter. Ie. `brightness: 90` returns the 90% lightness value of the base scale.
103
104#### `name` *string*:
105Unique name for each color scale. This value refers to the entire color group _(eg "blue")_ and will be used for the output color keys, ie `blue100: '#5CDBFF'`
106
107#### `ratios` *array* or *object*:
108List of numbers to be used as target contrast ratios. If entered as an array, swatch names are incremented in `100`s such as `blue100`, `blue200` based on the color scale [name](#name-string).
109
110Alternatively, `ratios` can be an object with custom keys to name each color, such as `['Blue_Large_Text', 'Blue_Normal_Text']`.
111
112#### `brightness` *number*:
113Optional value from 0-100 indicating the brightness of the base / background color. If undefined, `generateAdaptiveTheme` will return a function
114
115#### `contrast` *integer*:
116Optional value to increase contrast of your generated colors. This value is multiplied against all ratios defined for each color scale.
117
118#### `output` *string (enum)*:
119String value of the desired color space and output format for the generated colors. Output formats conform to the [W3C CSS Color Module Level 4](https://www.w3.org/TR/css-color-4/) spec for the supported options.
120
121| Output option | Sample value |
122|---------------|--------------|
123| `'HEX'` _(default)_ | `#RRGGBB` |
124| `'RGB'` | `rgb(255, 255, 255)` |
125| `'HSL'` | `hsl(360deg, 0%, 100%)` |
126| `'HSV'` | `hsv(360deg, 0%, 100%)` |
127| `'HSLuv'` | `hsluv(360, 0, 100)` |
128| `'LAB'` | `lab(100%, 0, 0)` |
129| `'LCH'` | `lch(100%, 0, 360deg)` |
130| `'CAM02'` | `jab(100%, 0, 0)`|
131| `'CAM02p'` | `jch(100%, 0, 360deg)` |
132
133
134#### Function outputs and examples
135The `generateAdaptiveTheme` function returns an array of color objects. Each key is named by concatenating the user-defined color name (above) with a numeric value.
136
137Colors with a **positive contrast ratio** with the base (ie, 2:1) will be named in increments of 100. For example, `gray100`, `gray200`.
138
139Colors with a **negative contrast ratio** with the base (ie -2:1) will be named in increments less than 100 and based on the number of negative values declared. For example, if there are 3 negative values `[-1.4, -1.3, -1.2, 1, 2, 3]`, the name for those values will be incremented by 100/4 (length plus one to avoid a `0` value), such as `gray25`, `gray50`, and `gray75`.
140
141Here is an example output from a theme:
142```js
143[
144 { background: "#e0e0e0" },
145 {
146 name: 'gray',
147 values: [
148 {name: "gray100", contrast: 1, value: "#e0e0e0"},
149 {name: "gray200", contrast: 2, value: "#a0a0a0"},
150 {name: "gray300", contrast: 3, value: "#808080"},
151 {name: "gray400", contrast: 4.5, value: "#646464"}
152 ]
153 },
154 {
155 name: 'blue',
156 values: [
157 {name: "blue100", contrast: 2, value: "#b18cff"},
158 {name: "blue200", contrast: 3, value: "#8d63ff"},
159 {name: "blue300", contrast: 4.5, value: "#623aff"},
160 {name: "blue400", contrast: 8, value: "#1c0ad1"}
161 ]
162 }
163]
164```
165
166#### Examples
167###### Creating your theme as a function
168```js
169let myPalette = {
170 colorScales: [
171 {
172 name: 'gray',
173 colorKeys: ['#cacaca'],
174 colorspace: 'HSL',
175 ratios: [1, 2, 3, 4.5, 8, 12]
176 },
177 {
178 name: 'blue',
179 colorKeys: ['#5CDBFF', '#0000FF'],
180 colorspace: 'HSL',
181 ratios: [3, 4.5]
182 },
183 {
184 name: 'red',
185 colorKeys: ['#FF9A81', '#FF0000'],
186 colorspace: 'HSL',
187 ratios: [3, 4.5]
188 }
189 ],
190 baseScale: 'gray'
191}
192
193let myTheme = generateAdaptiveTheme(myPalette);
194
195myTheme(95, 1.2) // outputs colors with background lightness of 95 and ratios increased by 1.2
196```
197
198###### Creating static instances of your theme
199```js
200// theme on light gray
201let lightTheme = generateAdaptiveTheme(95);
202
203// theme on dark gray with increased contrast
204let darkTheme = generateAdaptiveTheme(20, 1.3);
205```
206
207###### Assigning output to CSS properties
208```js
209let varPrefix = '--';
210
211// Iterate each color object
212for (let i = 0; i < myTheme.length; i++) {
213 // Iterate each value object within each color object
214 for(let j = 0; j < myTheme[i].values.length; j++) {
215 // output "name" of color and prefix
216 let key = myTheme[i].values[j].name;
217 let prop = varPrefix.concat(key);
218 // output value of color
219 let value = myTheme[i].values[j].value;
220 // create CSS property with name and value
221 document.documentElement.style
222 .setProperty(prop, value);
223 }
224}
225```
226
227### generateContrastColors
228
229Primary function used to generate colors based on target contrast ratios. Parameters are destructured and need to be explicitly called, such as `colorKeys: ["#f26322"]`.
230
231```js
232generateContrastColors({colorKeys, base, ratios, colorspace})
233```
234
235#### `colorKeys` *[array]*:
236List of colors referenced to generate a lightness scale. Much like [key frames](https://en.wikipedia.org/wiki/Key_frame), key colors are single points by which additional colors will be interpolated between.
237
238#### `base` *string*:
239References the color value that the color is to be generated from.
240
241#### `ratios` *[array]*:
242List of numbers to be used as target contrast ratios.
243
244#### `colorspace` *string*:
245The colorspace in which the key colors will be interpolated within. Below are the available options:
246
247- [LCH](https://en.wikipedia.org/wiki/HCL_color_space)
248- [LAB](https://en.wikipedia.org/wiki/CIELAB_color_space)
249- [CAM02](https://en.wikipedia.org/wiki/CIECAM02)
250- [HSL](https://en.wikipedia.org/wiki/HSL_and_HSV)
251- [HSLuv](https://en.wikipedia.org/wiki/HSLuv)
252- [HSV](https://en.wikipedia.org/wiki/HSL_and_HSV)
253- [RGB](https://en.wikipedia.org/wiki/RGB_color_space)
254
255### generateBaseScale
256
257This function is used to generate a color scale tailored specifically for use as a brightness scale when using Leonardo for brightness and contrast controls. Colors are generated that match HSLuv lightness values from `0` to `100` and are output as hex values.
258
259```js
260generateBaseScale({colorKeys, colorspace})
261```
262
263Only accepts **colorKeys** and **colorspace** parameters, as defined above for [`generateContrastColors`](#generateContrastColors)
264
265
266## Why are not all contrast ratios available?
267You may notice the tool takes an input (target ratio) but most often outputs a contrast ratio slightly higher. This has to do with the available colors in the RGB color space, and the math associated with calculating these ratios.
268
269For example let's look at blue and white.
270Blue: rgb(0, 0, 255)
271White: rgb(255, 255, 255)
272Contrast ratio: **8.59**:1
273
274If we change any one value in the RGB channel for either color, the ratio changes:
275Blue: rgb(0, **1**, 255)
276White: rgb(255, 255, 255)
277Contrast ratio: **8.57**:1
278
279If 8.58 is input as the target ratio with the starting color of blue, the output will not be exact. This is exaggerated by the various colorspace interpolations.
280
281Since the WCAG requirement is defined as a *minimum contrast requirement*, it should be fine to generate colors that are a little *more* accessible than the minimum.
282
283## D3 Color
284This project is currently built using [D3 color](https://github.com/d3/d3-color). Although functionality is comparable to [Chroma.js](https://gka.github.io/chroma.js/), the choice of D3 color is based on the additional modules available for state-of-the-art [color appearance models](https://en.wikipedia.org/wiki/Color_appearance_model), such as [CIE CAM02](https://gramaz.io/d3-cam02/).
285
286The `createScale()` function is basically a wrapper function for creating a d3 linear scale for colors, with a few enhancements that aid in the `generateContrastColors()` function.
287
288The Leonardo web app leverages d3 for additional features such as generating 2d and 3d charts.
289
290## Contributing
291Contributions are welcomed! Read the [Contributing Guide](../../.github/CONTRIBUTING.md) for more information.
292
293## Development
294
295You can run tests and watch for changes with:
296
297```sh
298yarn dev
299```
300
301## Licensing
302This project is licensed under the Apache V2 License. See [LICENSE](LICENSE) for more information.