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 |
|
6 | This 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 | ```
|
13 | npm i @adobe/leonardo-contrast-colors
|
14 | ```
|
15 |
|
16 | ### Import the package:
|
17 |
|
18 | #### CJS (Node 12.x)
|
19 |
|
20 | ```js
|
21 | const { generateAdaptiveTheme } = require('@adobe/leonardo-contrast-colors');
|
22 | ```
|
23 |
|
24 | #### ESM (Node 13.x)
|
25 |
|
26 | ```js
|
27 | import { 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
|
34 | let 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 |
|
72 | Function 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
|
75 | generateAdaptiveTheme({colorScales, baseScale}); // returns function
|
76 | generateAdaptiveTheme({colorScales, baseScale, brightness}); // returns color objects
|
77 | ```
|
78 |
|
79 | Returned function:
|
80 | ```js
|
81 | myTheme(brightness, contrast);
|
82 | ```
|
83 |
|
84 | #### `colorScales` *[array of objects]*:
|
85 | Each 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 |
|
87 | Example 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)*:
|
102 | String 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*:
|
105 | Unique 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*:
|
108 | List 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 |
|
110 | Alternatively, `ratios` can be an object with custom keys to name each color, such as `['Blue_Large_Text', 'Blue_Normal_Text']`.
|
111 |
|
112 | #### `brightness` *number*:
|
113 | Optional value from 0-100 indicating the brightness of the base / background color. If undefined, `generateAdaptiveTheme` will return a function
|
114 |
|
115 | #### `contrast` *integer*:
|
116 | Optional 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)*:
|
119 | String 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
|
135 | The `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 |
|
137 | Colors with a **positive contrast ratio** with the base (ie, 2:1) will be named in increments of 100. For example, `gray100`, `gray200`.
|
138 |
|
139 | Colors 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 |
|
141 | Here 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
|
169 | let 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 |
|
193 | let myTheme = generateAdaptiveTheme(myPalette);
|
194 |
|
195 | myTheme(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
|
201 | let lightTheme = generateAdaptiveTheme(95);
|
202 |
|
203 | // theme on dark gray with increased contrast
|
204 | let darkTheme = generateAdaptiveTheme(20, 1.3);
|
205 | ```
|
206 |
|
207 | ###### Assigning output to CSS properties
|
208 | ```js
|
209 | let varPrefix = '--';
|
210 |
|
211 | // Iterate each color object
|
212 | for (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 |
|
229 | Primary 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
|
232 | generateContrastColors({colorKeys, base, ratios, colorspace})
|
233 | ```
|
234 |
|
235 | #### `colorKeys` *[array]*:
|
236 | List 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*:
|
239 | References the color value that the color is to be generated from.
|
240 |
|
241 | #### `ratios` *[array]*:
|
242 | List of numbers to be used as target contrast ratios.
|
243 |
|
244 | #### `colorspace` *string*:
|
245 | The 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 |
|
257 | This 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
|
260 | generateBaseScale({colorKeys, colorspace})
|
261 | ```
|
262 |
|
263 | Only accepts **colorKeys** and **colorspace** parameters, as defined above for [`generateContrastColors`](#generateContrastColors)
|
264 |
|
265 |
|
266 | ## Why are not all contrast ratios available?
|
267 | You 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 |
|
269 | For example let's look at blue and white.
|
270 | Blue: rgb(0, 0, 255)
|
271 | White: rgb(255, 255, 255)
|
272 | Contrast ratio: **8.59**:1
|
273 |
|
274 | If we change any one value in the RGB channel for either color, the ratio changes:
|
275 | Blue: rgb(0, **1**, 255)
|
276 | White: rgb(255, 255, 255)
|
277 | Contrast ratio: **8.57**:1
|
278 |
|
279 | If 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 |
|
281 | Since 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
|
284 | This 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 |
|
286 | The `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 |
|
288 | The Leonardo web app leverages d3 for additional features such as generating 2d and 3d charts.
|
289 |
|
290 | ## Contributing
|
291 | Contributions are welcomed! Read the [Contributing Guide](../../.github/CONTRIBUTING.md) for more information.
|
292 |
|
293 | ## Development
|
294 |
|
295 | You can run tests and watch for changes with:
|
296 |
|
297 | ```sh
|
298 | yarn dev
|
299 | ```
|
300 |
|
301 | ## Licensing
|
302 | This project is licensed under the Apache V2 License. See [LICENSE](LICENSE) for more information.
|