diff --git a/src/material/sidenav/drawer.scss b/src/material/sidenav/drawer.scss index f7e89895a873..8f2fbc08beea 100644 --- a/src/material/sidenav/drawer.scss +++ b/src/material/sidenav/drawer.scss @@ -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; diff --git a/src/material/sidenav/drawer.ts b/src/material/sidenav/drawer.ts index b05af6537231..361440a53834 100644 --- a/src/material/sidenav/drawer.ts +++ b/src/material/sidenav/drawer.ts @@ -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, @@ -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); @@ -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) + ); + } } /** diff --git a/src/material/sidenav/sidenav.ts b/src/material/sidenav/sidenav.ts index e7214532f921..3a877964d9c2 100644 --- a/src/material/sidenav/sidenav.ts +++ b/src/material/sidenav/sidenav.ts @@ -30,8 +30,6 @@ import {CdkScrollable} from '@angular/cdk/scrolling'; template: '', 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, diff --git a/tools/public_api_guard/material/sidenav.md b/tools/public_api_guard/material/sidenav.md index 062c2ddddf52..8878fd1f9684 100644 --- a/tools/public_api_guard/material/sidenav.md +++ b/tools/public_api_guard/material/sidenav.md @@ -136,6 +136,7 @@ export class MatDrawerContent extends CdkScrollable implements AfterContentInit _container: MatDrawerContainer; // (undocumented) ngAfterContentInit(): void; + protected _shouldBeHidden(): boolean; // (undocumented) static ɵcmp: i0.ɵɵComponentDeclaration; // (undocumented)