diff --git a/packages/grid/src/vaadin-grid-keyboard-navigation-mixin.js b/packages/grid/src/vaadin-grid-keyboard-navigation-mixin.js index 4908a28eba..6d1d748569 100644 --- a/packages/grid/src/vaadin-grid-keyboard-navigation-mixin.js +++ b/packages/grid/src/vaadin-grid-keyboard-navigation-mixin.js @@ -751,6 +751,7 @@ export const KeyboardNavigationMixin = (superClass) => _detectInteracting(e) { const isInteracting = e.composedPath().some((el) => el.localName === 'vaadin-grid-cell-content'); this._setInteracting(isInteracting); + this.__updateHorizontalScrollPosition(); } /** @private */ diff --git a/packages/grid/src/vaadin-grid-scroll-mixin.js b/packages/grid/src/vaadin-grid-scroll-mixin.js index b02cb3b74f..5e15ae9a9a 100644 --- a/packages/grid/src/vaadin-grid-scroll-mixin.js +++ b/packages/grid/src/vaadin-grid-scroll-mixin.js @@ -245,26 +245,33 @@ export const ScrollMixin = (superClass) => __updateHorizontalScrollPosition() { const scrollWidth = this.$.table.scrollWidth; const clientWidth = this.$.table.clientWidth; - const scrollLeft = this.__getNormalizedScrollLeft(this.$.table); + const scrollLeft = Math.max(0, this.$.table.scrollLeft); + const normalizedScrollLeft = this.__getNormalizedScrollLeft(this.$.table); + + // Position header, footer and items container + const transform = `translate(${-scrollLeft}px, 0)`; + this.$.header.style.transform = transform; + this.$.footer.style.transform = transform; + this.$.items.style.transform = transform; + + // Position frozen cells + const x = this.__isRTL ? normalizedScrollLeft + clientWidth - scrollWidth : scrollLeft; + const transformFrozen = `translate(${x}px, 0)`; + for (let i = 0; i < this._frozenCells.length; i++) { + this._frozenCells[i].style.transform = transformFrozen; + } // Position cells frozen to end - const remaining = scrollLeft + clientWidth - scrollWidth; - - this.$.table.style.setProperty('--_grid-horizontal-scroll-remaining', remaining + 'px'); - this.$.table.style.setProperty('--_grid-horizontal-scroll-position', -this._scrollLeft + 'px'); - - if (this.__isRTL) { - // Translating the sticky sections using a CSS variable works nicely on LTR. - // On RTL, it causes jumpy behavior (on Desktop Safari) so we need to translate manually. - const transformFrozen = `translate(${remaining}px, 0)`; - for (let i = 0; i < this._frozenCells.length; i++) { - this._frozenCells[i].style.transform = transformFrozen; - } + const remaining = this.__isRTL ? normalizedScrollLeft : scrollLeft + clientWidth - scrollWidth; + const transformFrozenToEnd = `translate(${remaining}px, 0)`; + for (let i = 0; i < this._frozenToEndCells.length; i++) { + this._frozenToEndCells[i].style.transform = transformFrozenToEnd; + } - const transformFrozenToEnd = `translate(${scrollLeft}px, 0)`; - for (let i = 0; i < this._frozenToEndCells.length; i++) { - this._frozenToEndCells[i].style.transform = transformFrozenToEnd; - } + // Only update the --_grid-horizontal-scroll-position custom property when navigating + // on row focus mode to avoid performance issues. + if (this.hasAttribute('navigating') && this.__rowFocusMode) { + this.$.table.style.setProperty('--_grid-horizontal-scroll-position', -x + 'px'); } } }; diff --git a/packages/grid/src/vaadin-grid-styles.js b/packages/grid/src/vaadin-grid-styles.js index 09b62d007b..7f019e7355 100644 --- a/packages/grid/src/vaadin-grid-styles.js +++ b/packages/grid/src/vaadin-grid-styles.js @@ -74,7 +74,6 @@ registerStyles( #header, #footer { - transform: translateX(var(--_grid-horizontal-scroll-position)); display: block; position: -webkit-sticky; position: sticky; @@ -102,7 +101,6 @@ registerStyles( } #items { - transform: translateX(var(--_grid-horizontal-scroll-position)); flex-grow: 1; flex-shrink: 0; display: block; @@ -164,15 +162,9 @@ registerStyles( display: none !important; } - [frozen] { - z-index: 2; - transform: translateX(calc(-1 * var(--_grid-horizontal-scroll-position))); - will-change: transform; - } - + [frozen], [frozen-to-end] { z-index: 2; - transform: translateX(var(--_grid-horizontal-scroll-remaining)); will-change: transform; } @@ -293,10 +285,6 @@ registerStyles( /* RTL specific styles */ - :host([dir='rtl']) *:is(#items, #header, #footer, [frozen], [frozen-to-end]) { - transform: none; - } - :host([dir='rtl']) #items, :host([dir='rtl']) #header, :host([dir='rtl']) #footer { diff --git a/packages/grid/test/keyboard-navigation.test.js b/packages/grid/test/keyboard-navigation.test.js index 1a656b9047..bfc1341f89 100644 --- a/packages/grid/test/keyboard-navigation.test.js +++ b/packages/grid/test/keyboard-navigation.test.js @@ -5,6 +5,7 @@ import { fixtureSync, focusin, isChrome, + isDesktopSafari, keyboardEventFor, keyDownOn, keyUpOn, @@ -1063,6 +1064,13 @@ describe('keyboard navigation', () => { flushGrid(grid); + // Force reflow to workaround a Safari rendering issue + if (isDesktopSafari) { + grid.style.display = 'flex'; + await nextFrame(); + grid.style.display = ''; + } + expect(grid.$.table.scrollLeft).to.equal(grid.$.table.scrollWidth - grid.$.table.offsetWidth); });