position:sticky 遇到 overflow 時失效解法

今天在處理將 table 表頭凍結在最上方時,找到了使用position: sticky的方式解決,但若我要同時在小畫面時讓這個 table 的 X 軸能夠有 scroll bar 卻出現了問題,以下紀錄一下問題原因與解決方式。

範例連結:https://codepen.io/andyhung0723/pen/YzeOovW

問題

假設我有一個 table,若我想將它的表頭凍結在最上方不動,可以使用position: sticky

1
2
3
4
.table-sticky .th {
position: sticky;
top: 0;
}

若在小畫面時想要此 table 不要撐開整體寬度,一般會在外層使用overflow-x: auto來讓 X 軸產生 scroll bar:

1
2
3
.table-sticky-container {
overflow-x: auto;
}

此時就會發現原本position: sticky的凍結效果卻失效了


原因

經測試發現只要position: sticky上所有階層的父元素只要有一個的overflow值是visible以外的其他值,就會導致失效。


解法

目前單純使用 CSS 貌似沒有解法,因此我使用 JavaScript 的 scroll 事件來動態 transform 表頭的位置來解決,程式碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
window.addEventListener('scroll', function(event) {
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
var stickyTables = document.querySelectorAll('.table-sticky');
for(var i = 0 ; i < stickyTables.length ; i++) {
var thead = stickyTables[i].querySelector('thead');
var offsetTop = stickyTables[i].offsetTop;
var offsetHeight = stickyTables[i].offsetHeight - thead.offsetHeight;
var transformY = getTranslateY(thead);
if(scrollTop >= offsetTop && scrollTop <= offsetTop + offsetHeight) {
transformY = scrollTop - offsetTop;
}else if(scrollTop < offsetTop){
transformY = 0;
}
thead.style.transform = 'translateY('+ transformY +'px)';
}
});

function getTranslateY(element) {
var style = window.getComputedStyle(element);
var matrix = new WebKitCSSMatrix(style.transform);
return matrix.m42;
}
Google 官方正式宣布「項目範圍的自訂維度 (item scope)」上線啦! Angular 取得元素 offsetWidth 時有誤解法

評論

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×