在開發 WordPress 網站時,常會遇到「首屏導覽列」與「下滑後的導覽列」需要不同樣式的需求。例如在頁面頂部時,為了搭配大圖背景,Header 需要透明且高度較大;但當使用者向下捲動時,則希望出現一個固定在頂部、白底、高度較窄的精簡版導覽列。這種切換效果如果處理不當,容易造成兩個 Header 同時出現或切換瞬間版面跳動的問題。
內容導覽
運作原理說明
此實作方式是透過監聽瀏覽器的滾動事件(Scroll Event)來取得目前的垂直位移量(window.scrollY)。當位移量超過預設的門檻值(Threshold)時,JavaScript 會動態為原始 Header 加上隱藏標籤,同時為預備好的第二組 Header 加上顯示標籤。透過 CSS Class 的切換而非直接修改 Inline Style,能讓樣式控制回歸 CSS,後續維護樣式時也更具彈性。
實作步驟拆解
1. 定義 CSS 切換狀態
首先要在樣式表中定義好選單在切換前與切換後的狀態。我們預設將 .header-after 隱藏,並給予固定(fixed)在頂部的 CSS 屬性,確保它被觸發顯示時能正確黏在最上方。
<style>
.header-after {
display: none !important;
}
.header-after.is-show {
display: flex !important;
align-items: center;
width: 100vw !important;
position: fixed;
top: 0;
left: 0;
z-index: 9999;
}
.header-before.is-hide {
visibility: hidden !important;
}
</style>2. JavaScript 監聽與 Class 變換
這段腳本會監測捲動高度。當捲動超過 150px 時觸發狀態變更。我們使用了 passive 參數來優化滾動效能,避免腳本執行阻塞瀏覽器的原生滾動行為。
<script>
(function() {
var done = false;
function initHeader() {
if (done) return;
done = true;
var headersBefore = document.querySelectorAll('.header-before');
// 排除 Elementor 自動產生的佔位元素,避免抓錯對象
var headerAfter = document.querySelector('.header-after:not(.elementor-sticky__spacer)');
if (!headerAfter) return;
var threshold = 150;
var isShow = false;
window.addEventListener('scroll', function() {
var y = window.scrollY;
if (!isShow && y > threshold) {
isShow = true;
headersBefore.forEach(function(el) {
el.classList.add('is-hide');
});
headerAfter.classList.add('is-show');
} else if (isShow && y <= threshold) {
isShow = false;
headersBefore.forEach(function(el) {
el.classList.remove('is-hide');
});
headerAfter.classList.remove('is-show');
}
}, { passive: true });
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initHeader);
} else {
initHeader();
}
})();
</script>注意事項與踩坑提醒
- Elementor 相容性:如果你使用 Elementor Pro 的 Sticky 功能,系統會自動在 Header 外層包裹一個 .elementor-sticky__spacer。在選取元素時必須使用 :not(.elementor-sticky__spacer) 排除,否則 JavaScript 可能會操作到寬度為 0 的佔位元素,導致效果失效。
- Z-index 圖層順序:.header-after 的 z-index 必須設定得足夠高(例如 9999),否則當網頁下方有使用到其他具有定位屬性的區塊(如 Slider 或 Map)時,導覽列可能會被遮擋。
- Visibility 與 Display 的選擇:對於初始的 .header-before,建議使用 visibility: hidden 而不是 display: none。這樣可以保留原本 Header 佔據的空間高度,避免在切換瞬間頁面內容突然向上彈跳。
- 效能考量:Scroll 事件觸發頻率極高,務必確保腳本邏輯精簡。使用一個 boolean 變數(如本例中的 isShow)來判斷狀態,可以避免在每次滾動時都不斷執行 classList.add,減少瀏覽器重繪的壓力。
看不懂沒關係,照做就能用
以上的原理看不懂沒關係,只要照著下面的步驟操作就能直接套用:
步驟一:設定 Elementor 容器類別
- 進入 Elementor 編輯你的 Header 範本。
- 點選「原本的 Header」容器,到「進階」分頁的「CSS Classes」欄位填入:header-before
- 點選「想要捲動後才出現的 Header」容器,到「進階」分頁的「CSS Classes」欄位填入:header-after
步驟二:加入 CSS 樣式
- 安裝並啟用 FluentSnippets 外掛。
- 新增一個 CSS 片段,將文章中的 CSS 程式碼貼入。
- 點擊儲存並啟用,最後清除網站快取。
步驟三:加入 JavaScript 腳本
- 在 FluentSnippets 新增一個片段。
- 將文章中的 JavaScript 程式碼貼入。
- 執行位置(Placement)選「Site Wide Footer」。
- 點擊儲存並啟用,清除快取後到前台查看效果。
如果啟用後網站出現異常,回到 Snippets 將該片段停用即可立刻復原,不會影響其他設定。


