Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(material/sidenav): prevent the content from jumping when hydrated #29991

Merged
merged 1 commit into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading