Skip to content

Commit

Permalink
fix(material/sidenav): prevent the content from jumping when hydrated (
Browse files Browse the repository at this point in the history
…#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.
  • Loading branch information
crisbeto authored Nov 11, 2024
1 parent 80fdf19 commit 4f00d26
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/material/sidenav/drawer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ $drawer-over-drawer-z-index: 4;
height: 100%;
overflow: auto;

&.mat-drawer-content-hidden {
opacity: 0;
}

.mat-drawer-transition & {
transition: {
duration: variables.$swift-ease-out-duration;
Expand Down
20 changes: 20 additions & 0 deletions src/material/sidenav/drawer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export function MAT_DRAWER_DEFAULT_AUTOSIZE_FACTORY(): boolean {
'class': 'mat-drawer-content',
'[style.margin-left.px]': '_container._contentMargins.left',
'[style.margin-right.px]': '_container._contentMargins.right',
'[class.mat-drawer-content-hidden]': '_shouldBeHidden()',
},
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
Expand All @@ -104,6 +105,7 @@ export function MAT_DRAWER_DEFAULT_AUTOSIZE_FACTORY(): boolean {
],
})
export class MatDrawerContent extends CdkScrollable implements AfterContentInit {
private _platform = inject(Platform);
private _changeDetectorRef = inject(ChangeDetectorRef);
_container = inject(MatDrawerContainer);

Expand All @@ -122,6 +124,24 @@ export class MatDrawerContent extends CdkScrollable implements AfterContentInit
this._changeDetectorRef.markForCheck();
});
}

/** Determines whether the content element should be hidden from the user. */
protected _shouldBeHidden(): boolean {
// In some modes the content is pushed based on the width of the opened sidenavs, however on
// the server we can't measure the sidenav so the margin is always zero. This can cause the
// content to jump around when it's rendered on the server and hydrated on the client. We
// avoid it by hiding the content on the initial render and then showing it once the sidenav
// has been measured on the client.
if (this._platform.isBrowser) {
return false;
}

const {start, end} = this._container;
return (
(start != null && start.mode !== 'over' && start.opened) ||
(end != null && end.mode !== 'over' && end.opened)
);
}
}

/**
Expand Down
2 changes: 0 additions & 2 deletions src/material/sidenav/sidenav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ import {CdkScrollable} from '@angular/cdk/scrolling';
template: '<ng-content></ng-content>',
host: {
'class': 'mat-drawer-content mat-sidenav-content',
'[style.margin-left.px]': '_container._contentMargins.left',
'[style.margin-right.px]': '_container._contentMargins.right',
},
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
Expand Down
1 change: 1 addition & 0 deletions tools/public_api_guard/material/sidenav.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export class MatDrawerContent extends CdkScrollable implements AfterContentInit
_container: MatDrawerContainer;
// (undocumented)
ngAfterContentInit(): void;
protected _shouldBeHidden(): boolean;
// (undocumented)
static ɵcmp: i0.ɵɵComponentDeclaration<MatDrawerContent, "mat-drawer-content", never, {}, {}, never, ["*"], true, never>;
// (undocumented)
Expand Down

0 comments on commit 4f00d26

Please sign in to comment.