diff --git a/content/practices/high-contrast/css/switch-color-scheme.css b/content/practices/high-contrast/css/switch-color-scheme.css new file mode 100644 index 0000000000..3cb618dde0 --- /dev/null +++ b/content/practices/high-contrast/css/switch-color-scheme.css @@ -0,0 +1,87 @@ +:root { + color-scheme: light dark; +} + +button.color-scheme[role="switch"] { + display: block; + margin: 2px; + padding: 4px 4px 8px 8px; + border: 0 solid light-dark(#005a9c, #add8e6); + border-radius: 5px; + width: 17em; + height: 3em; + text-align: left; + background-color: light-dark(#e9e9e9, #333); + color: light-dark(#242424, #fff); +} + +button.color-scheme[role="switch"] .label { + position: relative; + top: -3px; + display: inline-block; + padding: 0; + margin: 0; + width: 10em; + vertical-align: middle; + color: light-dark(#242424, #fff); +} + +button.color-scheme[role="switch"] svg { + display: inline-block; + width: 36px; + height: 20px; + position: relative; + top: 4px; +} + +button.color-scheme[role="switch"] svg rect { + fill: light-dark(#a1a1a1, #36c); + stroke-width: 2; + stroke: light-dark(#757575, #36c); +} + +button.color-scheme[role="switch"] svg circle.off { + display: block; + stroke: light-dark(#757575, #fff); + fill: light-dark(#fff, #fff); + fill-opacity: 1; +} + +button.color-scheme[role="switch"] svg circle.on { + display: none; +} + +button.color-scheme[role="switch"][aria-checked="true"] svg circle.off { + display: none; +} + +button.color-scheme[role="switch"][aria-checked="true"] svg circle.on { + display: block; + stroke: #fff; + fill: #fff; + fill-opacity: 1; +} + +button.color-scheme[role="switch"] span.off { + display: inline-block; +} + +button.color-scheme[role="switch"] span.on { + display: none; +} + +button.color-scheme[role="switch"][aria-checked="true"] span.off { + display: none; +} + +button.color-scheme[role="switch"][aria-checked="true"] span.on { + display: inline-block; +} + +button.color-scheme[role="switch"]:focus, +button.color-scheme[role="switch"]:hover { + padding: 2px 2px 6px 6px; + border-width: 2px; + outline: none; + cursor: pointer; +} diff --git a/content/practices/high-contrast/css/switch-increase-contrast.css b/content/practices/high-contrast/css/switch-increase-contrast.css new file mode 100644 index 0000000000..acee9d2592 --- /dev/null +++ b/content/practices/high-contrast/css/switch-increase-contrast.css @@ -0,0 +1,105 @@ +button.increase-contrast[role="switch"] { + display: block; + margin: 2px; + padding: 4px 4px 8px 8px; + border: 0 solid #005a9c; + border-radius: 5px; + width: 17em; + height: 3em; + text-align: left; + background-color: #e9e9e9; + color: #242424; +} + +button.increase-contrast[role="switch"] .label { + position: relative; + top: -3px; + display: inline-block; + padding: 0; + margin: 0; + width: 10em; + vertical-align: middle; + color: #242424; +} + +button.increase-contrast[role="switch"] svg { + display: inline-block; + width: 36px; + height: 20px; + position: relative; + top: 4px; +} + +button.increase-contrast[role="switch"] svg rect { + fill: #a1a1a1; + stroke-width: 2; + stroke: #757575; +} + +button.increase-contrast[role="switch"] svg circle.off { + display: block; + stroke: #757575; + fill: #fff; + fill-opacity: 1; +} + +button.increase-contrast[role="switch"] svg circle.on { + display: none; +} + +button.increase-contrast[role="switch"][aria-checked="true"] svg circle.off { + display: none; +} + +button.increase-contrast[role="switch"][aria-checked="true"] svg circle.on { + display: block; + stroke: #061d3a; + fill: #fff; + fill-opacity: 1; +} + +button.increase-contrast[role="switch"] span.off { + display: inline-block; +} + +button.increase-contrast[role="switch"] span.on { + display: none; +} + +button.increase-contrast[role="switch"][aria-checked="true"] span.off { + display: none; +} + +button.increase-contrast[role="switch"][aria-checked="true"] span.on { + display: inline-block; +} + +button.increase-contrast[role="switch"]:focus, +button.increase-contrast[role="switch"]:hover { + padding: 2px 2px 6px 6px; + border-width: 2px; + outline: none; + cursor: pointer; +} + +@media (prefers-contrast: more) { + button.increase-contrast[role="switch"] { + background-color: #eee; + color: #000; + } + + button.increase-contrast[role="switch"] .label { + color: #000; + } + + button.increase-contrast[role="switch"] svg rect { + fill: #0051a4; + stroke: #061d3a; + } + + button.increase-contrast[role="switch"] svg circle.off, + button.increase-contrast[role="switch"] svg circle.on { + stroke: #061d3a; + fill: #fff; + } +} diff --git a/content/practices/high-contrast/high-contrast-practice.html b/content/practices/high-contrast/high-contrast-practice.html new file mode 100644 index 0000000000..c9163de2da --- /dev/null +++ b/content/practices/high-contrast/high-contrast-practice.html @@ -0,0 +1,814 @@ + + + + + + Supporting High Contrast Settings + + + + + + + + + + + + + + + +
+

Supporting High Contrast Settings

+ +
+

Introduction

+

+ Some people with + visual disabilities using the web + need more than the + required default minimum color contrast + to perceive content. + Operating systems provide settings that enable those users to increase contrast and choose alternate color themes. + Web authors can ensure their content is accessible to those users by appropriately responding to such operating system settings. + This section explains how to make components responsive to color and contrast settings and how to test support for those settings. +

+ +

This section covers:

+
    +
  1. Operating system and user agent features that enable users to adjust rendered colors and contrast ratios.
  2. +
  3. Using the CSS media queries that support user color and contrast settings (prefers-contrast, prefers-color-scheme, and forced-colors).
  4. +
  5. Using <system-colors> CSS data types to provide consistent rendering of components.
  6. +
  7. Using the value of currentcolor to inherit the value of the color property value of text content that responds to user color and contrast settings.
  8. +
  9. The benefits of using SVG graphics when creating components that adapt to color contrast and theme settings.
  10. +
+
+ +
+

User Options for Adjusting Colors and Contrast

+

The following table summarizes operating system settings that enable users to adjust color themes and increase contrast as well as authoring practices for supporting those settings in web content.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operating System Contrast Adjustment Features
FeatureOSDescriptionAuthoring Practices
Invert Colors + + +

+ Invert colors transforms colors by subtracting each RGB value from 255. + This is a simple way of turning a light color theme into a dark color theme or vice-versa. + It is a prominent feature in the accessibility settings of most operating systems. +

+

Examples of color inversion:

+
    +
  • rgb(255, 255, 255) is rendered as rgb(0, 0, 0)
  • +
  • rgb(165, 42, 42) is rendered as rgb(90, 213, 213)
  • +
  • rgb(220, 220, 220) is rendered as rgb(35, 35, 35)
  • +
+
+ Browsers do not provide a way for authors to determine whether a user has the setting for invert colors enabled. + For invert colors to work well, ensure content meets the minimum color requirements specified by + Web Content Accessibility Guidelines (WCAG). +
Increase contrast + + + Specifies that the user prefers contrast that is stronger than the default minimum. + Each operating system has its own approach to supporting this setting; there is no standard that specifies how much contrast should be increased when this setting is enabled. + A reasonable target for web content is specified by + WCAG 1.4.6: Contrast (Enhanced). + + When this setting is enabled, the CSS media query prefers-contrast is set to more. + Develop a higher contrast color scheme and use this media query to determine when to enable it. + This can also include switching to use system-colors CSS media types. +
+ Color Scheme
+ (AKA Light Mode and Dark Mode) +
+ + + Operating systems support light and dark color schemes. + They typically default to the light color scheme. + Many people switch to the dark color scheme in dark settings, e.g. at night, because it can make content easier to read or be less disruptive to other people. + However, people with certain visual disabilities prefer a dark color scheme as their default. + + The CSS media query prefers-color-scheme identifies the current color scheme by returning light or dark. + Develop styles for dark text on a light background and light text on a dark background and use this media query to apply the appropriate style. + Ensure the text content and components for both settings meet + WCAG 1.4.3: Contrast (Minimum). +
+ Contrast Themes
+ (AKA High Contrast Mode) +
Windows 10 and later. + This accessibility feature provides extra high contrast and user customizable color themes. + + When a user selects a high contrast color theme, the CSS media query forced-colors is set to active. + Use currentcolor and system-color values to style user interface controls and custom widgets to the user preferences. +
+
+ +
+

Invert Colors

+

+ The invert colors setting is a simple transformation that renders content to its opposite color. + For example, content rendered as white is changed to black. + Content styled as blue is rendered as a brown, i.e., a mixture of red and green. + User agents do not provide a media query that can determine whether invert colors is enabled in the operating system. +

+

+ To support invert colors effectively, ensure content meets + WCAG 1.4.3: Contrast (Minimum). +

+

+ The following example illustrates how a switch element is rendered on macOS both when invert colors is disabled and enabled. +

+ + + + + + + + + + + + + + + + + + +
Invert Colors Example: Button Switch
SettingScreen Shot
Invert Colors: Off (default)Screen shot of switch example with invert colors turned off
Invert Colors: onScreen shot of switch example with invert colors turned on
+
+ +
+

Increase Contrast

+

+ Increase contrast is an operating system feature, typically available in accessibility settings, that enables users to specify a preference for contrast that is higher than default minimum. + When the increase contrast setting is enabled, the prefers-contrast media query changes from no-preference to more. + To support the increase contrast setting, change the rendering of text content and components to use a color scheme that meets or exceeds the requirements specified in + WCAG 1.4.6: Contrast (Enhanced). +

+

Note: Operating systems that support the forced-colors media query set prefers-contrast to custom when the forced-colors is set to active.

+

Increase Contrast Example

+

Enable the "increased contrast" feature on your device, and color contrast ratios in the below example will change:

+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Increase Contrast Example Color Changes
prefers-contrastTextButton
BGTextCCRBGFillCCR
no-preference + + #e9e9e9 + + + #242424 + 12.8 + + #a1a1a1 + + + #fff + 4.6
+ more + + + #eeeeee + + + #000000 + 18.1 + + #0051A4 + + + #fff + 12.2
+ +

CSS Media Query Code

+ +
+          
+  @media (prefers-contrast: more) {
+
+    button[role="switch"] {
+      background-color: #eeeeee;
+      color: #000;
+    }
+
+    button[role="switch"] .label {
+      color: #000;
+    }
+
+    button[role="switch"] svg rect {
+      fill: #0051A4;
+      stroke: #061d3a;
+    }
+
+    button[role="switch"] svg circle.off,
+    button[role="switch"] svg circle.on {
+      stroke: #061d3a;
+      fill: #fff;
+    }
+  }
+          
+        
+ +

Testing Increase Contrast

+

In each operating system used by the target audience:

+
    +
  1. Turn on the increase contrast feature, which is typically located in accessibility settings.
  2. +
  3. + Verify that the color contrast ratios of text and components meets or exceeds the requirements specified by + WCAG 1.4.6: Contrast (Enhanced). +
  4. +
+ +
+ +
+

Color Scheme (Light or Dark)

+

+ The color scheme known as dark mode is used by Many people in dark settings, e.g. at night, because it can make content easier to read or be less disruptive to other people. + While such use cases were primary drivers of its development, dark mode also significantly improves accessibility for many people with visual impairments. +

+

+ To support dark mode, develop styles for dark text on a light background and light text on a dark background and use a media query to apply the appropriate style. + The CSS media query prefers-color-scheme identifies the current color scheme by returning light or dark. Browsers support the prefers-color-scheme media query using the light-dark function to identify a color value for a CSS property. +

+

+ Ensure the text content and components of both color schemes meet or exceed the color contrast ratios specified by + WCAG 1.4.3: Contrast (Minimum). +

+

Color Scheme Example: Switch

+

+ The below example of a switch shows how colors can change when users switch color schemes. + Enable "dark mode" on your device, and the example will be rendered with the dark color scheme. +

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Color Scheme Changes
+ prefers-color-scheme + TextButton
BGTextCCRBGFillCCR
light + + #e9e9e9 + + + #242424 + 12.8 + + #a1a1a1 + + + #fff + 4.6
+ dark + + + #333 + + + #fff + 12.6 + + #36c + + + #fff + 5.36
+ +

CSS Media Query Code

+ +
+          
+:root {
+  color-scheme: light dark;
+}
+
+button.color-scheme[role="switch"] {
+  display: block;
+  margin: 2px;
+  padding: 4px 4px 8px 8px;
+  border: 0 solid light-dark(#005a9c, #add8e6);
+  border-radius: 5px;
+  width: 17em;
+  height: 3em;
+  text-align: left;
+  background-color: light-dark(#e9e9e9, #333);
+  color: light-dark(#242424, #fff);
+}
+
+button.color-scheme[role="switch"] .label {
+  position: relative;
+  top: -3px;
+  display: inline-block;
+  padding: 0;
+  margin: 0;
+  width: 10em;
+  vertical-align: middle;
+  color: light-dark(#242424, #fff);
+}
+
+....
+
+button.color-scheme[role="switch"] svg rect {
+  fill: light-dark(#a1a1a1, #36c);
+  stroke-width: 2;
+  stroke: light-dark(#757575, #36c);
+}
+
+button.color-scheme[role="switch"] svg circle.off {
+  display: block;
+  stroke: light-dark(#757575, #fff);
+  fill: light-dark(#fff, #fff);
+  fill-opacity: 1;
+}
+
+....
+          
+        
+ +

Color Scheme Example: Wikipedia Page

+ +

The following example illustrates how Wikipedia supports the color scheme media query. The example includes showing the "Appearance" sidebar allowing the user to choose the light or dark scheme and other rendering options for text size and column width.

+ + + + + + + + + + + + + + + + + + +
Media QueryScreen Shot
+ prefers-color-scheme: light + + Screen shot of wikipedia page with user preferences sidebar open.  The red circle shows the users settings radio button for light settings checked. +
+ prefers-color-scheme: dark + + Screen shot of wikipedia page with user preferences sidebar open.  The red circle shows the users settings radio button for dark settings checked. +
+ +

Testing Dark Color Scheme

+

In each operating system used by the target audience:

+
    +
  1. Turn on the dark color theme.
  2. +
  3. + Verify contrast for text and components meet or exceed the contrast ratios specified by + WCAG 1.4.2: Contrast (Minimum). +
  4. +
+
+ +
+

Contrast Themes (Forced Colors)

+ +

The forced-colors CSS media query provides a means for components to use the color preferences of people with visual impairments. When the user chooses a color theme in their operating system, browsers set the forced-colors property to active. CSS media queries can change component colors to use operating system specified values using <system-colors> CSS data types. The advantage of using forced-colors over currentcolor is the ability to set a background color and to uniquely define colors for borders, outlines and text content.

+ +

System Colors

+ +

The following table identifies the current system colors defined in CSS Color Module Level 4. System colors are supported in all major browsers, but the actual colors they render may vary between browsers and operating systems based on default and user theme and contrast settings.

+ + + + + + + + + + + + +
System ColorComputed SampleComputed ColorDescription
+ +

System Color Example: Rating Slider

+ +

The Rating Slider Example uses CSS forced-colors: active media query to change the styling of SVG elements used for the rating scale, thumb and labels. The buttontext system color value is used for stroke and fill properties of the range and thumb elements and canvas system color is used for the label elements (e.g. "Extremely Unsatisfied" and "Extremely Satisfied"). The following table shows how the graphical rendering changes for some high contrast options.

+ +

The buttontext system color value was chosen so the interactive slider elements would match the colors of other standard form controls on the page. The canvas system color was chosen for the labels to match other static text on the page. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rating Slider Example with Selected High Contrast User Settings
Operating SystemSettingScreen Shot
macOS 14.4Invert Colors: Off (default) + Screen shot of switch example with invert colors turned off +
macOS 14.4Invert Colors: on + Screen shot of switch example with invert colors turned on +
Windows 11Contrast Theme: none (default) + Screen shot of switch example with no contrast theme applied +
Windows 11Contrast Theme: Night sky + Screen shot of switch example with night sky contrast theme applied +
Windows 11Contrast Theme: Desert + Screen shot of switch example with desert contrast theme applied +
+ +

Examples in using forced-colors

+ + +

currentcolor Keyword

+ +

The currentcolor keyword provides a means for components to use the color value of ancestors to set the color properties of an element. When the user chooses a high contrast setting the browser changes the color and background-color values of text content. The currentcolor value is set to the text color for use in setting the color of other properties including: border and outline on HTML elements, and stroke and fill properties on SVG elements. Note: There is no equivalent value for using the background color, so when using this technique it is important for the background of the element to be transparent to allow the background color of the page to be visible.

+ +

Current Color Example: Switch

+ +

The Button Switch Example uses currentcolor value to style the SVG rect elements used as the switch container and to indicate the on and off states. Current color applied to the stroke and fill properties of the rect elements. The following table shows how the graphical rendering changes for some high contrast options.

+ + + + + + + + + + + + + + + + + + + + + + + +
Button Switch Example with Selected High Contrast User Settings in Windows 11
SettingScreen Shot
Contrast Theme: none (default)Screen shot of switch example with no contrast theme applied
Contrast Theme: Night skyScreen shot of switch example with night sky contrast theme applied
Contrast Theme: DesertScreen shot of switch example with desert contrast theme applied
+ +

Examples using currentcolor keyword

+ +
+ +
+

SVG Graphics versus Bit-Mapped Images for Components

+ +

Limitations of Bit-Mapped Images

+ +

The colors of pixels used in bit-mapped images (e.g. .png, .jpeg) can respond to media queries by changing the actual image rendered or by applying a CSS filter to the image. Even when one or more of these techniques are used to respond to changes in contrast settings the resulting images may still be difficult or impossible for people with some types of visual impairments to see. Low resolution images also do not scale smoothly when the browser zoom features are used to increase the size of rendered content and the resulting distortion will make it more difficult or impossible for people to identify the component.

+ +

Note: Bit-mapped images used for components should meet WCAG 1.4.3: Contrast (Minimum) requirement.

+ +

Benefits of SVG Graphics

+ +

SVG graphics can respond to contrast related media queries including prefers-contrast, prefers-color-scheme and forced-colors to change the styling of components. SVG provides smooth scaling of the graphics as the size of components are adjusted using browser zoom features. SVG elements can also adapt to a wide variety of screen sizes and load faster due to their smaller size than equivalent bit-mapped images.

+ +

Note: Be sure to include forced-color-adjust=auto CSS property on SVG elements, due to inconsistencies in browsers setting the default value to auto.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Summary of SVG vs. Bit-Mapped Features
FeatureBit-MappedSVG
Scale to Screen SizeNoYes
Smooth ZoomingDistortionYes
Color Changes using Media QueriesImage substitution or CSS filtersYes
+ +
+ +
+

Testing for Contrast Theme Support

+ +

High contrast testing requires setting operating system contrast features or using browser extensions or configuration to emulate high contrast.

+ +

Operating System High Contrast Settings

+ + + +

Chrome High Contrast Options

+ +

The Chrome browser has Render options in the DOM Inspector to enable and disable contrast related media queries. Use the DOM Inspector Render Tab: Emulate and you can change the setting for prefers-color-scheme: dark and forced-colors: active. +

+
+ + + +
+ + diff --git a/content/practices/high-contrast/images/currentcolor-macos-invert-off.png b/content/practices/high-contrast/images/currentcolor-macos-invert-off.png new file mode 100644 index 0000000000..f49cf894be Binary files /dev/null and b/content/practices/high-contrast/images/currentcolor-macos-invert-off.png differ diff --git a/content/practices/high-contrast/images/currentcolor-macos-invert-on.png b/content/practices/high-contrast/images/currentcolor-macos-invert-on.png new file mode 100644 index 0000000000..f7a5d5f308 Binary files /dev/null and b/content/practices/high-contrast/images/currentcolor-macos-invert-on.png differ diff --git a/content/practices/high-contrast/images/currentcolor-windows11-theme-desert.png b/content/practices/high-contrast/images/currentcolor-windows11-theme-desert.png new file mode 100644 index 0000000000..0b75f86d12 Binary files /dev/null and b/content/practices/high-contrast/images/currentcolor-windows11-theme-desert.png differ diff --git a/content/practices/high-contrast/images/currentcolor-windows11-theme-night-sky.png b/content/practices/high-contrast/images/currentcolor-windows11-theme-night-sky.png new file mode 100644 index 0000000000..705fe8b22d Binary files /dev/null and b/content/practices/high-contrast/images/currentcolor-windows11-theme-night-sky.png differ diff --git a/content/practices/high-contrast/images/currentcolor-windows11-theme-none.png b/content/practices/high-contrast/images/currentcolor-windows11-theme-none.png new file mode 100644 index 0000000000..a4896dfcce Binary files /dev/null and b/content/practices/high-contrast/images/currentcolor-windows11-theme-none.png differ diff --git a/content/practices/high-contrast/images/forced-colors-macos-invert-off.png b/content/practices/high-contrast/images/forced-colors-macos-invert-off.png new file mode 100644 index 0000000000..ed23a81b5a Binary files /dev/null and b/content/practices/high-contrast/images/forced-colors-macos-invert-off.png differ diff --git a/content/practices/high-contrast/images/forced-colors-macos-invert-on.png b/content/practices/high-contrast/images/forced-colors-macos-invert-on.png new file mode 100644 index 0000000000..b3a67abafa Binary files /dev/null and b/content/practices/high-contrast/images/forced-colors-macos-invert-on.png differ diff --git a/content/practices/high-contrast/images/forced-colors-windows11-theme-desert.png b/content/practices/high-contrast/images/forced-colors-windows11-theme-desert.png new file mode 100644 index 0000000000..d7f7331d05 Binary files /dev/null and b/content/practices/high-contrast/images/forced-colors-windows11-theme-desert.png differ diff --git a/content/practices/high-contrast/images/forced-colors-windows11-theme-night-sky.png b/content/practices/high-contrast/images/forced-colors-windows11-theme-night-sky.png new file mode 100644 index 0000000000..ce542a870e Binary files /dev/null and b/content/practices/high-contrast/images/forced-colors-windows11-theme-night-sky.png differ diff --git a/content/practices/high-contrast/images/forced-colors-windows11-theme-none.png b/content/practices/high-contrast/images/forced-colors-windows11-theme-none.png new file mode 100644 index 0000000000..c219adb021 Binary files /dev/null and b/content/practices/high-contrast/images/forced-colors-windows11-theme-none.png differ diff --git a/content/practices/high-contrast/images/wikipedia-scheme-dark.png b/content/practices/high-contrast/images/wikipedia-scheme-dark.png new file mode 100644 index 0000000000..df2c55c102 Binary files /dev/null and b/content/practices/high-contrast/images/wikipedia-scheme-dark.png differ diff --git a/content/practices/high-contrast/images/wikipedia-scheme-light.png b/content/practices/high-contrast/images/wikipedia-scheme-light.png new file mode 100644 index 0000000000..60c4819d8f Binary files /dev/null and b/content/practices/high-contrast/images/wikipedia-scheme-light.png differ diff --git a/content/practices/high-contrast/js/high-contrast-practice.js b/content/practices/high-contrast/js/high-contrast-practice.js new file mode 100644 index 0000000000..142257cf26 --- /dev/null +++ b/content/practices/high-contrast/js/high-contrast-practice.js @@ -0,0 +1,844 @@ +/* high-contrast.js */ + +'use strict'; + +const htmlColorValues = [ + { + name: 'INDIAN RED', + hex: '#CD5C5C', + }, + { + name: 'LIGHT CORAL', + hex: '#F08080', + }, + { + name: 'SALMON', + hex: '#FA8072', + }, + { + name: 'DARK SALMON', + hex: '#E9967A', + }, + { + name: 'LIGHT SALMON', + hex: '#FFA07A', + }, + { + name: 'CRIMSON', + hex: '#DC143C', + }, + { + name: 'RED', + hex: '#FF0000', + }, + { + name: 'DARK RED', + hex: '#8B0000', + }, + { + name: 'PINK', + hex: '#FFC0CB', + }, + { + name: 'LIGHT PINK', + hex: '#FFB6C1', + }, + { + name: 'HOT PINK', + hex: '#FF69B4', + }, + { + name: 'DEEP PINK', + hex: '#FF1493', + }, + { + name: 'MEDIUM VIOLET RED', + hex: '#C71585', + }, + { + name: 'PALE VIOLET RED', + hex: '#DB7093', + }, + { + name: 'CORAL', + hex: '#FF7F50', + }, + { + name: 'TOMATO', + hex: '#FF6347', + }, + { + name: 'ORANGE RED', + hex: '#FF4500', + }, + { + name: 'DARK ORANGE', + hex: '#FF8C00', + }, + { + name: 'ORANGE', + hex: '#FFA500', + }, + { + name: 'GOLD', + hex: '#FFD700', + }, + { + name: 'YELLOW', + hex: '#FFFF00', + }, + { + name: 'LIGHT YELLOW', + hex: '#FFFFE0', + }, + { + name: 'LEMON CHIFFON', + hex: '#FFFACD', + }, + { + name: 'LIGHT GOLDEN ROD YELLOW', + hex: '#FAFAD2', + }, + { + name: 'PAPAYAWHIP', + hex: '#FFEFD5', + }, + { + name: 'MOCCASIN', + hex: '#FFE4B5', + }, + { + name: 'PEACH PUFF', + hex: '#FFDAB9', + }, + { + name: 'PALE GOLDEN ROD', + hex: '#EEE8AA', + }, + { + name: 'KHAKI', + hex: '#F0E68C', + }, + { + name: 'DARK KHAKI', + hex: '#BDB76B', + }, + { + name: 'LAVENDER', + hex: '#E6E6FA', + }, + { + name: 'THISTLE', + hex: '#D8BFD8', + }, + { + name: 'PLUM', + hex: '#DDA0DD', + }, + { + name: 'VIOLET', + hex: '#EE82EE', + }, + { + name: 'ORCHID', + hex: '#DA70D6', + }, + { + name: 'FUCHSIA', + hex: '#FF00FF', + }, + { + name: 'MAGENTA', + hex: '#FF00FF', + }, + { + name: 'MEDIUM ORCHID', + hex: '#BA55D3', + }, + { + name: 'MEDIUM PURPLE', + hex: '#9370DB', + }, + { + name: 'REBECCA PURPLE', + hex: '#663399', + }, + { + name: 'BLUE VIOLET', + hex: '#8A2BE2', + }, + { + name: 'DARK VIOLET', + hex: '#9400D3', + }, + { + name: 'DARK ORCHID', + hex: '#9932CC', + }, + { + name: 'DARK MAGENTA', + hex: '#8B008B', + }, + { + name: 'PURPLE', + hex: '#800080', + }, + { + name: 'INDIGO', + hex: '#4B0082', + }, + { + name: 'SLATE BLUE', + hex: '#6A5ACD', + }, + { + name: 'DARK SLATE BLUE', + hex: '#483D8B', + }, + { + name: 'MEDIUM SLATE BLUE', + hex: '#7B68EE', + }, + { + name: 'GREEN YELLOW', + hex: '#ADFF2F', + }, + { + name: 'CHARTREUSE', + hex: '#7FFF00', + }, + { + name: 'LAWN GREEN', + hex: '#7CFC00', + }, + { + name: 'LIME', + hex: '#00FF00', + }, + { + name: 'LIME GREEN', + hex: '#32CD32', + }, + { + name: 'PALE GREEN', + hex: '#98FB98', + }, + { + name: 'LIGHT GREEN', + hex: '#90EE90', + }, + { + name: 'MEDIUM SPRING GREEN', + hex: '#00FA9A', + }, + { + name: 'SPRING GREEN', + hex: '#00FF7F', + }, + { + name: 'MEDIUM SEA GREEN', + hex: '#3CB371', + }, + { + name: 'SEA GREEN', + hex: '#2E8B57', + }, + { + name: 'FOREST GREEN', + hex: '#228B22', + }, + { + name: 'GREEN', + hex: '#008000', + }, + { + name: 'DARK GREEN', + hex: '#006400', + }, + { + name: 'YELLOW GREEN', + hex: '#9ACD32', + }, + { + name: 'OLIVE DRAB', + hex: '#6B8E23', + }, + { + name: 'OLIVE', + hex: '#6B8E23', + }, + { + name: 'DARK OLIVE GREEN', + hex: '#556B2F', + }, + { + name: 'MEDIUM AQUA MARINE', + hex: '#66CDAA', + }, + { + name: 'DARK SEA GREEN', + hex: '#8FBC8B', + }, + { + name: 'LIGHT SEA GREEN', + hex: '#20B2AA', + }, + { + name: 'DARK CYAN', + hex: '#008B8B', + }, + { + name: 'TEAL', + hex: '#008080', + }, + { + name: 'AQUA', + hex: '#00FFFF', + }, + { + name: 'CYAN', + hex: '#00FFFF', + }, + { + name: 'LIGHT CYAN', + hex: '#E0FFFF', + }, + { + name: 'PALE TURQUOISE', + hex: '#AFEEEE', + }, + { + name: 'AQUAMARINE', + hex: '#7FFFD4', + }, + { + name: 'TURQUOISE', + hex: '#40E0D0', + }, + { + name: 'MEDIUM TURQUOISE', + hex: '#48D1CC', + }, + { + name: 'DARK TURQUOISE', + hex: '#00CED1', + }, + { + name: 'CADET BLUE', + hex: '#5F9EA0', + }, + { + name: 'STEEL BLUE', + hex: '#4682B4', + }, + { + name: 'LIGHT STEEL BLUE', + hex: '#B0C4DE', + }, + { + name: 'POWDER BLUE', + hex: '#B0E0E6', + }, + { + name: 'LIGHT BLUE', + hex: '#ADD8E6', + }, + { + name: 'SKY BLUE', + hex: '#87CEEB', + }, + { + name: 'LIGHT SKY BLUE', + hex: '#87CEFA', + }, + { + name: 'DEEP SKY BLUE', + hex: '#00BFFF', + }, + { + name: 'DODGER BLUE', + hex: '#1E90FF', + }, + { + name: 'CORN FLOWER BLUE', + hex: '#6495ED', + }, + { + name: 'ROYAL BLUE', + hex: '#4169E1', + }, + { + name: 'BLUE', + hex: '#0000FF', + }, + { + name: 'MEDIUM BLUE', + hex: '#0000CD', + }, + { + name: 'DARK BLUE', + hex: '#00008B', + }, + { + name: 'NAVY', + hex: '#00008B', + }, + { + name: 'MIDNIGHT BLUE', + hex: '#191970', + }, + { + name: 'CORN SILK', + hex: '#FFF8DC', + }, + { + name: 'BLANCHED ALMOND', + hex: '#FFEBCD', + }, + { + name: 'BISQUE', + hex: '#FFE4C4', + }, + { + name: 'NAVAJO WHITE', + hex: '#FFDEAD', + }, + { + name: 'WHEAT', + hex: '#F5DEB3', + }, + { + name: 'BURLY WOOD', + hex: '#DEB887', + }, + { + name: 'TAN', + hex: '#D2B48C', + }, + { + name: 'ROSY BROWN', + hex: '#BC8F8F', + }, + { + name: 'SANDY BROWN', + hex: '#F4A460', + }, + { + name: 'GOLDENROD', + hex: '#DAA520', + }, + { + name: 'DARK GOLDEN ROD', + hex: '#B8860B', + }, + { + name: 'PERU', + hex: '#CD853F', + }, + { + name: 'CHOCOLATE', + hex: '#D2691E', + }, + { + name: 'SADDLE BROWN', + hex: '#8B4513', + }, + { + name: 'SIENNA', + hex: '#A0522D', + }, + { + name: 'BROWN', + hex: '#A52A2A', + }, + { + name: 'MAROON', + hex: '#800000', + }, + { + name: 'WHITE', + hex: '#FFFFFF', + }, + { + name: 'SNOW', + hex: '#FFFAFA', + }, + { + name: 'HONEY DEW', + hex: '#F0FFF0', + }, + { + name: 'MINT CREAM', + hex: '#F5FFFA', + }, + { + name: 'AZURE', + hex: '#F0FFFF', + }, + { + name: 'ALICE BLUE', + hex: '#F0F8FF', + }, + { + name: 'GHOST WHITE', + hex: '#F8F8FF', + }, + { + name: 'WHITE SMOKE', + hex: '#F5F5F5', + }, + { + name: 'SEA SHELL', + hex: '#FFF5EE', + }, + { + name: 'BEIGE', + hex: '#F5F5DC', + }, + { + name: 'OLD LACE', + hex: '#FDF5E6', + }, + { + name: 'FLORAL WHITE', + hex: '#FDF5E6', + }, + { + name: 'IVORY', + hex: '#FFFFF0', + }, + { + name: 'ANTIQUE WHITE', + hex: '#FAEBD7', + }, + { + name: 'LINEN', + hex: '#FAF0E6', + }, + { + name: 'LAVENDER BLUSH', + hex: '#FFF0F5', + }, + { + name: 'MISTY ROSE', + hex: '#FFE4E1', + }, + { + name: 'GAINSBORO', + hex: '#DCDCDC', + }, + { + name: 'LIGHT GRAY', + hex: '#D3D3D3', + }, + { + name: 'SILVER', + hex: '#C0C0C0', + }, + { + name: 'DARK GRAY', + hex: '#A9A9A9', + }, + { + name: 'GRAY', + hex: '#808080', + }, + { + name: 'DIMGRAY', + hex: '#696969', + }, + { + name: 'LIGHT SLATE GRAY', + hex: '#778899', + }, + { + name: 'SLATE GRAY', + hex: '#708090', + }, + { + name: 'DARK SLATE GRAY', + hex: '#2F4F4F', + }, + { + name: 'BLACK', + hex: '#000000', + }, +]; + +/* + * @function computeDistance + * + * @desc Computes a numerical value of how difference between two hex color values + * for comparison in finding the closest HTML color value + * + * @param {String} hex1: A hexadecimal number representing a color + * @param {String} hex2: A hexadecimal number representing a color + * + * @return {Number} A number representing the difference between two colors + */ + +function computeDistance(hex1, hex2) { + const rgb1 = { + r: parseInt(hex1.substring(1, 2), 16), + b: parseInt(hex1.substring(3, 4), 16), + g: parseInt(hex1.substring(5, 6), 16), + }; + + const rgb2 = { + r: parseInt(hex2.substring(1, 2), 16), + b: parseInt(hex2.substring(3, 4), 16), + g: parseInt(hex2.substring(5, 6), 16), + }; + + return ( + Math.pow(rgb1.r - rgb2.r, 2) + + Math.pow(rgb1.g - rgb2.g, 2) + + Math.pow(rgb1.b - rgb2.b, 2) + ); +} + +/* + * @function getHTMLColorName + * + * @desc Returns a text description of a System Color based on HTML Color values + * + * @param {String} systemColorName: Name of a system color + * @param {String} colorHex: A hexadecimal number representing a color + * + * @return {String) see @desc + */ + +function getHTMLColorName(systemColorName, colorHex) { + // Check for transparent + + if (colorHex[0] !== '#') { + return `${systemColorName} is ${colorHex}`; + } + + for (let i = 0; i < htmlColorValues.length; i += 1) { + const v = htmlColorValues[i]; + if (v.hex.toLowerCase() === colorHex) { + return `${systemColorName} is ${v.name.toLowerCase()}`; + } + } + + // See if shade of gray + if ( + colorHex.substring(1, 2) === colorHex.substring(3, 4) && + colorHex.substring(1, 2) === colorHex.substring(5, 6) + ) { + switch (colorHex[1]) { + case '0': + case '1': + case '2': + case '3': + case '4': + return `${systemColorName} is a dark shade of gray`; + + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + return `${systemColorName} is a light shade of gray`; + + default: + return `${systemColorName} is shade of gray`; + } + } + + // Look for closest color + + let closestValue = htmlColorValues[0]; + let closestComputedDistance = computeDistance(closestValue.hex, colorHex); + + htmlColorValues.forEach((v) => { + const cd = computeDistance(v.hex, colorHex); + if (cd < closestComputedDistance) { + closestValue = v; + closestComputedDistance = cd; + } + }); + + return `${systemColorName} is similar to ${closestValue.name.toLowerCase()}`; +} + +const systemColorValues = [ + { + value: 'AccentColor', + name: 'Accent color', + desc: 'Background of accented user interface controls', + }, + { + value: 'AccentColorText', + name: 'Accent color text', + desc: 'Text of accented user interface controls', + }, + { + value: 'ActiveText', + name: 'Active text', + desc: 'Text of active links', + }, + { + value: 'ButtonBorder', + name: 'Button border', + desc: 'Base border color of controls', + }, + { + value: 'ButtonFace', + name: 'Button face', + desc: 'Background color of controls', + }, + { + value: 'ButtonText', + name: 'Button text', + desc: 'Text color of controls', + }, + { + value: 'Canvas', + name: 'Canvas', + desc: 'Background of application content or documents', + }, + { + value: 'CanvasText', + name: 'Canvas text', + desc: 'Text color in application content or documents', + }, + { + value: 'Field', + name: 'Field', + desc: 'Background of input fields', + }, + { + value: 'FieldText', + name: 'Field text', + desc: 'Text in input fields', + }, + { + value: 'GrayText', + name: 'Gray text', + desc: 'Text color for disabled items (e.g. a disabled control)', + }, + { + value: 'Highlight', + name: 'Highlight', + desc: 'Background of selected items', + }, + { + value: 'HighlightText', + name: 'Highlight text', + desc: 'Text color of selected items', + }, + { + value: 'LinkText', + name: 'Link text', + desc: 'Text of non-active, non-visited links', + }, + { + value: 'Mark', + name: 'Mark', + desc: 'Background of text that has been specially marked (such as by the HTML mark element)', + }, + { + value: 'MarkText', + name: 'Mark text', + desc: 'Text that has been specially marked (such as by the HTML mark element)', + }, + { + value: 'SelectedItem', + name: 'Selected item', + desc: 'Background of selected items, for example, a selected checkbox', + }, + { + value: 'SelectedItemText', + name: 'Selected item text', + desc: 'Text of selected items', + }, + { + value: 'VisitedText', + name: 'Visited text', + desc: 'Text of visited links', + }, +]; + +/* + * @function rgb2Hex + * + * @desc Converts a RGB color to its equivalent hex color value + * + * @param {String} rgb: The color of in RGB format + * + * @return {String) d=see @desc + */ + +function rgb2Hex(rgb) { + // Choose correct separator + let sep = rgb.indexOf(',') > -1 ? ',' : ' '; + // Turn "rgb(r,g,b)" into [r,g,b] + rgb = rgb.split('(')[1].split(')')[0].split(sep); + + let a = rgb[3] ? parseFloat(rgb[3]) : 1; + + if (a < 0.01) { + return 'transparent'; + } + + let r = Math.round(parseInt(rgb[0]) * a + 255 * (1 - a)).toString(16), + g = Math.round(parseInt(rgb[1]) * a + 255 * (1 - a)).toString(16), + b = Math.round(parseInt(rgb[2]) * a + 255 * (1 - a)).toString(16); + + if (r.length == 1) { + r = '0' + r; + } + if (g.length == 1) { + g = '0' + g; + } + if (b.length == 1) { + b = '0' + b; + } + + const hex = '#' + r + g + b; + + return hex; +} + +// Fill in System color table + +window.addEventListener('load', () => { + const tbodyNode = document.getElementById('samples'); + + systemColorValues.forEach((v) => { + if (v.value) { + const tr = document.createElement('tr'); + const thv = document.createElement('th'); + thv.textContent = v.value; + tr.appendChild(thv); + const tds = document.createElement('td'); + const div = document.createElement('div'); + div.role = 'img'; + div.classList.add('sample'); + div.style.backgroundColor = v.value; + tds.appendChild(div); + const divHex = document.createElement('div'); + divHex.className = 'color'; + tds.appendChild(divHex); + tr.appendChild(tds); + const tdRGB = document.createElement('td'); + tdRGB.className = 'font'; + tdRGB.textContent = '??'; + tr.appendChild(tdRGB); + const tdHex = document.createElement('td'); + tdHex.className = 'font'; + tdHex.textContent = '??'; + const tdd = document.createElement('td'); + tdd.textContent = v.desc; + tr.appendChild(tdd); + tbodyNode.appendChild(tr); + const cStyle = window.getComputedStyle(div); + tdRGB.textContent = cStyle.backgroundColor; + const colorHex = rgb2Hex(cStyle.backgroundColor); + divHex.textContent = colorHex; + div.ariaLabel = getHTMLColorName(v.name, colorHex); + } + }); +}); diff --git a/content/practices/practices.html b/content/practices/practices.html index 3f31e1ce80..2529dd33b4 100644 --- a/content/practices/practices.html +++ b/content/practices/practices.html @@ -75,6 +75,18 @@

+
  • + +

    + Supporting High Contrast Settings +

    +
    +
    + Some people need more than the required default minimum color contrast to perceive content. + make components responsive to operating system color and contrast settings so it is accessible to them. +
    +
  • +
  • diff --git a/cspell.json b/cspell.json index 3841ca274a..b26484880c 100644 --- a/cspell.json +++ b/cspell.json @@ -197,6 +197,7 @@ "radiogroups", "rawgit", "Rearrangeable", + "Rebecca", "refreshable", "respec", "Rhincodon",