diff --git a/src/cdk/table/sticky-styler.ts b/src/cdk/table/sticky-styler.ts index afa44787e417..1cb73461f1af 100644 --- a/src/cdk/table/sticky-styler.ts +++ b/src/cdk/table/sticky-styler.ts @@ -21,6 +21,7 @@ export type StickyDirection = 'top' | 'bottom' | 'left' | 'right'; */ export const STICKY_DIRECTIONS: StickyDirection[] = ['top', 'bottom', 'left', 'right']; + /** * Applies and removes sticky positioning styles to the `CdkTable` rows and columns cells. * @docs-private @@ -34,12 +35,16 @@ export class StickyStyler { * @param direction The directionality context of the table (ltr/rtl); affects column positioning * by reversing left/right positions. * @param _isBrowser Whether the table is currently being rendered on the server or the client. + * @param _needsPositionStickyOnElement Whether we need to specify position: sticky on cells + * using inline styles. If false, it is assumed that position: sticky is included in + * the component stylesheet for _stickCellCss. */ constructor(private _isNativeHtmlTable: boolean, private _stickCellCss: string, public direction: Direction, private _coalescedStyleScheduler: _CoalescedStyleScheduler, - private _isBrowser = true) { } + private _isBrowser = true, + private readonly _needsPositionStickyOnElement = true) { } /** * Clears the sticky positioning styles from the row and its cells by resetting the `position` @@ -204,13 +209,21 @@ export class StickyStyler { for (const dir of stickyDirections) { element.style[dir] = ''; } - element.style.zIndex = this._getCalculatedZIndex(element); // If the element no longer has any more sticky directions, remove sticky positioning and // the sticky CSS class. - const hasDirection = STICKY_DIRECTIONS.some(dir => !!element.style[dir]); - if (!hasDirection) { - element.style.position = ''; + // Short-circuit checking element.style[dir] for stickyDirections as they + // were already removed above. + const hasDirection = STICKY_DIRECTIONS.some(dir => + stickyDirections.indexOf(dir) === -1 && element.style[dir]); + if (hasDirection) { + element.style.zIndex = this._getCalculatedZIndex(element); + } else { + // When not hasDirection, _getCalculatedZIndex will always return ''. + element.style.zIndex = ''; + if (this._needsPositionStickyOnElement) { + element.style.position = ''; + } element.classList.remove(this._stickCellCss); } } @@ -223,8 +236,10 @@ export class StickyStyler { _addStickyStyle(element: HTMLElement, dir: StickyDirection, dirValue: number) { element.classList.add(this._stickCellCss); element.style[dir] = `${dirValue}px`; - element.style.cssText += 'position: -webkit-sticky; position: sticky; '; element.style.zIndex = this._getCalculatedZIndex(element); + if (this._needsPositionStickyOnElement) { + element.style.cssText += 'position: -webkit-sticky; position: sticky; '; + } } /** diff --git a/src/cdk/table/table.ts b/src/cdk/table/table.ts index dde7c98e496f..602fd186351d 100644 --- a/src/cdk/table/table.ts +++ b/src/cdk/table/table.ts @@ -310,6 +310,13 @@ export class CdkTable implements AfterContentChecked, CollectionViewer, OnDes */ protected stickyCssClass: string = 'cdk-table-sticky'; + /** + * Whether to manually add positon: sticky to all sticky cell elements. Not needed if + * the position is set in a selector associated with the value of stickyCssClass. May be + * overridden by table subclasses + */ + protected needsPositionStickyOnElement = true; + /** Whether the no data row is currently showing anything. */ private _isShowingNoDataRow = false; @@ -1096,7 +1103,7 @@ export class CdkTable implements AfterContentChecked, CollectionViewer, OnDes const direction: Direction = this._dir ? this._dir.value : 'ltr'; this._stickyStyler = new StickyStyler( this._isNativeHtmlTable, this.stickyCssClass, direction, this._coalescedStyleScheduler, - this._platform.isBrowser); + this._platform.isBrowser, this.needsPositionStickyOnElement); (this._dir ? this._dir.change : observableOf()) .pipe(takeUntil(this._onDestroy)) .subscribe(value => { diff --git a/src/material-experimental/mdc-table/BUILD.bazel b/src/material-experimental/mdc-table/BUILD.bazel index d8dbc9bf3595..c867dd8c517b 100644 --- a/src/material-experimental/mdc-table/BUILD.bazel +++ b/src/material-experimental/mdc-table/BUILD.bazel @@ -44,6 +44,7 @@ sass_binary( deps = [ "//src/material-experimental/mdc-helpers:mdc_helpers_scss_lib", "//src/material-experimental/mdc-helpers:mdc_scss_deps_lib", + "//src/material/core:core_scss_lib", ], ) diff --git a/src/material-experimental/mdc-table/table.scss b/src/material-experimental/mdc-table/table.scss index 2b0af8558604..d615377e156a 100644 --- a/src/material-experimental/mdc-table/table.scss +++ b/src/material-experimental/mdc-table/table.scss @@ -1,4 +1,9 @@ +@use '../../material/core/style/vendor-prefixes'; @import '@material/data-table/mixins.import'; @import '../mdc-helpers/mdc-helpers'; @include mdc-data-table-core-styles($query: $mat-base-styles-without-animation-query); + +.mat-table-sticky { + @include vendor-prefixes.position-sticky; +} diff --git a/src/material-experimental/mdc-table/table.ts b/src/material-experimental/mdc-table/table.ts index 1e5ae437a5a8..00726afb7b4d 100644 --- a/src/material-experimental/mdc-table/table.ts +++ b/src/material-experimental/mdc-table/table.ts @@ -30,6 +30,9 @@ export class MatTable extends CdkTable implements OnInit { /** Overrides the sticky CSS class set by the `CdkTable`. */ protected stickyCssClass = 'mat-mdc-table-sticky'; + /** Overrides the need to add position: sticky on every sticky cell element in `CdkTable`. */ + protected needsPositionStickyOnElement = false; + // After ngOnInit, the `CdkTable` has created and inserted the table sections (thead, tbody, // tfoot). MDC requires the `mdc-data-table__content` class to be added to the body. ngOnInit() { diff --git a/src/material/core/style/_vendor-prefixes.scss b/src/material/core/style/_vendor-prefixes.scss index 196e99ce40f0..8d9ecbac4409 100644 --- a/src/material/core/style/_vendor-prefixes.scss +++ b/src/material/core/style/_vendor-prefixes.scss @@ -38,4 +38,9 @@ -webkit-backface-visibility: $value; backface-visibility: $value; } + +@mixin position-sticky { + position: -webkit-sticky; + position: sticky; +} /* stylelint-enable */ diff --git a/src/material/table/BUILD.bazel b/src/material/table/BUILD.bazel index 6e8a3b370031..adec57fe918c 100644 --- a/src/material/table/BUILD.bazel +++ b/src/material/table/BUILD.bazel @@ -38,6 +38,7 @@ sass_library( sass_binary( name = "table_scss", src = "table.scss", + deps = ["//src/material/core:core_scss_lib"], ) ng_test_library( diff --git a/src/material/table/table.scss b/src/material/table/table.scss index 5e906293cc30..8ee7994267e3 100644 --- a/src/material/table/table.scss +++ b/src/material/table/table.scss @@ -1,3 +1,5 @@ +@use '../core/style/vendor-prefixes'; + $mat-header-row-height: 56px; $mat-row-height: 48px; $mat-row-horizontal-padding: 24px; @@ -114,3 +116,7 @@ th.mat-header-cell:last-of-type, td.mat-cell:last-of-type, td.mat-footer-cell:la padding-left: $mat-row-horizontal-padding; } } + +.mat-table-sticky { + @include vendor-prefixes.position-sticky; +} diff --git a/src/material/table/table.ts b/src/material/table/table.ts index f86f0eae9ea8..7b47b91cf95d 100644 --- a/src/material/table/table.ts +++ b/src/material/table/table.ts @@ -38,4 +38,7 @@ import {ChangeDetectionStrategy, Component, ViewEncapsulation} from '@angular/co export class MatTable extends CdkTable { /** Overrides the sticky CSS class set by the `CdkTable`. */ protected stickyCssClass = 'mat-table-sticky'; + + /** Overrides the need to add position: sticky on every sticky cell element in `CdkTable`. */ + protected needsPositionStickyOnElement = false; } diff --git a/tools/public_api_guard/cdk/table.d.ts b/tools/public_api_guard/cdk/table.d.ts index aa1abeac5695..b49c72ae2d17 100644 --- a/tools/public_api_guard/cdk/table.d.ts +++ b/tools/public_api_guard/cdk/table.d.ts @@ -204,6 +204,7 @@ export declare class CdkTable implements AfterContentChecked, CollectionViewe set dataSource(dataSource: CdkTableDataSourceInput); get multiTemplateDataRows(): boolean; set multiTemplateDataRows(v: boolean); + protected needsPositionStickyOnElement: boolean; protected stickyCssClass: string; get trackBy(): TrackByFunction; set trackBy(fn: TrackByFunction); @@ -316,7 +317,7 @@ export declare type StickyDirection = 'top' | 'bottom' | 'left' | 'right'; export declare class StickyStyler { direction: Direction; - constructor(_isNativeHtmlTable: boolean, _stickCellCss: string, direction: Direction, _coalescedStyleScheduler: _CoalescedStyleScheduler, _isBrowser?: boolean); + constructor(_isNativeHtmlTable: boolean, _stickCellCss: string, direction: Direction, _coalescedStyleScheduler: _CoalescedStyleScheduler, _isBrowser?: boolean, _needsPositionStickyOnElement?: boolean); _addStickyStyle(element: HTMLElement, dir: StickyDirection, dirValue: number): void; _getCalculatedZIndex(element: HTMLElement): string; _getCellWidths(row: HTMLElement): number[]; diff --git a/tools/public_api_guard/material/table.d.ts b/tools/public_api_guard/material/table.d.ts index 20d2f60600fb..d28a4b569b05 100644 --- a/tools/public_api_guard/material/table.d.ts +++ b/tools/public_api_guard/material/table.d.ts @@ -74,6 +74,7 @@ export declare class MatRowDef extends CdkRowDef { } export declare class MatTable extends CdkTable { + protected needsPositionStickyOnElement: boolean; protected stickyCssClass: string; static ɵcmp: i0.ɵɵComponentDefWithMeta, "mat-table, table[mat-table]", ["matTable"], {}, {}, never, ["caption", "colgroup, col"]>; static ɵfac: i0.ɵɵFactoryDef, never>;