Skip to content

Commit 76e2265

Browse files
jackierchucrisbeto
authored andcommitted
feat(material/core): use strong focus indicators in high contrast mode
Reuses the strong focus indicators styling for high-contrast mode users.
1 parent d40da65 commit 76e2265

File tree

39 files changed

+339
-404
lines changed

39 files changed

+339
-404
lines changed

src/dev-app/theme.scss

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,9 @@ $candy-app-theme: mat.define-light-theme((
3333

3434
.demo-strong-focus {
3535
// Include base styles for strong focus indicators.
36-
@include mat.strong-focus-indicators();
37-
@include experimental.mdc-strong-focus-indicators();
38-
39-
// Include the default theme for focus indicators.
40-
@include mat.strong-focus-indicators-theme($candy-app-theme);
41-
@include experimental.mdc-strong-focus-indicators-theme($candy-app-theme);
36+
$indicators-config: (border-color: mat.get-color-from-palette($candy-app-primary));
37+
@include mat.strong-focus-indicators($indicators-config);
38+
@include experimental.mdc-strong-focus-indicators($indicators-config);
4239
}
4340

4441
// Include the alternative theme styles inside of a block with a CSS class. You can make this
@@ -60,8 +57,9 @@ $candy-app-theme: mat.define-light-theme((
6057

6158
// Include the dark theme colors for focus indicators.
6259
&.demo-strong-focus {
63-
@include mat.strong-focus-indicators-color($dark-colors);
64-
@include experimental.mdc-strong-focus-indicators-color($dark-colors);
60+
$indicators-config: (border-color: mat.get-color-from-palette($dark-primary));
61+
@include mat.strong-focus-indicators($indicators-config);
62+
@include experimental.mdc-strong-focus-indicators($indicators-config);
6563
}
6664
}
6765

src/material-experimental/mdc-button/button-high-contrast.scss

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,3 @@
1111
outline: solid 1px;
1212
}
1313
}
14-
15-
@include cdk.high-contrast(active, off) {
16-
.mat-mdc-button-base:focus {
17-
outline: solid 3px;
18-
}
19-
}

src/material-experimental/mdc-button/button.scss

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,29 @@
107107
right: $offset;
108108
border-width: $offset;
109109
}
110+
111+
// For the button element, default inset/offset values are necessary to ensure that
112+
// the focus indicator is sufficiently contrastive and renders appropriately.
113+
.mat-mdc-unelevated-button,
114+
.mat-mdc-raised-button,
115+
.mdc-fab {
116+
.mat-mdc-focus-indicator::before {
117+
$default-border-width: mat.$focus-indicators-private-default-border-width;
118+
$border-width: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
119+
$offset: calc(#{$border-width} + 2px);
120+
margin: calc(#{$offset} * -1);
121+
}
122+
}
123+
124+
.mat-mdc-outlined-button .mat-mdc-focus-indicator::before {
125+
$default-border-width: mat.$focus-indicators-private-default-border-width;
126+
$border-width: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
127+
$offset: calc(#{$border-width} + 3px);
128+
margin: calc(#{$offset} * -1);
129+
}
130+
131+
// For buttons, render the focus indicator when the parent
132+
// button is focused.
133+
.mat-mdc-button-base:focus .mat-mdc-focus-indicator::before {
134+
content: '';
135+
}

src/material-experimental/mdc-checkbox/checkbox.scss

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
@use '@angular/cdk';
21
@use '@angular/material' as mat;
32
@use '@material/checkbox/checkbox' as mdc-checkbox;
43
@use '@material/checkbox/checkbox-theme' as mdc-checkbox-theme;
@@ -49,11 +48,6 @@
4948
.mdc-checkbox__native-control:not([disabled]):focus ~ .mdc-checkbox__ripple {
5049
opacity: map.get(mdc-ripple.$dark-ink-opacities, hover) +
5150
map.get(mdc-ripple.$dark-ink-opacities, focus);
52-
53-
@include cdk.high-contrast(active, off) {
54-
outline: solid 3px;
55-
opacity: 1;
56-
}
5751
}
5852
}
5953

@@ -125,3 +119,15 @@
125119
$set-width: true,
126120
$query: mdc-helpers.$mat-base-styles-query);
127121
}
122+
123+
// Checkbox components have to set `border-radius: 50%` in order to support density scaling
124+
// which will clip a square focus indicator so we have to turn it into a circle.
125+
.mat-mdc-checkbox-ripple.mat-mdc-focus-indicator::before {
126+
border-radius: 50%;
127+
}
128+
129+
// For checkboxes render the focus indicator when we know
130+
// the hidden input is focused (slightly different for each control).
131+
.mdc-checkbox__native-control:focus ~ .mat-mdc-focus-indicator::before {
132+
content: '';
133+
}

src/material-experimental/mdc-chips/chip.scss

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,6 @@
4040
@include cdk.high-contrast(active, off) {
4141
outline: solid 1px;
4242

43-
&.cdk-focused {
44-
// Use 2px here since the dotted outline is a little thinner.
45-
outline: dotted 2px;
46-
}
47-
4843
.mdc-evolution-chip__checkmark-path {
4944
// SVG colors won't be changed in high contrast mode and since the checkmark is white
5045
// by default, it'll blend in with the background in black-on-white mode. Override the
@@ -215,3 +210,28 @@
215210
outline-width: 3px;
216211
}
217212
}
213+
214+
// For the chip element, default inset/offset values are necessary to ensure that
215+
// the focus indicator is sufficiently contrastive and renders appropriately.
216+
.mat-mdc-chip-action-label .mat-mdc-focus-indicator::before {
217+
$default-border-width: mat.$focus-indicators-private-default-border-width;
218+
$border-width: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
219+
$offset: calc(#{$border-width} + 2px);
220+
margin: calc(#{$offset} * -1);
221+
}
222+
223+
.mat-mdc-focus-indicator.mat-mdc-chip-remove::before {
224+
$default-border-width: mat.$focus-indicators-private-default-border-width;
225+
margin: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
226+
}
227+
228+
// MDC sets a padding a on the chip button which stretches out the focus indicator.
229+
.mat-mdc-focus-indicator.mat-mdc-chip-remove::before {
230+
left: 8px;
231+
right: 8px;
232+
}
233+
234+
// In the chips the individual actions have focus so we target a different element.
235+
.mat-mdc-chip-action:focus .mat-mdc-focus-indicator::before {
236+
content: '';
237+
}

src/material-experimental/mdc-core/option/option.scss

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
@use '@angular/cdk';
21
@use '@angular/material' as mat;
32
@use '@material/list/evolution-mixins' as mdc-list-mixins;
43
@use '@material/list/evolution-variables' as mdc-list-variables;
@@ -91,24 +90,7 @@
9190
}
9291
}
9392

94-
.mat-mdc-option-active {
95-
@include cdk.high-contrast(active, off) {
96-
// A pseudo element is used here, because the active indication gets moved between options
97-
// and we don't want the border from below to shift the layout around as it's added and removed.
98-
&::before {
99-
content: '';
100-
position: absolute;
101-
top: 0;
102-
bottom: 0;
103-
left: 0;
104-
right: 0;
105-
pointer-events: none;
106-
107-
// We use a border here, rather than an outline, because the outline will be cut off
108-
// by the `overflow: hidden` on the panel wrapping the options, whereas a border
109-
// will push the element inwards. This could be done using `outline-offset: -1px`,
110-
// however the property isn't supported on IE11.
111-
border: solid 1px currentColor;
112-
}
113-
}
93+
// For options, render the focus indicator when the class .mat-mdc-option-active is present.
94+
.mat-mdc-focus-indicator.mat-mdc-option-active::before {
95+
content: '';
11496
}

src/material-experimental/mdc-helpers/_focus-indicators-theme.scss

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,28 @@
22
@use 'sass:map';
33
@use 'sass:meta';
44

5-
@mixin _border-color($color) {
6-
.mat-mdc-focus-indicator::before {
7-
border-color: $color;
8-
}
9-
}
10-
115
// stylelint-disable-next-line material/theme-mixin-api
126
@mixin color($config-or-theme-or-color) {
137
@if meta.type-of($config-or-theme-or-color) == 'color' {
14-
@include _border-color($config-or-theme-or-color);
8+
@include mat.focus-indicators-private-private-customize-focus-indicators((
9+
border-color: $config-or-theme-or-color
10+
), 'mat-mdc');
1511
}
1612
@else {
1713
$config: mat.get-color-config($config-or-theme-or-color);
1814
$border-color: mat.get-color-from-palette(map.get($config, primary));
19-
@include _border-color($border-color);
15+
@include mat.focus-indicators-private-private-customize-focus-indicators((
16+
border-color: $border-color
17+
), 'mat-mdc');
2018
}
2119
}
2220

2321
// stylelint-disable-next-line material/theme-mixin-api
2422
@mixin theme($theme-or-color-config-or-color) {
2523
@if meta.type-of($theme-or-color-config-or-color) == 'color' {
26-
@include _border-color($theme-or-color-config-or-color);
24+
@include mat.focus-indicators-private-private-customize-focus-indicators((
25+
border-color: $theme-or-color-config-or-color
26+
), 'mat-mdc');
2727
}
2828
@else {
2929
$theme: mat.private-legacy-get-theme($theme-or-color-config-or-color);
Lines changed: 4 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,15 @@
1-
@use '@angular/material' as mat;
21
@use 'sass:map';
2+
@use '@angular/material' as mat;
33

4-
/// Mixin that turns on strong focus indicators.
5-
///
6-
/// @example
7-
/// .my-app {
8-
/// @include mat-mdc-strong-focus-indicators($config);
9-
/// }
104
@mixin strong-focus-indicators($config: ()) {
115
// Default focus indicator config.
126
$default-config: (
13-
border-style: solid,
14-
border-width: 3px,
15-
border-radius: 4px,
7+
border-color: black,
8+
display: block,
169
);
1710

1811
// Merge default config with user config.
1912
$config: map.merge($default-config, $config);
20-
$border-style: map.get($config, border-style);
21-
$border-width: map.get($config, border-width);
22-
$border-radius: map.get($config, border-radius);
23-
24-
// Base styles for focus indicators.
25-
.mat-mdc-focus-indicator::before {
26-
@include mat.private-fill();
27-
box-sizing: border-box;
28-
pointer-events: none;
29-
border: $border-width $border-style transparent;
30-
border-radius: $border-radius;
31-
32-
.cdk-high-contrast-active & {
33-
display: none;
34-
}
35-
}
36-
37-
// By default, all focus indicators are flush with the bounding box of their
38-
// host element. For particular elements (listed below), default inset/offset
39-
// values are necessary to ensure that the focus indicator is sufficiently
40-
// contrastive and renders appropriately.
41-
42-
.mat-mdc-unelevated-button .mat-mdc-focus-indicator::before,
43-
.mat-mdc-raised-button .mat-mdc-focus-indicator::before,
44-
.mdc-fab .mat-mdc-focus-indicator::before,
45-
.mat-mdc-chip-action-label .mat-mdc-focus-indicator::before {
46-
margin: -($border-width + 2px);
47-
}
48-
49-
.mat-mdc-outlined-button .mat-mdc-focus-indicator::before {
50-
margin: -($border-width + 3px);
51-
}
52-
53-
.mat-mdc-focus-indicator.mat-mdc-chip-remove::before {
54-
margin: -$border-width;
55-
}
56-
57-
// MDC sets a padding a on the button which stretches out the focus indicator.
58-
.mat-mdc-focus-indicator.mat-mdc-chip-remove::before {
59-
left: 8px;
60-
right: 8px;
61-
}
62-
63-
.mat-mdc-focus-indicator.mat-mdc-tab::before,
64-
.mat-mdc-focus-indicator.mat-mdc-tab-link::before {
65-
margin: 5px;
66-
}
67-
68-
// These components have to set `border-radius: 50%` in order to support density scaling
69-
// which will clip a square focus indicator so we have to turn it into a circle.
70-
.mat-mdc-checkbox-ripple.mat-mdc-focus-indicator::before,
71-
.mat-radio-ripple.mat-mdc-focus-indicator::before,
72-
.mat-mdc-slider .mat-mdc-focus-indicator::before,
73-
.mat-mdc-slide-toggle .mat-mdc-focus-indicator::before {
74-
border-radius: 50%;
75-
}
76-
77-
// Render the focus indicator on focus. Defining a pseudo element's
78-
// content will cause it to render.
79-
80-
// For checkboxes, radios and slide toggles, render the focus indicator when we know
81-
// the hidden input is focused (slightly different for each control).
82-
.mdc-checkbox__native-control:focus ~ .mat-mdc-focus-indicator::before,
83-
.mat-mdc-slide-toggle-focused .mat-mdc-focus-indicator::before,
84-
.mat-mdc-radio-button.cdk-focused .mat-mdc-focus-indicator::before,
85-
86-
// In the chips the individual actions have focus so we target a different element.
87-
.mat-mdc-chip-action:focus .mat-mdc-focus-indicator::before,
88-
89-
// For buttons and list items, render the focus indicator when the parent
90-
// button or list item is focused.
91-
.mat-mdc-button-base:focus .mat-mdc-focus-indicator::before,
92-
.mat-mdc-list-item:focus > .mat-mdc-focus-indicator::before,
93-
94-
// For options, render the focus indicator when the class .mat-mdc-option-active is present.
95-
.mat-mdc-focus-indicator.mat-mdc-option-active::before,
96-
97-
// In the MDC slider the focus indicator is inside the thumb.
98-
.mdc-slider__thumb--focused .mat-mdc-focus-indicator::before,
9913

100-
// For all other components, render the focus indicator on focus.
101-
.mat-mdc-focus-indicator:focus::before {
102-
content: '';
103-
}
14+
@include mat.focus-indicators-private-private-customize-focus-indicators($config, 'mat-mdc');
10415
}

src/material-experimental/mdc-list/list.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,9 @@ mat-action-list button {
104104
border: 0;
105105
}
106106
}
107+
108+
// For list items, render the focus indicator when the parent
109+
// listem item is focused.
110+
.mat-mdc-list-item:focus > .mat-mdc-focus-indicator::before {
111+
content: '';
112+
}

src/material-experimental/mdc-menu/menu.scss

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ mat-menu {
8484
// from closing, but clicks on child nodes still propagate which is inconsistent (see #16694).
8585
// In order to keep the behavior consistent and prevent the menu from closing, we add an overlay
8686
// on top of the content that will catch all the clicks while disabled.
87-
&::before {
87+
&::after {
8888
display: block;
8989
position: absolute;
9090
content: '';
@@ -124,12 +124,6 @@ mat-menu {
124124
// We need to move the item 1px down, because Firefox seems to have
125125
// an issue rendering the top part of the outline (see #21524).
126126
margin-top: $outline-width;
127-
128-
&.cdk-program-focused,
129-
&.cdk-keyboard-focused,
130-
&-highlighted {
131-
outline: dotted $outline-width;
132-
}
133127
}
134128
}
135129

src/material-experimental/mdc-radio/radio.scss

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
@use 'sass:map';
2-
@use '@angular/cdk';
32
@use '@angular/material' as mat;
43
@use '@material/radio/radio' as mdc-radio;
54
@use '@material/radio/radio-theme' as mdc-radio-theme;
@@ -105,16 +104,14 @@
105104
}
106105
}
107106

108-
// Note that this creates a square box around the circle, however it's consistent with
109-
// how IE/Edge treat native radio buttons in high contrast mode. We can't turn the border
110-
// into a dotted one, because it's too thick which causes the circles to look off.
111-
@include cdk.high-contrast(active, 'off') {
112-
.mat-mdc-radio-button:not(.mat-radio-disabled) {
113-
&.cdk-keyboard-focused,
114-
&.cdk-program-focused {
115-
.mat-radio-ripple {
116-
outline: solid 3px;
117-
}
118-
}
119-
}
107+
// Radio components have to set `border-radius: 50%` in order to support density scaling
108+
// which will clip a square focus indicator so we have to turn it into a circle.
109+
.mat-radio-ripple.mat-mdc-focus-indicator::before {
110+
border-radius: 50%;
111+
}
112+
113+
// For radios render the focus indicator when we know
114+
// the hidden input is focused (slightly different for each control).
115+
.mat-mdc-radio-button.cdk-focused .mat-mdc-focus-indicator::before {
116+
content: '';
120117
}

0 commit comments

Comments
 (0)