Skip to content

Commit 96f6e06

Browse files
crisbetojelbourn
authored andcommittedFeb 20, 2019
fix: errors when building theme using CSS variables (#15140)
* Adds an extra theme to the build that will allow us to verify that everything still works if somebody passes in the palette colors as CSS variables. * Fixes a handful of places where Sass would either throw an error or would produce invalid CSS. Fixes #15107.
1 parent 9bf368d commit 96f6e06

File tree

11 files changed

+202
-105
lines changed

11 files changed

+202
-105
lines changed
 

‎src/cdk/a11y/_a11y.scss

+6-7
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,12 @@
1818
}
1919
}
2020

21-
/**
22-
* Applies styles for users in high contrast mode. Note that this only applies
23-
* to Microsoft browsers. Chrome can be included by checking for the `html[hc]`
24-
* attribute, however Chrome handles high contrast differently.
25-
* @param target Which kind of high contrast setting to target. Defaults to `active`, can be
26-
* `white-on-black` or `black-on-white`.
27-
*/
21+
// Applies styles for users in high contrast mode. Note that this only applies
22+
// to Microsoft browsers. Chrome can be included by checking for the `html[hc]`
23+
// attribute, however Chrome handles high contrast differently.
24+
//
25+
// @param target Which kind of high contrast setting to target. Defaults to `active`, can be
26+
// `white-on-black` or `black-on-white`.
2827
@mixin cdk-high-contrast($target: active) {
2928
@media (-ms-high-contrast: $target) {
3029
@content;

‎src/lib/badge/_badge-theme.scss

+14-6
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,22 @@ $mat-badge-large-size: $mat-badge-default-size + 6;
130130

131131
.mat-badge-disabled {
132132
.mat-badge-content {
133-
// The disabled color usually has some kind of opacity, but because the badge is overlayed
134-
// on top of something else, it won't look good if it's opaque. We convert it into a solid
135-
// color by taking the opacity from the rgba value and using the value to determine the
136-
// percentage of the background to put into foreground when mixing the colors together.
137133
$app-background: mat-color($background, 'background');
138134
$badge-color: mat-color($foreground, disabled-button);
139-
$badge-opacity: opacity($badge-color);
140-
background: mix($app-background, rgba($badge-color, 1), (1 - $badge-opacity) * 100%);
135+
136+
// The disabled color usually has some kind of opacity, but because the badge is overlayed
137+
// on top of something else, it won't look good if it's opaque. If it is a color *type*,
138+
// we convert it into a solid color by taking the opacity from the rgba value and using
139+
// the value to determine the percentage of the background to put into foreground when
140+
// mixing the colors together.
141+
@if (type-of($badge-color) == color and type-of($app-background) == color) {
142+
$badge-opacity: opacity($badge-color);
143+
background: mix($app-background, rgba($badge-color, 1), (1 - $badge-opacity) * 100%);
144+
}
145+
@else {
146+
background: $badge-color;
147+
}
148+
141149
color: mat-color($foreground, disabled-text);
142150
}
143151
}

‎src/lib/core/BUILD.bazel

+8
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,11 @@ filegroup(
125125
name = "source-files",
126126
srcs = glob(["**/*.ts"]),
127127
)
128+
129+
# Test theme used to ensure that our themes will compile using CSS variables in the palettes.
130+
sass_binary(
131+
name = "test-css-variables-theme",
132+
src = "theming/test-css-variables-theme.scss",
133+
deps = [":all_themes"],
134+
testonly = True
135+
)

‎src/lib/core/ripple/_ripple.scss

+9-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ $mat-ripple-color-opacity: 0.1;
4040
$foreground-base: map_get($foreground, base);
4141

4242
.mat-ripple-element {
43-
background-color: rgba($foreground-base, $mat-ripple-color-opacity);
43+
// If the ripple color is resolves to a color *type*, we can use it directly, otherwise
44+
// (e.g. it resolves to a CSS variable) we fall back to using the color and setting an opacity.
45+
@if (type-of($foreground-base) == color) {
46+
background-color: rgba($foreground-base, $mat-ripple-color-opacity);
47+
}
48+
@else {
49+
background-color: $foreground-base;
50+
opacity: $mat-ripple-color-opacity;
51+
}
4452
}
4553
}

‎src/lib/core/style/_elevation.scss

+81-75
Original file line numberDiff line numberDiff line change
@@ -32,92 +32,98 @@
3232
// all of the values between them.
3333

3434
@function _get-umbra-map($color, $opacity) {
35+
$shadow-color: if(type-of($color) == color, rgba($color, $opacity * 0.2), $color);
36+
3537
@return (
36-
0: '0px 0px 0px 0px #{rgba($color, $opacity * 0.2)}',
37-
1: '0px 2px 1px -1px #{rgba($color, $opacity * 0.2)}',
38-
2: '0px 3px 1px -2px #{rgba($color, $opacity * 0.2)}',
39-
3: '0px 3px 3px -2px #{rgba($color, $opacity * 0.2)}',
40-
4: '0px 2px 4px -1px #{rgba($color, $opacity * 0.2)}',
41-
5: '0px 3px 5px -1px #{rgba($color, $opacity * 0.2)}',
42-
6: '0px 3px 5px -1px #{rgba($color, $opacity * 0.2)}',
43-
7: '0px 4px 5px -2px #{rgba($color, $opacity * 0.2)}',
44-
8: '0px 5px 5px -3px #{rgba($color, $opacity * 0.2)}',
45-
9: '0px 5px 6px -3px #{rgba($color, $opacity * 0.2)}',
46-
10: '0px 6px 6px -3px #{rgba($color, $opacity * 0.2)}',
47-
11: '0px 6px 7px -4px #{rgba($color, $opacity * 0.2)}',
48-
12: '0px 7px 8px -4px #{rgba($color, $opacity * 0.2)}',
49-
13: '0px 7px 8px -4px #{rgba($color, $opacity * 0.2)}',
50-
14: '0px 7px 9px -4px #{rgba($color, $opacity * 0.2)}',
51-
15: '0px 8px 9px -5px #{rgba($color, $opacity * 0.2)}',
52-
16: '0px 8px 10px -5px #{rgba($color, $opacity * 0.2)}',
53-
17: '0px 8px 11px -5px #{rgba($color, $opacity * 0.2)}',
54-
18: '0px 9px 11px -5px #{rgba($color, $opacity * 0.2)}',
55-
19: '0px 9px 12px -6px #{rgba($color, $opacity * 0.2)}',
56-
20: '0px 10px 13px -6px #{rgba($color, $opacity * 0.2)}',
57-
21: '0px 10px 13px -6px #{rgba($color, $opacity * 0.2)}',
58-
22: '0px 10px 14px -6px #{rgba($color, $opacity * 0.2)}',
59-
23: '0px 11px 14px -7px #{rgba($color, $opacity * 0.2)}',
60-
24: '0px 11px 15px -7px #{rgba($color, $opacity * 0.2)}'
38+
0: '0px 0px 0px 0px #{$shadow-color}',
39+
1: '0px 2px 1px -1px #{$shadow-color}',
40+
2: '0px 3px 1px -2px #{$shadow-color}',
41+
3: '0px 3px 3px -2px #{$shadow-color}',
42+
4: '0px 2px 4px -1px #{$shadow-color}',
43+
5: '0px 3px 5px -1px #{$shadow-color}',
44+
6: '0px 3px 5px -1px #{$shadow-color}',
45+
7: '0px 4px 5px -2px #{$shadow-color}',
46+
8: '0px 5px 5px -3px #{$shadow-color}',
47+
9: '0px 5px 6px -3px #{$shadow-color}',
48+
10: '0px 6px 6px -3px #{$shadow-color}',
49+
11: '0px 6px 7px -4px #{$shadow-color}',
50+
12: '0px 7px 8px -4px #{$shadow-color}',
51+
13: '0px 7px 8px -4px #{$shadow-color}',
52+
14: '0px 7px 9px -4px #{$shadow-color}',
53+
15: '0px 8px 9px -5px #{$shadow-color}',
54+
16: '0px 8px 10px -5px #{$shadow-color}',
55+
17: '0px 8px 11px -5px #{$shadow-color}',
56+
18: '0px 9px 11px -5px #{$shadow-color}',
57+
19: '0px 9px 12px -6px #{$shadow-color}',
58+
20: '0px 10px 13px -6px #{$shadow-color}',
59+
21: '0px 10px 13px -6px #{$shadow-color}',
60+
22: '0px 10px 14px -6px #{$shadow-color}',
61+
23: '0px 11px 14px -7px #{$shadow-color}',
62+
24: '0px 11px 15px -7px #{$shadow-color}'
6163
);
6264
}
6365

6466
@function _get-penumbra-map($color, $opacity) {
67+
$shadow-color: if(type-of($color) == color, rgba($color, $opacity * 0.14), $color);
68+
6569
@return (
66-
0: '0px 0px 0px 0px #{rgba($color, $opacity * 0.14)}',
67-
1: '0px 1px 1px 0px #{rgba($color, $opacity * 0.14)}',
68-
2: '0px 2px 2px 0px #{rgba($color, $opacity * 0.14)}',
69-
3: '0px 3px 4px 0px #{rgba($color, $opacity * 0.14)}',
70-
4: '0px 4px 5px 0px #{rgba($color, $opacity * 0.14)}',
71-
5: '0px 5px 8px 0px #{rgba($color, $opacity * 0.14)}',
72-
6: '0px 6px 10px 0px #{rgba($color, $opacity * 0.14)}',
73-
7: '0px 7px 10px 1px #{rgba($color, $opacity * 0.14)}',
74-
8: '0px 8px 10px 1px #{rgba($color, $opacity * 0.14)}',
75-
9: '0px 9px 12px 1px #{rgba($color, $opacity * 0.14)}',
76-
10: '0px 10px 14px 1px #{rgba($color, $opacity * 0.14)}',
77-
11: '0px 11px 15px 1px #{rgba($color, $opacity * 0.14)}',
78-
12: '0px 12px 17px 2px #{rgba($color, $opacity * 0.14)}',
79-
13: '0px 13px 19px 2px #{rgba($color, $opacity * 0.14)}',
80-
14: '0px 14px 21px 2px #{rgba($color, $opacity * 0.14)}',
81-
15: '0px 15px 22px 2px #{rgba($color, $opacity * 0.14)}',
82-
16: '0px 16px 24px 2px #{rgba($color, $opacity * 0.14)}',
83-
17: '0px 17px 26px 2px #{rgba($color, $opacity * 0.14)}',
84-
18: '0px 18px 28px 2px #{rgba($color, $opacity * 0.14)}',
85-
19: '0px 19px 29px 2px #{rgba($color, $opacity * 0.14)}',
86-
20: '0px 20px 31px 3px #{rgba($color, $opacity * 0.14)}',
87-
21: '0px 21px 33px 3px #{rgba($color, $opacity * 0.14)}',
88-
22: '0px 22px 35px 3px #{rgba($color, $opacity * 0.14)}',
89-
23: '0px 23px 36px 3px #{rgba($color, $opacity * 0.14)}',
90-
24: '0px 24px 38px 3px #{rgba($color, $opacity * 0.14)}'
70+
0: '0px 0px 0px 0px #{$shadow-color}',
71+
1: '0px 1px 1px 0px #{$shadow-color}',
72+
2: '0px 2px 2px 0px #{$shadow-color}',
73+
3: '0px 3px 4px 0px #{$shadow-color}',
74+
4: '0px 4px 5px 0px #{$shadow-color}',
75+
5: '0px 5px 8px 0px #{$shadow-color}',
76+
6: '0px 6px 10px 0px #{$shadow-color}',
77+
7: '0px 7px 10px 1px #{$shadow-color}',
78+
8: '0px 8px 10px 1px #{$shadow-color}',
79+
9: '0px 9px 12px 1px #{$shadow-color}',
80+
10: '0px 10px 14px 1px #{$shadow-color}',
81+
11: '0px 11px 15px 1px #{$shadow-color}',
82+
12: '0px 12px 17px 2px #{$shadow-color}',
83+
13: '0px 13px 19px 2px #{$shadow-color}',
84+
14: '0px 14px 21px 2px #{$shadow-color}',
85+
15: '0px 15px 22px 2px #{$shadow-color}',
86+
16: '0px 16px 24px 2px #{$shadow-color}',
87+
17: '0px 17px 26px 2px #{$shadow-color}',
88+
18: '0px 18px 28px 2px #{$shadow-color}',
89+
19: '0px 19px 29px 2px #{$shadow-color}',
90+
20: '0px 20px 31px 3px #{$shadow-color}',
91+
21: '0px 21px 33px 3px #{$shadow-color}',
92+
22: '0px 22px 35px 3px #{$shadow-color}',
93+
23: '0px 23px 36px 3px #{$shadow-color}',
94+
24: '0px 24px 38px 3px #{$shadow-color}'
9195
);
9296
}
9397

9498
@function _get-ambient-map($color, $opacity) {
99+
$shadow-color: if(type-of($color) == color, rgba($color, $opacity * 0.12), $color);
100+
95101
@return (
96-
0: '0px 0px 0px 0px #{rgba($color, $opacity * 0.12)}',
97-
1: '0px 1px 3px 0px #{rgba($color, $opacity * 0.12)}',
98-
2: '0px 1px 5px 0px #{rgba($color, $opacity * 0.12)}',
99-
3: '0px 1px 8px 0px #{rgba($color, $opacity * 0.12)}',
100-
4: '0px 1px 10px 0px #{rgba($color, $opacity * 0.12)}',
101-
5: '0px 1px 14px 0px #{rgba($color, $opacity * 0.12)}',
102-
6: '0px 1px 18px 0px #{rgba($color, $opacity * 0.12)}',
103-
7: '0px 2px 16px 1px #{rgba($color, $opacity * 0.12)}',
104-
8: '0px 3px 14px 2px #{rgba($color, $opacity * 0.12)}',
105-
9: '0px 3px 16px 2px #{rgba($color, $opacity * 0.12)}',
106-
10: '0px 4px 18px 3px #{rgba($color, $opacity * 0.12)}',
107-
11: '0px 4px 20px 3px #{rgba($color, $opacity * 0.12)}',
108-
12: '0px 5px 22px 4px #{rgba($color, $opacity * 0.12)}',
109-
13: '0px 5px 24px 4px #{rgba($color, $opacity * 0.12)}',
110-
14: '0px 5px 26px 4px #{rgba($color, $opacity * 0.12)}',
111-
15: '0px 6px 28px 5px #{rgba($color, $opacity * 0.12)}',
112-
16: '0px 6px 30px 5px #{rgba($color, $opacity * 0.12)}',
113-
17: '0px 6px 32px 5px #{rgba($color, $opacity * 0.12)}',
114-
18: '0px 7px 34px 6px #{rgba($color, $opacity * 0.12)}',
115-
19: '0px 7px 36px 6px #{rgba($color, $opacity * 0.12)}',
116-
20: '0px 8px 38px 7px #{rgba($color, $opacity * 0.12)}',
117-
21: '0px 8px 40px 7px #{rgba($color, $opacity * 0.12)}',
118-
22: '0px 8px 42px 7px #{rgba($color, $opacity * 0.12)}',
119-
23: '0px 9px 44px 8px #{rgba($color, $opacity * 0.12)}',
120-
24: '0px 9px 46px 8px #{rgba($color, $opacity * 0.12)}'
102+
0: '0px 0px 0px 0px #{$shadow-color}',
103+
1: '0px 1px 3px 0px #{$shadow-color}',
104+
2: '0px 1px 5px 0px #{$shadow-color}',
105+
3: '0px 1px 8px 0px #{$shadow-color}',
106+
4: '0px 1px 10px 0px #{$shadow-color}',
107+
5: '0px 1px 14px 0px #{$shadow-color}',
108+
6: '0px 1px 18px 0px #{$shadow-color}',
109+
7: '0px 2px 16px 1px #{$shadow-color}',
110+
8: '0px 3px 14px 2px #{$shadow-color}',
111+
9: '0px 3px 16px 2px #{$shadow-color}',
112+
10: '0px 4px 18px 3px #{$shadow-color}',
113+
11: '0px 4px 20px 3px #{$shadow-color}',
114+
12: '0px 5px 22px 4px #{$shadow-color}',
115+
13: '0px 5px 24px 4px #{$shadow-color}',
116+
14: '0px 5px 26px 4px #{$shadow-color}',
117+
15: '0px 6px 28px 5px #{$shadow-color}',
118+
16: '0px 6px 30px 5px #{$shadow-color}',
119+
17: '0px 6px 32px 5px #{$shadow-color}',
120+
18: '0px 7px 34px 6px #{$shadow-color}',
121+
19: '0px 7px 36px 6px #{$shadow-color}',
122+
20: '0px 8px 38px 7px #{$shadow-color}',
123+
21: '0px 8px 40px 7px #{$shadow-color}',
124+
22: '0px 8px 42px 7px #{$shadow-color}',
125+
23: '0px 9px 44px 8px #{$shadow-color}',
126+
24: '0px 9px 46px 8px #{$shadow-color}'
121127
);
122128
}
123129

‎src/lib/core/theming/_theming.scss

+8-2
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,15 @@
5252
}
5353

5454
$color: map-get($palette, $hue);
55-
$opacity: if($opacity == null, opacity($color), $opacity);
5655

57-
@return rgba($color, $opacity);
56+
@if (type-of($color) != color) {
57+
// If the $color resolved to something different from a color (e.g. a CSS variable),
58+
// we can't apply the opacity anyway so we return the value as is, otherwise Sass can
59+
// throw an error or output something invalid.
60+
@return $color;
61+
}
62+
63+
@return rgba($color, if($opacity == null, opacity($color), $opacity));
5864
}
5965

6066

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
@import './all-theme';
2+
3+
// Recursively replaces all of the values inside a Sass map with a different value.
4+
@function replace-all-values($palette, $replacement) {
5+
$output: ();
6+
7+
@each $key, $value in $palette {
8+
@if (type-of($value) == 'map') {
9+
$output: map-merge(($key: replace-all-values($value, $replacement)), $output);
10+
}
11+
@else {
12+
$output: map-merge(($key: $replacement), $output);
13+
}
14+
}
15+
16+
@return $output;
17+
}
18+
19+
// Theme used to test that our themes would compile if the colors were specified as CSS variables.
20+
._demo-css-variables-theme {
21+
$palette: mat-palette($mat-blue-grey);
22+
$theme: mat-dark-theme($palette, $palette, $palette);
23+
@include angular-material-theme(replace-all-values($theme, var(--test-var)));
24+
}

‎src/lib/datepicker/_datepicker-theme.scss

+22-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,16 @@ $mat-calendar-weekday-table-font-size: 11px !default;
1717
}
1818

1919
.mat-calendar-body-disabled > .mat-calendar-body-selected {
20-
background-color: fade-out(mat-color($palette), $mat-datepicker-selected-fade-amount);
20+
$background: mat-color($palette);
21+
22+
@if (type-of($background) == color) {
23+
background-color: fade-out($background, $mat-datepicker-selected-fade-amount);
24+
}
25+
@else {
26+
// If we couldn't resolve to background to a color (e.g. it's a CSS variable),
27+
// fall back to fading the content out via `opacity`.
28+
opacity: $mat-datepicker-today-fade-amount;
29+
}
2130
}
2231

2332
.mat-calendar-body-today.mat-calendar-body-selected {
@@ -78,7 +87,18 @@ $mat-calendar-weekday-table-font-size: 11px !default;
7887
}
7988

8089
.mat-calendar-body-disabled > .mat-calendar-body-today:not(.mat-calendar-body-selected) {
81-
border-color: fade-out(mat-color($foreground, hint-text), $mat-datepicker-today-fade-amount);
90+
$color: mat-color($foreground, hint-text);
91+
92+
@if (type-of($color) == color) {
93+
border-color: fade-out($color, $mat-datepicker-today-fade-amount);
94+
}
95+
@else {
96+
// If the color didn't resolve to a color value, but something like a CSS variable, we can't
97+
// fade it out so we fall back to reducing the element opacity. Note that we don't use the
98+
// $mat-datepicker-today-fade-amount, because hint text usually has some opacity applied
99+
// to it already and we don't want them to stack on top of each other.
100+
opacity: 0.5;
101+
}
82102
}
83103

84104
@include _mat-datepicker-color(map-get($theme, primary));

‎src/lib/sidenav/_sidenav-theme.scss

+15-5
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@
1010
$background: map-get($theme, background);
1111
$foreground: map-get($theme, foreground);
1212

13-
// We use invert() here to have the darken the background color expected to be used. If the
14-
// background is light, we use a dark backdrop. If the background is dark,
15-
// we use a light backdrop.
16-
$drawer-backdrop-color: invert(mat-color($background, card, 0.6));
1713
$drawer-background-color: mat-color($background, dialog);
1814
$drawer-container-background-color: mat-color($background, background);
1915
$drawer-push-background-color: mat-color($background, dialog);
@@ -59,7 +55,21 @@
5955
}
6056

6157
.mat-drawer-backdrop.mat-drawer-shown {
62-
background-color: $drawer-backdrop-color;
58+
$opacity: 0.6;
59+
$backdrop-color: mat-color($background, card, $opacity);
60+
61+
@if (type-of($backdrop-color) == color) {
62+
// We use invert() here to have the darken the background color expected to be used. If the
63+
// background is light, we use a dark backdrop. If the background is dark,
64+
// we use a light backdrop.
65+
background-color: invert($backdrop-color);
66+
}
67+
@else {
68+
// If we couldn't resolve the backdrop color to a color value, fall back to using
69+
// `opacity` to make it opaque since its end value could be a solid color.
70+
background-color: $backdrop-color;
71+
opacity: $opacity;
72+
}
6373
}
6474
}
6575

‎src/lib/sort/_sort-theme.scss

+14-6
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,22 @@
33
$foreground: map-get($theme, foreground);
44

55
.mat-sort-header-arrow {
6-
// Because the arrow is made up of multiple elements that are stacked on top of each other,
7-
// we can't use the semi-trasparent color from the theme directly. We convert it into a solid
8-
// color by taking the opacity from the rgba value and using the value to determine the
9-
// percentage of the background to put into foreground when mixing the colors together.
106
$table-background: mat-color($background, 'card');
117
$text-color: mat-color($foreground, secondary-text);
12-
$text-opacity: opacity($text-color);
13-
color: mix($table-background, rgba($text-color, 1), (1 - $text-opacity) * 100%);
8+
9+
// Because the arrow is made up of multiple elements that are stacked on top of each other,
10+
// we can't use the semi-trasparent color from the theme directly. If the value is a color
11+
// *type*, we convert it into a solid color by taking the opacity from the rgba value and
12+
// using the value to determine the percentage of the background to put into foreground
13+
// when mixing the colors together. Otherwise, if it resolves to something different
14+
// (e.g. it resolves to a CSS variable), we use the color directly.
15+
@if (type-of($table-background) == color and type-of($text-color) == color) {
16+
$text-opacity: opacity($text-color);
17+
color: mix($table-background, rgba($text-color, 1), (1 - $text-opacity) * 100%);
18+
}
19+
@else {
20+
color: $text-color;
21+
}
1422
}
1523
}
1624

‎tools/package-tools/gulp/build-scss-pipeline.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ gulpSass.compiler = nodeSass;
1717

1818
/** Create a gulp task that builds SCSS files. */
1919
export function buildScssPipeline(sourceDir: string, minifyOutput = false) {
20-
return src(join(sourceDir, '**/*.scss'))
20+
return src(join(sourceDir, '**/!(test-).scss'))
2121
.pipe(gulpSass({includePaths: sassIncludePaths}).on('error', gulpSass.logError))
2222
.pipe(gulpIf(minifyOutput, gulpCleanCss()));
2323
}

0 commit comments

Comments
 (0)
Please sign in to comment.