position 是前端必知必會的屬性,但 z-index 失效的問題坑了不少人。
五種定位方式
css
/* static:預設,不參與 z-index 堆疊 */
position: static;
/* relative:相對自身原始位置偏移,不脫離文件流 */
position: relative;
top: 10px; /* 向下移 10px,原位置仍佔據空間 */
/* absolute:相對最近的非 static 祖先定位,脫離文件流 */
position: absolute;
top: 0;
right: 0; /* 右上角 */
/* fixed:相對視口定位,脫離文件流,滾動不跟隨 */
position: fixed;
bottom: 20px;
right: 20px; /* 固定在右下角 */
/* sticky:滾動到閾值前是 relative,之後變 fixed */
position: sticky;
top: 60px; /* 滾動到距視口頂部 60px 時固定 */
absolute 定位的參照系
找最近的 非 static 祖先:
html
<div class="parent" style="position: relative;">
<!-- 參照這個 -->
<div class="child" style="position: absolute; top: 10px; left: 10px;"></div>
</div>
如果沒有非 static 祖先,就相對 <html> 定位。
層疊上下文(Stacking Context)
z-index 失效通常是不理解層疊上下文導致的。
建立層疊上下文的條件(常見的):
position: relative/absolute/fixed+z-index不為 autoopacity < 1transform: translate/rotate/scale等filter非 nonewill-change
html
<div style="position: relative; z-index: 1;">
<!-- 這裡有自己的層疊上下文 -->
<div style="position: absolute; z-index: 999;">
<!-- z-index: 999 只在父級上下文內有效 -->
<!-- 無法超過兄弟的 z-index: 2 -->
</div>
</div>
<div style="position: relative; z-index: 2;">
<!-- 這個在 z-index: 999 的元素之上 -->
</div>
理解關鍵:子元素的 z-index 只在父層疊上下文內比較,無法跳出。
常見陷阱:transform 建立層疊上下文
css
/* 父元素有 transform,子元素 fixed 失效! */
.parent {
transform: translateZ(0); /* 或 will-change: transform */
}
.child {
position: fixed; /* 變成相對 parent 定位,而非視口 */
}
實用技巧
css
/* 垂直水平居中(absolute 經典做法) */
.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
/* 固定底部導航(Safari 安全區域處理) */
.bottom-nav {
position: fixed;
bottom: 0;
bottom: env(safe-area-inset-bottom); /* iOS 劉海屏 */
width: 100%;
}
/* sticky 表頭 */
thead th {
position: sticky;
top: 0;
background: white; /* 必須有背景色,否則會透明 */
z-index: 1;
}
小結
absolute找最近的非 static 祖先- 層疊上下文隔離了內部的
z-index,這是 z-index 失效的根本原因 transform、opacity < 1、filter都會建立層疊上下文sticky需要父元素有確定的高度且不能overflow: hidden