Elementor Swiper 輪播 overflow 溢出效果:卡片突破容器邊界實作

在設計現代網頁時,常會遇到「輪播卡片需要突破容器邊界」的需求,也就是讓左右兩側的下一張卡片微露出一部份,營造視覺的延伸感。但在使用 Elementor 內建的輪播元件時,一旦開啟了 Overflow Visible,往往會導致整個網頁出現橫向捲軸,或者是在行動版上造成排版崩潰,這通常是因為層級設定與 Swiper 原生機制衝突所致。

核心設計原理

要達成完美的溢出效果而不產生全域捲軸,關鍵在於「雙層容器控制」。我們必須將最外層的 Elementor 容器(Section 或 Container)設定為 overflow: hidden 來切斷網頁外部捲軸,但同時要強制將 Swiper 內層容器設定為 overflow: visible。此外,現代版本的 Swiper 會針對螢幕外的卡片自動加上 inert 或 aria-hidden 屬性,這會導致溢出的卡片雖然看得到卻無法點擊,因此需要透過 JavaScript 動態移除這些限制。

實作步驟拆解

第一步:CSS 佈局與 RWD 設定

首先處理樣式部分。我們利用屬性選擇器來定位所有包含 overflow-carousel- 的類別,確保樣式能精準套用到特定的輪播組件。這裡也包含了 Hover 縮放效果的微調,增加互動感。

<style>
/* ========== Overflow 輪播樣式初始化 ========== */
/* 最外層容器限制溢出,避免全域捲軸 */
[class*="overflow-carousel-"] {
    overflow: hidden !important;
} 

/* 強制 Swiper 容器可見並調整寬度 */
[class*="overflow-carousel-"].swiper {
    overflow: visible !important; 
    width: auto !important;
} 

/* 卡片基礎設定與過渡動畫 */
[class*="overflow-carousel-"].swiper-slide {
    width: 372px !important; 
    height: auto !important; 
    flex-shrink: 0 !important; 
    opacity: 1 !important; 
    transition: transform 0.3s ease !important; 
    cursor: pointer !important;
} 

/* Hover 放大效果,提升層級避免被鄰近卡片覆蓋 */
[class*="overflow-carousel-"].swiper-slide:hover {
    transform: scale(1.05) !important; 
    z-index: 10 !important; 
    position: relative !important;
} 

/* RWD:行動版卡片寬度調整 */
@media (max-width: 767px) {
    [class*="overflow-carousel-"].swiper-slide {
        width: 300px !important;
    }
} 

/* 單張模式設定 */
[class*="overflow-carousel-"].single-mode.swiper {
    margin-left: 0 !important; 
    margin-right: 0 !important; 
    overflow: hidden !important;
} 

[class*="overflow-carousel-"].single-mode.swiper-slide {
    width: 100% !important;
} 

/* 隱藏 Elementor 原生箭頭,方便自定義導航 */
[class*="overflow-carousel-"].elementor-swiper-button-prev,
[class*="overflow-carousel-"].elementor-swiper-button-next {
    display: none !important;
}
</style>

第二步:JavaScript 邏輯與點擊修正

接下來這段 Script 主要解決兩個問題:一是確保在頁面載入後能順利抓到 Swiper 實例並重新初始化;二是利用 MutationObserver 持續監聽卡片屬性,解決側邊溢出卡片「看得到點不到」的問題。

<script>
(function() {
    var CONFIG = {
        cardWidth: 372, 
        cardWidthMobile: 300, 
        gap: 24, 
        gapMobile: 12, 
        breakpoint: 767
    }; 

    function initOverflowCarousels() {
        var carousels = document.querySelectorAll('[class*="overflow-carousel-"]'); 
        carousels.forEach(function(carousel) {
            // 避免重複初始化
            if (carousel.dataset.overflowInit === 'true') return; 
            var swiperContainer = carousel.querySelector('.swiper'); 
            if (!swiperContainer) return; 

            // 如果 swiper 已經存在,直接執行設定
            if (swiperContainer.swiper) {
                carousel.dataset.overflowInit = 'true'; 
                setupCarousel(carousel, swiperContainer.swiper); 
                return;
            } 

            // 輪詢等待 Elementor 載入 Swiper
            var attempts = 0; 
            var checkSwiper = setInterval(function() {
                attempts++; 
                if (swiperContainer.swiper) {
                    clearInterval(checkSwiper); 
                    carousel.dataset.overflowInit = 'true'; 
                    setupCarousel(carousel, swiperContainer.swiper);
                } 
                if (attempts > 300) {
                    clearInterval(checkSwiper);
                }
            }, 10);
        });
    } 

    function setupCarousel(carousel, swiper) {
        // 修正點擊事件穿透
        swiper.params.preventClicks = false; 
        swiper.params.preventClicksPropagation = false; 
        swiper.params.touchStartPreventDefault = false; 

        // 強制移除限制點擊與可見性的屬性
        function removeInert() {
            var slides = carousel.querySelectorAll('.swiper-slide'); 
            slides.forEach(function(slide) {
                slide.removeAttribute('inert'); 
                slide.removeAttribute('aria-hidden');
            });
        } 

        removeInert(); 
        swiper.on('slideChange', removeInert); 
        swiper.on('transitionEnd', removeInert); 

        // 監聽 DOM 變化,防止 Swiper 自動加回屬性
        var observer = new MutationObserver(function(mutations) {
            var needsUpdate = mutations.some(function(m) {
                return m.attributeName === 'inert' || m.attributeName === 'aria-hidden';
            }); 
            if (needsUpdate) removeInert();
        }); 

        carousel.querySelectorAll('.swiper-slide').forEach(function(slide) {
            observer.observe(slide, {attributes: true});
        });
    }

    // 啟動初始化
    document.addEventListener('DOMContentLoaded', initOverflowCarousels);
})();
</script>

實務重點與踩坑提醒

  • 橫向捲軸噴發:如果實作後發現網頁右側出現大片空白,請檢查輪播所在的最外層 Container 是否有設定 overflow: hidden。在 Elementor 中,這通常需要在「進階設定」的「佈局」內將溢出改為「隱藏」。
  • 卡片無法點擊:這是因為 Swiper 為了 SEO 與無障礙設計,會將視窗外的 Slide 加上 inert 屬性。本文提供的 JavaScript 範例中,使用了 MutationObserver 來解決這個問題,確保溢出部分依然具備交互功能。
  • Z-index 衝突:當開啟 Hover 放大效果時,若沒有設定 z-index: 10,放大的卡片可能會被後面的卡片遮擋,導致陰影或邊框顯示不完全。
  • Elementor 更新風險:Elementor 偶爾會更改 Swiper 的 DOM 結構(例如從 .swiper-container 改為 .swiper),建議類別選擇器使用屬性包含式的寫法(如 [class*="..."])以增加容錯率。

看不懂沒關係,照做就能用

以上的原理看不懂沒關係,只要照著下面的步驟操作就能直接套用:

操作步驟

  1. 安裝 FluentSnippets 外掛
  2. 新增 CSS 片段,將文章第一步中的 style 標籤內程式碼貼入並啟用
  3. 新增 JS 片段,將文章第二步中的 script 標籤內程式碼貼入,執行位置選擇「Site Wide Footer」並啟用
  4. 回到 Elementor 編輯器,選取你想要製作溢出效果的「輪播元件」或「容器」
  5. 在該元件的「進階 (Advanced)」>「CSS Classes」欄位填入:overflow-carousel-custom(請確保開頭包含 overflow-carousel- 關鍵字)
  6. 確保該輪播所在的「最外層容器」進階設定中,佈局的「溢出 (Overflow)」設定為「隱藏 (Hidden)」,以防止產生全域橫向捲軸
  7. 清除快取後,到前台確認輪播是否已達成卡片溢出且可正常點擊的效果
如果啟用後網站出現異常,回到 Snippets 將該片段停用即可立刻復原,不會影響其他設定。
文章分享