Skip to content

Commit 4f00d26

Browse files
authored
fix(material/sidenav): prevent the content from jumping when hydrated (angular#29991)
Fixes that the content of the sidenav was jumping when the page is hydrated, because we can't measure the sidenav on the server.
1 parent 80fdf19 commit 4f00d26

File tree

4 files changed

+25
-2
lines changed

4 files changed

+25
-2
lines changed

src/material/sidenav/drawer.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ $drawer-over-drawer-z-index: 4;
109109
height: 100%;
110110
overflow: auto;
111111

112+
&.mat-drawer-content-hidden {
113+
opacity: 0;
114+
}
115+
112116
.mat-drawer-transition & {
113117
transition: {
114118
duration: variables.$swift-ease-out-duration;

src/material/sidenav/drawer.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export function MAT_DRAWER_DEFAULT_AUTOSIZE_FACTORY(): boolean {
9393
'class': 'mat-drawer-content',
9494
'[style.margin-left.px]': '_container._contentMargins.left',
9595
'[style.margin-right.px]': '_container._contentMargins.right',
96+
'[class.mat-drawer-content-hidden]': '_shouldBeHidden()',
9697
},
9798
changeDetection: ChangeDetectionStrategy.OnPush,
9899
encapsulation: ViewEncapsulation.None,
@@ -104,6 +105,7 @@ export function MAT_DRAWER_DEFAULT_AUTOSIZE_FACTORY(): boolean {
104105
],
105106
})
106107
export class MatDrawerContent extends CdkScrollable implements AfterContentInit {
108+
private _platform = inject(Platform);
107109
private _changeDetectorRef = inject(ChangeDetectorRef);
108110
_container = inject(MatDrawerContainer);
109111

@@ -122,6 +124,24 @@ export class MatDrawerContent extends CdkScrollable implements AfterContentInit
122124
this._changeDetectorRef.markForCheck();
123125
});
124126
}
127+
128+
/** Determines whether the content element should be hidden from the user. */
129+
protected _shouldBeHidden(): boolean {
130+
// In some modes the content is pushed based on the width of the opened sidenavs, however on
131+
// the server we can't measure the sidenav so the margin is always zero. This can cause the
132+
// content to jump around when it's rendered on the server and hydrated on the client. We
133+
// avoid it by hiding the content on the initial render and then showing it once the sidenav
134+
// has been measured on the client.
135+
if (this._platform.isBrowser) {
136+
return false;
137+
}
138+
139+
const {start, end} = this._container;
140+
return (
141+
(start != null && start.mode !== 'over' && start.opened) ||
142+
(end != null && end.mode !== 'over' && end.opened)
143+
);
144+
}
125145
}
126146

127147
/**

src/material/sidenav/sidenav.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ import {CdkScrollable} from '@angular/cdk/scrolling';
3030
template: '<ng-content></ng-content>',
3131
host: {
3232
'class': 'mat-drawer-content mat-sidenav-content',
33-
'[style.margin-left.px]': '_container._contentMargins.left',
34-
'[style.margin-right.px]': '_container._contentMargins.right',
3533
},
3634
changeDetection: ChangeDetectionStrategy.OnPush,
3735
encapsulation: ViewEncapsulation.None,

tools/public_api_guard/material/sidenav.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ export class MatDrawerContent extends CdkScrollable implements AfterContentInit
136136
_container: MatDrawerContainer;
137137
// (undocumented)
138138
ngAfterContentInit(): void;
139+
protected _shouldBeHidden(): boolean;
139140
// (undocumented)
140141
static ɵcmp: i0.ɵɵComponentDeclaration<MatDrawerContent, "mat-drawer-content", never, {}, {}, never, ["*"], true, never>;
141142
// (undocumented)

0 commit comments

Comments
 (0)