Skip to content

Commit 1256c6c

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 503f12f commit 1256c6c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+362
-420
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-base.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@
4949
.mat-mdc-focus-indicator {
5050
@include mat.private-fill();
5151
}
52+
53+
&:focus .mat-mdc-focus-indicator::before {
54+
content: '';
55+
}
5256
}
5357

5458
// MDC's disabled buttons define a default cursor with pointer-events none. However, they select

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: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,22 @@
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+
.mat-mdc-focus-indicator::before {
116+
$default-border-width: mat.$focus-indicators-private-default-border-width;
117+
$border-width: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
118+
$offset: calc(#{$border-width} + 2px);
119+
margin: calc(#{$offset} * -1);
120+
}
121+
}
122+
123+
.mat-mdc-outlined-button .mat-mdc-focus-indicator::before {
124+
$default-border-width: mat.$focus-indicators-private-default-border-width;
125+
$border-width: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
126+
$offset: calc(#{$border-width} + 3px);
127+
margin: calc(#{$offset} * -1);
128+
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@
6565
.mat-icon, .material-icons {
6666
@include mdc-fab.icon_();
6767
}
68+
69+
.mat-mdc-focus-indicator::before {
70+
$default-border-width: mat.$focus-indicators-private-default-border-width;
71+
$border-width: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
72+
$offset: calc(#{$border-width} + 2px);
73+
margin: calc(#{$offset} * -1);
74+
}
6875
}
6976

7077
.mat-mdc-extended-fab {

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::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: 31 additions & 14 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
@@ -180,25 +175,42 @@
180175
left: 0;
181176
pointer-events: none;
182177
}
183-
}
184178

185-
.mat-mdc-chip-remove {
186-
.mat-icon {
187-
width: inherit;
188-
height: inherit;
189-
font-size: inherit;
190-
box-sizing: content-box;
179+
// For the chip element, default inset/offset values are necessary to ensure that
180+
// the focus indicator is sufficiently contrastive and renders appropriately.
181+
.mat-mdc-focus-indicator::before {
182+
$default-border-width: mat.$focus-indicators-private-default-border-width;
183+
$border-width: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
184+
$offset: calc(#{$border-width} + 2px);
185+
margin: calc(#{$offset} * -1);
191186
}
192187
}
193188

194-
// Fades out the trailing icon slightly so that it can become darker when focused.
195-
// The MDC theming has variables for this, but the focus/hover states don't seem to work.
196189
.mat-mdc-chip-remove {
190+
// Fades out the trailing icon slightly so that it can become darker when focused.
191+
// The MDC theming has variables for this, but the focus/hover states don't seem to work.
197192
opacity: 0.54;
198193

199194
&:focus {
200195
opacity: 1;
201196
}
197+
198+
&::before {
199+
$default-border-width: mat.$focus-indicators-private-default-border-width;
200+
$offset: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
201+
margin: calc(#{$offset} * -1);
202+
203+
// MDC sets a padding a on the chip button which stretches out the focus indicator.
204+
left: 8px;
205+
right: 8px;
206+
}
207+
208+
.mat-icon {
209+
width: inherit;
210+
height: inherit;
211+
font-size: inherit;
212+
box-sizing: content-box;
213+
}
202214
}
203215

204216
.mat-chip-edit-input {
@@ -215,3 +227,8 @@
215227
outline-width: 3px;
216228
}
217229
}
230+
231+
// In the chips the individual actions have focus so we target a different element.
232+
.mat-mdc-chip-action:focus .mat-mdc-focus-indicator::before {
233+
content: '';
234+
}

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-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: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,17 @@
5858
// The MDC-based list items already use the `::before` pseudo element for the standard
5959
// focus/selected/hover state. Hence, we need to have a separate list-item spanning
6060
// element that can be used for strong focus indicators.
61-
.mat-mdc-list-item > .mat-mdc-focus-indicator {
62-
@include mat.private-fill();
63-
pointer-events: none;
61+
.mat-mdc-list-item {
62+
& > .mat-mdc-focus-indicator {
63+
@include mat.private-fill();
64+
pointer-events: none;
65+
}
66+
67+
// For list items, render the focus indicator when the parent
68+
// listem item is focused.
69+
&:focus > .mat-mdc-focus-indicator::before {
70+
content: '';
71+
}
6472
}
6573

6674
.mat-mdc-list-item.mdc-list-item--with-three-lines {

0 commit comments

Comments
 (0)