-
Notifications
You must be signed in to change notification settings - Fork 67
fix (carousel): fix overlapping inner columns on infinite scroll #3588
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 (carousel): fix overlapping inner columns on infinite scroll #3588
Conversation
WalkthroughCompute per-slide translateX from offsetLeft for infinite-scroll clones; initialize clones with non-animated transform to avoid flicker; introduce conditional per-swap translation (useSlideTranslateX) and apply matching translations to slides and clones, with RTL-aware signs and special handling for the last clone. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Carousel
participant Slides
participant Clones
User->>Carousel: Initialize carousel
Carousel->>Slides: Measure offsetLeft (first slide, first clone)
Slides-->>Carousel: offsetLeft values
Carousel->>Carousel: Compute slideTranslateX & cloneTranslateX (RTL-aware)
Carousel->>Clones: Create/init clones with will-change, translateX(0), transition:0s
User->>Carousel: Trigger swap/scroll
Carousel->>Carousel: Set useSlideTranslateX = true if needed
alt useSlideTranslateX == true
Carousel->>Slides: Apply transform: translateX(slide.slideTranslateX)
Carousel->>Clones: Apply transform: translateX(clone.cloneTranslateX) (last clone uses special sign)
else
Carousel->>Slides: Apply transform: translateX(0)
Carousel->>Clones: Apply transform: translateX(0)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🤖 Pull request artifacts
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/block/carousel/frontend-carousel.js (2)
96-105: Avoid persistent will-change/0s transitions; clean up after init to prevent long-lived layersKeeping
will-change: transformandtransition: transform 0son slides/clones can pin them to separate compositor layers and hurt performance. Clear these after the initial, non-animated positioning.clone.classList.add( `stk-slide-clone-${ slideIndex + 1 }` ) clone.style.zIndex = -1 clone.style.willChange = 'transform' clone.style.transform = 'TranslateX( 0 )' original.style.willChange = 'transform' original.style.transform = 'TranslateX( 0 )' // prevents flickering when changing the value of TranslateX original.style.transition = 'transform 0s' clone.style.transition = 'transform 0s' +// Clean up layer hints/transitions after initial layout +requestAnimationFrame( () => { + original.style.transition = '' + clone.style.transition = '' + original.style.willChange = '' + clone.style.willChange = '' +} )Also consider using lowercase
translateXfor consistency with common style guides (CSS is case-insensitive, this is a nit).
339-342: Prefer lowercasetranslateXand guard against undefined slideTranslateXCosmetic but consistent: use
translateX. Also, whenuseSlideTranslateXis true, ensureslide.slideTranslateX/clone.slideTranslateXexist to avoid settingtranslateX(undefined)if indices drift.- slide.style.transform = `TranslateX(${ useSlideTranslateX ? slide.slideTranslateX : 0 })` + slide.style.transform = `translateX(${ useSlideTranslateX && slide.slideTranslateX ? slide.slideTranslateX : 0 })`- clone.style.transform = `TranslateX(${ useSlideTranslateX ? clone.slideTranslateX : 0 })` + clone.style.transform = `translateX(${ useSlideTranslateX && clone.slideTranslateX ? clone.slideTranslateX : 0 })`
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
src/block/carousel/frontend-carousel.js(4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/block/carousel/frontend-carousel.js (1)
src/higher-order/with-visual-guide/visual-guide.js (1)
computedStyles(22-36)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: PHP 7.3 and WP 6.5.5
- GitHub Check: PHP 8.2 and WP 6.7.2
- GitHub Check: PHP 8.2 and WP latest
- GitHub Check: PHP 7.3 and WP latest
- GitHub Check: PHP 8.2 and WP 6.5.5
- GitHub Check: PHP 8.2 and WP 6.6.2
- GitHub Check: build
🔇 Additional comments (1)
src/block/carousel/frontend-carousel.js (1)
319-325: Gate for using swap translations looks fine; ensure reverse path resets transforms cleanlySetting
useSlideTranslateX = trueonly when adding swaps (forward) is reasonable. On reverse, transforms go back to0. Please verify no stale transforms remain on slides/clones when oscillating near the boundary (rapid prev/next). I can script-check for any non-zero inline transforms after a swap sequence if helpful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/block/carousel/frontend-carousel.js (1)
7-10: Broken iOS detection (always truthy); fix logic.The current check returns a truthy value for most UAs (because -1 is truthy and the boolean logic is inverted), enabling iOS-specific handlers on non‑iOS devices.
Apply this diff:
-function isiOS() { - const userAgent = navigator?.userAgent - return userAgent && ( userAgent.indexOf( 'iPhone' ) === -1 || userAgent.indexOf( 'iPad' ) ) -} +function isiOS() { + const ua = navigator?.userAgent || '' + // Covers iPhone/iPad/iPod; also iPadOS on Safari (Mac UA + touch) + const isIOSUA = /iP(hone|od|ad)/i.test( ua ) + const isTouchMac = /Mac/i.test( ua ) && ( navigator?.maxTouchPoints > 1 ) + return isIOSUA || isTouchMac +}
♻️ Duplicate comments (1)
src/block/carousel/frontend-carousel.js (1)
124-132: Good switch to layout-based delta; also recompute on resize (extract helper).The offsetLeft-based delta fixes variable widths. Ensure it’s recalculated on resize; right now it runs only during first-time clone setup, so deltas get stale after a resize or font load.
Apply this diff here:
- const slideOffsetLeft = this.slideEls[ 0 ].offsetLeft - const cloneOffsetLeft = this.clones[ 0 ].offsetLeft - - const diff = Math.abs( slideOffsetLeft - cloneOffsetLeft ) - this.slideTranslateX = ( this.isRTL ? -diff : diff ) + 'px' - this.cloneTranslateX = ( this.isRTL ? diff : -diff ) + 'px' + this.computeTrackDelta()Then add this method in the class (outside this hunk):
computeTrackDelta = () => { if ( !this.infiniteScroll || !this.clones?.length ) return const slideOffsetLeft = this.slideEls[0].offsetLeft const cloneOffsetLeft = this.clones[0].offsetLeft const diff = Math.abs( slideOffsetLeft - cloneOffsetLeft ) this.slideTranslateX = ( this.isRTL ? -diff : diff ) + 'px' this.cloneTranslateX = ( this.isRTL ? diff : -diff ) + 'px' }And call it whenever initProperties runs after first init:
if ( this.infiniteScroll && this.clones?.length ) { this.computeTrackDelta() }
🧹 Nitpick comments (4)
src/block/carousel/frontend-carousel.js (4)
97-105: Use lowercase translateX and avoid long-lived will-change/transition.
- translateX is case-insensitive but keep it lowercase for consistency.
- Clear willChange and inline transition after init; keeping them set increases memory/painting costs.
Apply this diff:
- clone.style.willChange = 'transform' - clone.style.transform = 'TranslateX( 0 )' + clone.style.willChange = 'transform' + clone.style.transform = 'translateX(0)' original.style.willChange = 'transform' - original.style.transform = 'TranslateX( 0 )' + original.style.transform = 'translateX(0)' // prevents flickering when changing the value of TranslateX original.style.transition = 'transform 0s' - clone.style.transition = 'transform 0s' + clone.style.transition = 'transform 0s'Outside this hunk, after init completes (e.g., right after step 5), clear hints:
requestAnimationFrame( () => { this.clones.forEach( c => { c.style.willChange = ''; c.style.transition = '' } ) this.slideEls.forEach( s => { s.style.willChange = ''; s.style.transition = '' } ) } )
327-331: Optional: use translate3d for smoother swaps.GPU-promote the move to reduce subpixel jank on mobile.
- slide.style.transform = `translateX(${ useSlideTranslateX ? this.slideTranslateX : 0 })` + slide.style.transform = `translate3d(${ useSlideTranslateX ? this.slideTranslateX : '0px' },0,0)` ... - clone.style.transform = `translateX(${ useSlideTranslateX ? this.cloneTranslateX : 0 })` + clone.style.transform = `translate3d(${ useSlideTranslateX ? this.cloneTranslateX : '0px' },0,0)`
307-313: Minor: rename for intent clarity.useSlideTranslateX could be shouldTranslate or willTranslate for readability; logic is fine.
220-224: Optional: throttle resize handler.initProperties on every resize event can thrash. Consider a rAF or 100–200ms debounce before calling initProperties/computeTrackDelta.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/block/carousel/frontend-carousel.js(4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: PHP 8.2 and WP 6.5.5
- GitHub Check: PHP 8.2 and WP latest
- GitHub Check: PHP 8.2 and WP 6.6.2
- GitHub Check: PHP 8.2 and WP 6.7.2
- GitHub Check: PHP 7.3 and WP latest
- GitHub Check: PHP 7.3 and WP 6.5.5
Summary by CodeRabbit