Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit cae51a6

Browse files
topherfangiojelbourn
authored andcommitted
fix(toast): Hide scrollbars during animation.
During animation, certain browsers would show scroll bars if the toast was positioned at the bottom of the parent container. Fix by wrapping the animated portions in a div with hidden overflow. Also, update documentation with notes about positioning and recommendations. BREAKING CHANGE md-toast now applies the enter/leave animations to an inner div with a class `md-toast-content`. If you have customized the animations or other styles of your toast, you will need to update your CSS to account for the new wrapper. Fixes #2936. Closes #6029
1 parent 7edda11 commit cae51a6

File tree

4 files changed

+115
-85
lines changed

4 files changed

+115
-85
lines changed

src/components/toast/toast-theme.scss

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
md-toast.md-THEME_NAME-theme {
2-
background-color: #323232;
3-
color: '{{background-50}}';
4-
5-
.md-button {
2+
.md-toast-content {
3+
background-color: #323232;
64
color: '{{background-50}}';
7-
&.md-highlight {
8-
color: '{{primary-A200}}';
9-
&.md-accent {
10-
color: '{{accent-A200}}';
11-
}
12-
&.md-warn {
13-
color: '{{warn-A200}}';
5+
6+
.md-button {
7+
color: '{{background-50}}';
8+
&.md-highlight {
9+
color: '{{primary-A200}}';
10+
&.md-accent {
11+
color: '{{accent-A200}}';
12+
}
13+
&.md-warn {
14+
color: '{{warn-A200}}';
15+
}
1416
}
1517
}
1618
}

src/components/toast/toast.js

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -62,19 +62,6 @@ function MdToastDirective($mdToast) {
6262
* </div>
6363
* </hljs>
6464
*
65-
* Additionally, during animation, we will add the `md-toast-animating` class to the parent
66-
* container. This defines a simple rule of `overflow: hidden !important;` to ensure that
67-
* scrollbars are not visible on the parent during animation if you use a different overflow style.
68-
*
69-
* If you need to override this, you can use the following CSS, but be aware that it may cause
70-
* scrollbars to intermittently appear.
71-
*
72-
* <hljs lang="css">
73-
* .md-toast-animating {
74-
* overflow: auto !important;
75-
* }
76-
* </hljs>
77-
*
7865
* @usage
7966
* <hljs lang="html">
8067
* <div ng-controller="MyController">
@@ -246,16 +233,17 @@ function MdToastProvider($$interimElementProvider) {
246233
methods: ['textContent', 'content', 'action', 'highlightAction', 'theme', 'parent'],
247234
options: /* @ngInject */ function($mdToast, $mdTheming) {
248235
var opts = {
249-
template: [
250-
'<md-toast md-theme="{{ toast.theme }}" ng-class="{\'md-capsule\': toast.capsule}">',
251-
'<span flex role="alert" aria-relevant="all" aria-atomic="true">' +
252-
'{{ toast.content }}' +
253-
'</span>',
254-
'<md-button class="md-action" ng-if="toast.action" ng-click="toast.resolve()" ng-class="{\'md-highlight\': toast.highlightAction}">',
255-
'{{ toast.action }}',
256-
'</md-button>',
257-
'</md-toast>'
258-
].join(''),
236+
template:
237+
'<md-toast md-theme="{{ toast.theme }}" ng-class="{\'md-capsule\': toast.capsule}">' +
238+
' <div class="md-toast-content">' +
239+
' <span flex role="alert" aria-relevant="all" aria-atomic="true">' +
240+
' {{ toast.content }}' +
241+
' </span>' +
242+
' <md-button class="md-action" ng-if="toast.action" ng-click="toast.resolve()" ng-class="{\'md-highlight\': toast.highlightAction}">' +
243+
' {{ toast.action }}' +
244+
' </md-button>' +
245+
' </div>' +
246+
'</md-toast>',
259247
controller: /* @ngInject */ function mdToastCtrl($scope) {
260248
var self = this;
261249
$scope.$watch(function() { return activeToastContent; }, function() {

src/components/toast/toast.scss

Lines changed: 82 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,107 @@
11
// See height set globally, depended on by buttons
22

3-
43
md-toast {
5-
display: flex;
6-
position:absolute;
4+
position: absolute;
75
z-index: $z-index-toast;
86

97
box-sizing: border-box;
10-
align-items: center;
8+
cursor: default;
9+
overflow: hidden;
1110

12-
min-height: 48px;
13-
padding-left: 24px;
14-
padding-right: 24px;
11+
// Add some padding to the outer toast container so that the wrapper's box shadow is visible
12+
padding: $toast-margin;
1513

16-
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
17-
border-radius: 2px;
18-
font-size: 14px;
19-
cursor: default;
14+
// Setup opacity transition on whole toast
15+
opacity: 1;
16+
transition: $swift-ease-out;
2017

21-
height: 0px;
22-
max-height: 7*$toast-height;
23-
max-width: 100%;
18+
.md-toast-content {
19+
display: flex;
20+
align-items: center;
2421

25-
overflow:hidden;
22+
height: 0;
23+
max-height: 7 * $toast-height;
24+
max-width: 100%;
25+
min-height: 48px;
26+
padding-left: 24px;
27+
padding-right: 24px;
28+
29+
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
30+
border-radius: 2px;
31+
font-size: 14px;
32+
33+
overflow: hidden;
34+
35+
// Setup for transform transitions on inner content
36+
transform: translate3d(0, 0, 0) rotateZ(0deg);
37+
transition: $swift-ease-out;
38+
}
2639

2740
&.md-capsule {
2841
border-radius: 24px;
29-
}
3042

31-
opacity: 1;
32-
transform: translate3d(0,0,0) rotateZ(0deg);
33-
transition: $swift-ease-out;
43+
.md-toast-content {
44+
border-radius: 24px;
45+
}
46+
}
3447

3548
&.ng-leave-active {
36-
transition: $swift-ease-in;
49+
.md-toast-content {
50+
transition: $swift-ease-in;
51+
}
3752
}
3853

3954
/* Transition differently when swiping */
4055
&.md-swipeleft,
4156
&.md-swiperight,
4257
&.md-swipeup,
4358
&.md-swipedown {
44-
transition: $swift-ease-out;
59+
.md-toast-content {
60+
transition: $swift-ease-out;
61+
}
4562
}
4663

4764
&.ng-enter {
48-
transform: translate3d(0, 100%, 0);
65+
opacity: 0;
66+
.md-toast-content {
67+
transform: translate3d(0, 100%, 0);
68+
}
4969
&.md-top {
50-
transform: translate3d(0, -100%, 0);
70+
.md-toast-content {
71+
transform: translate3d(0, -100%, 0);
72+
}
5173
}
52-
opacity: 0;
5374
&.ng-enter-active {
54-
transform: translate3d(0, 0, 0);
5575
opacity: 1;
76+
.md-toast-content {
77+
transform: translate3d(0, 0, 0);
78+
}
5679
}
5780
}
5881
/*
5982
* When the toast doesn't take up the whole screen,
6083
* make it rotate when the user swipes it away
6184
*/
6285
&.ng-leave.ng-leave-active {
63-
opacity: 0;
64-
transform: translate3d(0, 100%, 0);
86+
.md-toast-content {
87+
opacity: 0;
88+
transform: translate3d(0, 100%, 0);
89+
}
6590

6691
&.md-swipeup {
67-
transform: translate3d(0, -50%, 0);
92+
.md-toast-content {
93+
transform: translate3d(0, -50%, 0);
94+
}
6895
}
6996
&.md-swipedown {
70-
transform: translate3d(0, 50%, 0);
97+
.md-toast-content {
98+
transform: translate3d(0, 50%, 0);
99+
}
71100
}
72101
&.md-top {
73-
transform: translate3d(0, -100%, 0);
102+
.md-toast-content {
103+
transform: translate3d(0, -100%, 0);
104+
}
74105
}
75106
}
76107

@@ -100,28 +131,33 @@ md-toast {
100131

101132
&.ng-leave.ng-leave-active {
102133
&.md-swipeup {
103-
transform: translate3d(0, -50%, 0);
134+
.md-toast-content {
135+
transform: translate3d(0, -50%, 0);
136+
}
104137
}
105138
&.md-swipedown {
106-
transform: translate3d(0, 50%, 0);
139+
.md-toast-content {
140+
transform: translate3d(0, 50%, 0);
141+
}
107142
}
108143
}
109144
}
110145
}
146+
111147
@media (min-width: $layout-breakpoint-sm) {
112148
md-toast {
113-
min-width: 288px;
149+
min-width: 288px + $toast-margin * 2;
114150
&.md-bottom {
115-
bottom: $toast-margin;
151+
bottom: 0;
116152
}
117153
&.md-left {
118-
left: $toast-margin;
154+
left: 0;
119155
}
120156
&.md-right {
121-
right: $toast-margin;
157+
right: 0;
122158
}
123159
&.md-top {
124-
top: $toast-margin;
160+
top: 0;
125161
}
126162

127163
/*
@@ -130,23 +166,27 @@ md-toast {
130166
*/
131167
&.ng-leave.ng-leave-active {
132168
&.md-swipeleft {
133-
transform: translate3d(-50%, 0, 0);
169+
.md-toast-content {
170+
transform: translate3d(-50%, 0, 0);
171+
}
134172
}
135173
&.md-swiperight {
136-
transform: translate3d(50%, 0, 0);
174+
.md-toast-content {
175+
transform: translate3d(50%, 0, 0);
176+
}
137177
}
138178
}
139179
}
140180
}
141181

142182
@media (min-width: $layout-breakpoint-lg) {
143183
md-toast {
144-
max-width: $baseline-grid * 71;
184+
.md-toast-content {
185+
max-width: $baseline-grid * 71;
186+
}
145187
}
146188
}
147189

148-
149-
150190
@media screen and (-ms-high-contrast: active) {
151191
md-toast {
152192
border: 1px solid #fff;

src/components/toast/toast.spec.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ describe('$mdToast service', function() {
4343

4444
$material.flushOutstandingAnimations();
4545

46-
expect(parent.find('span').text()).toBe('Do something');
46+
expect(parent.find('span').text().trim()).toBe('Do something');
4747
expect(parent.find('md-toast')).toHaveClass('md-capsule');
4848
expect(parent.find('md-toast').attr('md-theme')).toBe('some-theme');
4949

@@ -58,7 +58,7 @@ describe('$mdToast service', function() {
5858
$rootScope.$digest();
5959
$mdToast.updateContent('Goodbye world');
6060
$rootScope.$digest();
61-
expect($rootElement.find('span').text()).toBe('Goodbye world');
61+
expect($rootElement.find('span').text().trim()).toBe('Goodbye world');
6262
}));
6363

6464
it('supports an action toast', inject(function($mdToast, $rootScope, $material) {
@@ -76,7 +76,7 @@ describe('$mdToast service', function() {
7676
});
7777
$material.flushOutstandingAnimations();
7878
var button = parent.find('button');
79-
expect(button.text()).toBe('Click me');
79+
expect(button.text().trim()).toBe('Click me');
8080
button.triggerHandler('click');
8181
$material.flushInterimElement();
8282
expect(resolved).toBe(true);
@@ -100,8 +100,8 @@ describe('$mdToast service', function() {
100100
var content = parent.find('span').eq(0);
101101
var button = parent.find('button');
102102

103-
expect(content.text()).toBe('Do something');
104-
expect(button.text()).toBe('Click me');
103+
expect(content.text().trim()).toBe('Do something');
104+
expect(button.text().trim()).toBe('Click me');
105105
}));
106106

107107

@@ -119,8 +119,8 @@ describe('$mdToast service', function() {
119119
var content = parent.find('span').eq(0);
120120
var button = parent.find('button');
121121

122-
expect(content.text()).toBe('Do something');
123-
expect(button.text()).toBe('Click me');
122+
expect(content.text().trim()).toBe('Do something');
123+
expect(button.text().trim()).toBe('Click me');
124124
}));
125125
});
126126

@@ -145,7 +145,7 @@ describe('$mdToast service', function() {
145145
});
146146
var toast = $rootElement.find('md-toast');
147147
$timeout.flush();
148-
expect(toast.text()).toBe('1234');
148+
expect(toast.text().trim()).toBe('1234');
149149
}));
150150

151151
it('should have templateUrl', inject(function($timeout, $rootScope, $templateCache, $rootElement) {
@@ -154,7 +154,7 @@ describe('$mdToast service', function() {
154154
templateUrl: 'template.html',
155155
});
156156
var toast = $rootElement.find('md-toast');
157-
expect(toast.text()).toBe('hello, 1');
157+
expect(toast.text().trim()).toBe('hello, 1');
158158
}));
159159

160160
it('should add position class to toast', inject(function($rootElement, $timeout) {

0 commit comments

Comments
 (0)