Skip to content

Commit b090f6d

Browse files
crisbetojosephperrott
authored andcommitted
perf(tabs): use a transform to resize and move the ink bar (#10664)
Uses a transform, rather than `left` and `width` to move/resize the ink bar in order to ensure a smoother transition.
1 parent 7ceedc7 commit b090f6d

File tree

2 files changed

+20
-10
lines changed

2 files changed

+20
-10
lines changed

src/lib/tabs/_tabs-common.scss

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,23 @@ $mat-tab-animation-duration: 500ms !default;
5050
$height: 2px;
5151

5252
position: absolute;
53+
left: 0;
5354
bottom: 0;
5455
height: $height;
55-
transition: $mat-tab-animation-duration $ease-in-out-curve-function;
56+
width: 1px;
57+
transform-origin: 0;
5658

5759
.mat-tab-group-inverted-header & {
5860
bottom: auto;
5961
top: 0;
6062
}
6163

64+
&.mat-ink-bar-animations-enabled {
65+
transition: transform $mat-tab-animation-duration $ease-in-out-curve-function;
66+
}
67+
6268
@include cdk-high-contrast {
63-
outline: solid $height;
69+
border-bottom: solid $height;
6470
height: 0;
6571
}
6672
}

src/lib/tabs/ink-bar.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@
88

99
import {Directive, ElementRef, Inject, InjectionToken, NgZone} from '@angular/core';
1010

11-
1211
/**
1312
* Interface for a a MatInkBar positioner method, defining the positioning and width of the ink
1413
* bar in a set of tabs.
1514
*/
1615
// tslint:disable-next-line class-name Using leading underscore to denote internal interface.
1716
export interface _MatInkBarPositioner {
18-
(element: HTMLElement): { left: string, width: string };
17+
(element: HTMLElement): {left: number, width: number};
1918
}
2019

2120
/** Injection token for the MatInkBar's Positioner. */
@@ -31,8 +30,8 @@ export const _MAT_INK_BAR_POSITIONER =
3130
*/
3231
export function _MAT_INK_BAR_POSITIONER_FACTORY(): _MatInkBarPositioner {
3332
const method = (element: HTMLElement) => ({
34-
left: element ? (element.offsetLeft || 0) + 'px' : '0',
35-
width: element ? (element.offsetWidth || 0) + 'px' : '0',
33+
left: element ? (element.offsetLeft || 0) : 0,
34+
width: element ? (element.offsetWidth || 0) : 0,
3635
});
3736

3837
return method;
@@ -50,7 +49,7 @@ export function _MAT_INK_BAR_POSITIONER_FACTORY(): _MatInkBarPositioner {
5049
})
5150
export class MatInkBar {
5251
constructor(
53-
private _elementRef: ElementRef,
52+
private _elementRef: ElementRef<HTMLElement>,
5453
private _ngZone: NgZone,
5554
@Inject(_MAT_INK_BAR_POSITIONER) private _inkBarPositioner: _MatInkBarPositioner) { }
5655

@@ -87,9 +86,14 @@ export class MatInkBar {
8786
*/
8887
private _setStyles(element: HTMLElement) {
8988
const positions = this._inkBarPositioner(element);
90-
const inkBar: HTMLElement = this._elementRef.nativeElement;
89+
const inkBar = this._elementRef.nativeElement;
90+
91+
// We want to prevent the ink bar from animating on the initial load.
92+
// Enable animations only if the ink bar has been translated before.
93+
if (inkBar.style.transform) {
94+
inkBar.classList.add('mat-ink-bar-animations-enabled');
95+
}
9196

92-
inkBar.style.left = positions.left;
93-
inkBar.style.width = positions.width;
97+
inkBar.style.transform = `translateX(${positions.left}px) scaleX(${positions.width})`;
9498
}
9599
}

0 commit comments

Comments
 (0)