Skip to content

Commit 75632f9

Browse files
committed
fix(sidenav): prevent content from scrolling when sidenav is open
1 parent ca5339b commit 75632f9

File tree

3 files changed

+42
-14
lines changed

3 files changed

+42
-14
lines changed

src/components/sidenav/sidenav.scss

+7
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ $md-sidenav-push-background-color: md-color($md-background, dialog) !default;
6464
// TODO(hansl): Update this with a more robust solution.
6565
&[fullscreen] {
6666
@include md-sidenav-fullscreen();
67+
68+
&.md-sidenav-opened {
69+
overflow: hidden;
70+
}
6771
}
6872

6973
// Need this to take up space in the layout.
@@ -109,6 +113,9 @@ $md-sidenav-push-background-color: md-color($md-background, dialog) !default;
109113
z-index: 3;
110114
min-width: 5%;
111115

116+
// TODO(kara): revisit scrolling behavior for sidenavs
117+
overflow-y: auto;
118+
112119
background-color: $md-sidenav-background-color;
113120

114121
@include md-sidenav-transition(0, -100%);

src/components/sidenav/sidenav.ts

+31-9
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
Type,
1414
ChangeDetectionStrategy,
1515
EventEmitter,
16+
Renderer
1617
} from 'angular2/core';
1718
import {BaseException} from 'angular2/src/facade/exceptions';
1819
import {Dir} from '../../core/rtl/dir';
@@ -49,7 +50,7 @@ export class MdSidenav {
4950
@Input() mode: 'over' | 'push' | 'side' = 'over';
5051

5152
/** Whether the sidenav is opened. */
52-
@Input('opened') private _opened: boolean;
53+
@Input('opened') private _opened: boolean = false;
5354

5455
/** Event emitted when the sidenav is being opened. Use this to synchronize animations. */
5556
@Output('open-start') onOpenStart = new EventEmitter<void>();
@@ -247,7 +248,8 @@ export class MdSidenavLayout implements AfterContentInit {
247248
get start() { return this._start; }
248249
get end() { return this._end; }
249250

250-
constructor(@Optional() @Host() private _dir: Dir) {
251+
constructor(@Optional() @Host() private _dir: Dir, private _element: ElementRef,
252+
private _renderer: Renderer) {
251253
// If a `Dir` directive exists up the tree, listen direction changes and update the left/right
252254
// properties to point to the proper start/end.
253255
if (_dir != null) {
@@ -258,9 +260,28 @@ export class MdSidenavLayout implements AfterContentInit {
258260
ngAfterContentInit() {
259261
// On changes, assert on consistency.
260262
this._sidenavs.changes.subscribe(() => this._validateDrawers());
263+
this._sidenavs.forEach((sidenav: MdSidenav) => this._watchSidenavToggle(sidenav));
261264
this._validateDrawers();
262265
}
263266

267+
/*
268+
* Subscribes to sidenav events in order to set a class on the main layout element when the sidenav
269+
* is open and the backdrop is visible. This ensures any overflow on the layout element is properly
270+
* hidden.
271+
* */
272+
private _watchSidenavToggle(sidenav: MdSidenav): void {
273+
if (!sidenav || sidenav.mode === 'side') { return; }
274+
sidenav.onOpen.subscribe(() => this._setLayoutClass(sidenav, true));
275+
sidenav.onClose.subscribe(() => this._setLayoutClass(sidenav, false));
276+
}
277+
278+
/*
279+
* Toggles the 'md-sidenav-opened' class on the main 'md-sidenav-layout' element.
280+
* */
281+
private _setLayoutClass(sidenav: MdSidenav, bool: boolean): void {
282+
this._renderer.setElementClass(this._element.nativeElement, 'md-sidenav-opened', bool);
283+
}
284+
264285

265286
/** The sidenav at the start/end alignment, independent of direction. */
266287
private _start: MdSidenav;
@@ -318,9 +339,13 @@ export class MdSidenavLayout implements AfterContentInit {
318339
}
319340
}
320341

321-
private _isShowingBackdrop() {
322-
return (this._start != null && this._start.mode != 'side' && this._start.opened)
323-
|| (this._end != null && this._end.mode != 'side' && this._end.opened);
342+
private _isShowingBackdrop(): boolean {
343+
return (this._isSidenavOpen(this._start) && this._start.mode != 'side')
344+
|| (this._isSidenavOpen(this._end) && this._end.mode != 'side');
345+
}
346+
347+
private _isSidenavOpen(side: MdSidenav): boolean {
348+
return side != null && side.opened;
324349
}
325350

326351
/**
@@ -330,10 +355,7 @@ export class MdSidenavLayout implements AfterContentInit {
330355
* @private
331356
*/
332357
private _getSidenavEffectiveWidth(sidenav: MdSidenav, mode: string): number {
333-
if (sidenav != null && sidenav.mode == mode && sidenav.opened) {
334-
return sidenav._width;
335-
}
336-
return 0;
358+
return (this._isSidenavOpen(sidenav) && sidenav.mode == mode) ? sidenav._width : 0;
337359
}
338360

339361
private _getMarginLeft() {

src/demo-app/demo-app.scss

+4-5
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
}
1010

1111
md-sidenav {
12-
width: 15%;
12+
min-width: 15%;
1313

1414
[md-button] {
1515
width: 100%;
16-
position: absolute;
16+
position: relative;
1717
bottom: 0;
18-
margin-bottom: 24px;
18+
margin: 24px 0;
1919
}
2020
}
2121

@@ -39,5 +39,4 @@
3939
h1 {
4040
font-size: 20px;
4141
}
42-
}
43-
42+
}

0 commit comments

Comments
 (0)