Skip to content

Commit ff93d45

Browse files
crisbetojelbourn
authored andcommitted
refactor(button): render focus tint and ripples behind button content
Reworks the button focus indication and ripples so that they render behind the text of the button, instead of top of it. This helps with the contrast ratios while focused. Also gets rid of the `mat-button-focus-overlay` element in favor of using `::before` which saves us the extra DOM node. Incorporates some of the changes from #11961 so that we don't have to increase the size of the CSS selectors.
1 parent aa22368 commit ff93d45

File tree

5 files changed

+47
-33
lines changed

5 files changed

+47
-33
lines changed

src/material/button/_button-base.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ $mat-mini-fab-padding: 8px !default;
6363
}
6464

6565
&.cdk-keyboard-focused, &.cdk-program-focused {
66-
.mat-button-focus-overlay {
66+
&::before {
6767
opacity: 0.12;
6868
}
6969
}

src/material/button/_button-theme.scss

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,19 @@ $_mat-button-ripple-opacity: 0.1;
1010
$accent: map-get($theme, accent);
1111
$warn: map-get($theme, warn);
1212

13-
&.mat-primary .mat-button-focus-overlay {
13+
&.mat-primary::before {
1414
background-color: mat-color($primary);
1515
}
1616

17-
&.mat-accent .mat-button-focus-overlay {
17+
&.mat-accent::before {
1818
background-color: mat-color($accent);
1919
}
2020

21-
&.mat-warn .mat-button-focus-overlay {
21+
&.mat-warn::before {
2222
background-color: mat-color($warn);
2323
}
2424

25-
&[disabled] .mat-button-focus-overlay {
25+
&[disabled]::before {
2626
background-color: transparent;
2727
}
2828
}
@@ -98,7 +98,7 @@ $_mat-button-ripple-opacity: 0.1;
9898
}
9999
}
100100

101-
.mat-button-focus-overlay {
101+
.mat-button-base::before {
102102
background: map_get($foreground, base);
103103
}
104104

src/material/button/button.html

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
<span class="mat-button-wrapper"><ng-content></ng-content></span>
21
<div matRipple class="mat-button-ripple"
32
[class.mat-button-ripple-round]="isRoundButton || isIconButton"
43
[matRippleDisabled]="_isRippleDisabled()"
54
[matRippleCentered]="isIconButton"
65
[matRippleTrigger]="_getHostElement()"></div>
7-
<div class="mat-button-focus-overlay"></div>
6+
<span class="mat-button-wrapper"><ng-content></ng-content></span>

src/material/button/button.scss

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
@import '../../cdk/a11y/a11y';
66

77
.mat-button, .mat-icon-button {
8-
.mat-button-focus-overlay {
8+
&::before {
99
opacity: 0;
1010
}
1111
}
@@ -14,7 +14,7 @@
1414
// Use the same visual treatment for hover as for focus.
1515
.mat-button:hover,
1616
.mat-stroked-button:hover {
17-
.mat-button-focus-overlay {
17+
&::before {
1818
opacity: 0.04;
1919
}
2020
}
@@ -25,7 +25,7 @@
2525
@media (hover: none) {
2626
.mat-button:hover,
2727
.mat-stroked-button:hover {
28-
.mat-button-focus-overlay {
28+
&::before {
2929
opacity: 0;
3030
}
3131
}
@@ -41,26 +41,6 @@
4141
@include mat-raised-button;
4242
}
4343

44-
.mat-stroked-button {
45-
border: $mat-stroked-button-border-width solid currentColor;
46-
padding: $mat-stroked-button-padding;
47-
line-height: $mat-stroked-button-line-height;
48-
49-
// Since the stroked button has has an actual border that reduces the available space for
50-
// child elements such as the ripple container or focus overlay, an inherited border radius
51-
// for the absolute-positioned child elements does not work properly. This is because the
52-
// child element cannot expand to the same boundaries as the parent element with a border.
53-
// In order to work around this issue by *not* hiding overflow, we adjust the child elements
54-
// to fully cover the actual button element. This means that the border-radius would be correct
55-
// then. See: https://github.com/angular/components/issues/13738
56-
.mat-button-ripple.mat-ripple, .mat-button-focus-overlay {
57-
top: -$mat-stroked-button-border-width;
58-
left: -$mat-stroked-button-border-width;
59-
right: -$mat-stroked-button-border-width;
60-
bottom: -$mat-stroked-button-border-width;
61-
}
62-
}
63-
6444
.mat-fab {
6545
@include mat-fab($mat-fab-size, $mat-fab-padding);
6646
}
@@ -91,7 +71,7 @@
9171
// Increase specificity for the ripple container because ripple styles are part of
9272
// the `mat-core` mixin and can potentially overwrite the absolute position of the container.
9373
.mat-button-ripple.mat-ripple,
94-
.mat-button-focus-overlay {
74+
.mat-button-base::before {
9575
@include mat-fill;
9676

9777
// Disable pointer events for the ripple container and focus overlay because the container
@@ -112,10 +92,17 @@
11292
transform: translateZ(0);
11393
}
11494

95+
.mat-button-wrapper {
96+
// Bump the `z-index` so the focus overlay and ripples go behind the content.
97+
z-index: 1;
98+
position: relative;
99+
}
100+
115101
// Element that overlays the button to show focus and hover effects.
116-
.mat-button-focus-overlay {
102+
.mat-button-base::before {
117103
opacity: 0;
118104
transition: $mat-button-focus-transition;
105+
content: '';
119106

120107
._mat-animation-noopable & {
121108
transition: none;
@@ -144,6 +131,29 @@
144131
z-index: 1;
145132
}
146133

134+
// Note that this needs to be after initial declarations for `.mat-button-ripple` and
135+
// `.mat-button-base::before` so that we can override the top/left/right/bottom without
136+
// having to bump the specificity.
137+
.mat-stroked-button {
138+
border: $mat-stroked-button-border-width solid currentColor;
139+
padding: $mat-stroked-button-padding;
140+
line-height: $mat-stroked-button-line-height;
141+
142+
// Since the stroked button has has an actual border that reduces the available space for
143+
// child elements such as the ripple container or focus overlay, an inherited border radius
144+
// for the absolute-positioned child elements does not work properly. This is because the
145+
// child element cannot expand to the same boundaries as the parent element with a border.
146+
// In order to work around this issue by *not* hiding overflow, we adjust the child elements
147+
// to fully cover the actual button element. This means that the border-radius would be correct
148+
// then. See: https://github.com/angular/components/issues/13738
149+
.mat-button-ripple.mat-ripple, &::before {
150+
top: -$mat-stroked-button-border-width;
151+
left: -$mat-stroked-button-border-width;
152+
right: -$mat-stroked-button-border-width;
153+
bottom: -$mat-stroked-button-border-width;
154+
}
155+
}
156+
147157
// Elements inside of all type of buttons should be vertical aligned in the middle.
148158
.mat-button, .mat-flat-button, .mat-stroked-button, .mat-raised-button, .mat-icon-button,
149159
.mat-fab, .mat-mini-fab {

src/material/button/button.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ export class MatButton extends _MatButtonMixinBase
9494
@Optional() @Inject(ANIMATION_MODULE_TYPE) public _animationMode: string) {
9595
super(elementRef);
9696

97+
// Add a class that applies to all buttons. This makes it easier to target if somebody
98+
// wants to target all Material buttons. We do it here rather than `host` to ensure that
99+
// the class is applied to derived classes.
100+
elementRef.nativeElement.classList.add('mat-button-base');
101+
97102
// For each of the variant selectors that is prevent in the button's host
98103
// attributes, add the correct corresponding class.
99104
for (const attr of BUTTON_HOST_ATTRIBUTES) {

0 commit comments

Comments
 (0)