Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Accessible by Law! Generating Colors with JS and CSS Custom Properties presentet at CSSConfEU 2018

3,329 views

Published on

In Norway, all websites are required by law to be accessible. That has inspired us rather than constrained us when building our video consultation service. How could we make it easy for users to pick their own brand color, and still make sure they had sufficient contrast? Combining CSS Custom Properties with a sprinkle of JavaScript we were able to create a color palette and components that also meet the WCAG criteria (and learned a lot on the way).

Published in: Environment
  • Be the first to comment

  • Be the first to like this

Accessible by Law! Generating Colors with JS and CSS Custom Properties presentet at CSSConfEU 2018

  1. 1. Accessible by law! Generating colors with JS and CSS Custom Properties Dag-Inge Aas @daginge Ida Aalen @idaaa
  2. 2. Inaccessible websites are illegal
 in Norway.
  3. 3. Unanimous support from parliament In effect since July 2014
  4. 4. Both public and private sector
  5. 5. Any main
 channel used to offer services or information
 to the general public
  6. 6. Based on the
 Web Content Accessibility Guidelines (WCAG) 2.0 level AA
  7. 7. A state agency makes random checks and publishes their reports online.
  8. 8. WCAG can make headlines in Norway
  9. 9. @daginge, CTO@idaaa, CPO
  10. 10. I run a website with info on pregnancy called
  11. 11. * Google translate
  12. 12. I would like to let people ask questions on video, too!
  13. 13. But if people can pick any color, what about the contrast?
  14. 14. @IngvildIndrebo sr. engineer @eivindmolvaer
 designer What if people could pick any color, and we’d just fix the accessibility? @daginge
 CTO @sventy CEO
  15. 15. 1.4.3 Contrast (Minimum): • The visual presentation of text and images of text has a contrast ratio of at least 4.5:1 (for large text, 3:1) • With WCAG 2.1, non-text elements like interface elements and icons must also have sufficient contrast (3:1).
  16. 16. Luminance of lighter color + 0.05 Luminance of darker color + 0.05 = Color Contrast k Color contrast defined. Every color has a “relative luminance”, from 0 (black) to 1 (white).
  17. 17. Luminance of yellow + 0.05 Luminance of black + 0.05 = Color Contrast I’m a yellow button
  18. 18. = 12.4 0.572 + 0.05 0 + 0.05 = I’m a yellow button > 4.5
  19. 19. I’m a yellow button Contrast: 12.4 > 4.5
  20. 20. I’m a dark blue button Contrast: 1.7 < 4.5
  21. 21. I’m a dark blue button Contrast: 12.2 > 4.5
  22. 22. I’m a grey button Contrast: 4.6 > 4.5
  23. 23. I’m a grey button Contrast: 4.6 > 4.5
  24. 24. I’m a grey button I’m a yellow button I’m a dark blue button I’m a grey button
  25. 25. What if
 we could do math on
 colors? There’s an npm package for that!
  26. 26. npm install color • Manipulate and convert colors • Rotation, mixing, lightness • Test WCAG color contrast and more
  27. 27. CSS Custom properties • Allows you to define variables in CSS • Can re-use color definitions and more throughout stylesheet • Is cascading and can be overwritten
  28. 28. CSS Custom properties body { --color-primary: #ffbc00; background-color: var(--color-primary); }
  29. 29. Set properties from JavaScript document.body.style.setProperty(
 "--color-primary",
 "tomato"
 );
  30. 30. Calculating colors import Color from "color";
  31. 31. Calculating colors import Color from "color";
 const primaryColor = Color("#ffbc00");
  32. 32. Calculating colors import Color from "color";
 const primaryColor = Color("#ffbc00"); const primaryColorContrast = primaryColor.light()
 ? Color("black")
 : Color("white");
  33. 33. Calculating colors document.body.style.setProperty(
 "--color-primary",
 primaryColor.string()
 );
 document.body.style.setProperty(
 "--color-primary-contrast",
 primaryColorContrast.string()
 );
  34. 34. Applying the color to our class .button { background-color: var(--color-primary); color: var(--color-primary-contrast); }
  35. 35. I’m a grey button I’m a yellow button I’m a dark blue button I’m a grey button
  36. 36. I’m a grey button I’m a yellow button I’m a light blue button I’m a pink button
  37. 37. I’m a grey button I’m a yellow button I’m a light blue button I’m a pink button
  38. 38. I’m a grey button I’m a yellow button I’m a light blue button I’m a pink button
  39. 39. Maybe if we mix in black? Well… How would you make a darker color in real life?
  40. 40. Generating a darker color function getValidatedColor({ colorToChange, colorToValidate = Color("white"), minimumContrastRatio = 4.5, mixingAmount = 0.5, mixingColor = Color("black"), }) {…}
  41. 41. Generating a darker color function getValidatedColor({…}){
  42. 42. Generating a darker color function getValidatedColor({…}){ const newColor = colorToChange.mix(mixingColor, mixingAmount);

  43. 43. Generating a darker color function getValidatedColor({…}){ const newColor = colorToChange.mix(mixingColor, mixingAmount);
 if (newColor.contrast(colorToValidate) < minimumContrastRatio) {

  44. 44. Generating a darker color function getValidatedColor({…}){ const newColor = colorToChange.mix(mixingColor, mixingAmount);
 if (newColor.contrast(colorToValidate) < minimumContrastRatio) { return getValidatedColor({
 colorToChange: newColor,
 mixingAmount: 0.1,
 });
 }

  45. 45. Generating a darker color function getValidatedColor({…}){ const newColor = colorToChange.mix(mixingColor, mixingAmount);
 if (newColor.contrast(colorToValidate) < minimumContrastRatio) { return getValidatedColor({
 colorToChange: newColor,
 mixingAmount: 0.1,
 });
 }
 return newColor;
 }
  46. 46. Generating a darker color const primaryColorDark = getValidatedColor({
 colorToChange: primaryColor,
 mixingColor: Color("black"),
 colorToValidate: Color("white"),
 });
 document.body.style.setProperty(
 "—-color-primary-dark",
 primaryColorDark.string()
 );
  47. 47. Adding button border
  48. 48. Adding button border body { --button-border: none; } .button { border: var(--button-border); }
  49. 49. Adding button border if (primaryColor.contrast(Color("white")) < 4.5) {
  50. 50. Adding button border if (primaryColor.contrast(Color("white")) < 4.5) { document.body.style.setProperty( "--button-border", "2px solid var(--color-primary-dark)", ); }
  51. 51. Brand #3Brand #3 Brand #2Brand #2 Generated palettes! Brand #1
  52. 52. But what about secondary colors? And I’m not sure how we make that user- friendly…
  53. 53. Ideally, the secondary color fits with the brand color, but should also stand out.
  54. 54. But where’s the math in that?
  55. 55. HSL color Hue A degree from 0 to 360 Saturation 0% is a shade of gray, 100% is the full color Lightness 0% is black, 100% is white
  56. 56. What if we rotate the hue? 0˚ = red 60˚ = yellow primary color secondary color
  57. 57. Secondary color using hue rotation const secondaryColor = primaryColor.rotate(60); document.body.style.setProperty(
 "--color-secondary",
 secondaryColor.string()
 );
  58. 58. Bringing it all together in a theme engine. • Create a React component called Theme • Takes the prop brandColor, and calculates all other colors • Do not hardcode, always use CSS Custom properties • Single stylesheet, infinitely brandable
  59. 59. Using the theme component function render() { return ( <Theme brandColor="#ffbc00"> <App /> </Theme> ); }
  60. 60. You can
 pick any color you’d like!
  61. 61. Demo & resources: confrere.com/a11y
  62. 62. Accessibility
 is never finished.
  63. 63. Accessibility
 is a team effort.
  64. 64. Accessibility
 isn’t a deterrent.
  65. 65. Accessibility
 can simply be fun.
  66. 66. Demo & resources: confrere.com/a11y
  67. 67. Thank you! confrere.com/a11y @daginge @sventy @idaaa @IngvildIndrebo

×