在前端網頁切版中,只要遇到「右上角未讀紅點徽章」、「固定在畫面頂端的導覽列」、「右下角回到頂端按鈕」或是「滾動到一半自動吸附置頂的分類列」,就一定會用到 CSS position 定位屬性。
本文用最直白的方式整理 CSS position 的 5 個屬性值(static、relative、absolute、fixed、sticky),幫你一次搞懂它們各自是「相對於誰定位」以及為什麼有時候設了卻沒效果。
一張表看懂:5 種 CSS position 定位屬性差別
position 屬性值 | 是否保留原本的排版空間? | top / left 是相對於誰定位? | 最常見實務場景 |
|---|---|---|---|
static(預設值) | 是(正常文流) | 無效(忽略 top/left,z-index 也無作用,Flex/Grid 子項除外) | 一般普通段落與區塊 |
relative(相對定位) | 是(原位置保留空白) | 相對於「自己原本的位置」微調 | 作為 absolute 子元素的定位基準父層 |
absolute(絕對定位) | 否(脫離排版、浮起來) | 相對於最近一層「非 static 的祖先元素」(祖先有 transform、filter 等屬性時也會成為基準) | 卡片右上角徽章、下拉選單、彈跳燈箱 |
fixed(固定定位) | 否(脫離排版、浮起來) | 相對於「瀏覽器視窗(Viewport)」(祖先有 transform、filter 等屬性時例外) | 固定置頂 Header、右下角客服與返回頂部按鈕 |
sticky(黏性定位) | 是(滾動前等同 relative) | 相對於最近一層「滾動容器」 | 捲動到頂端時自動吸附的表格標題列、側邊目錄 |
1. relative(相對定位)與 absolute(絕對定位)的黃金口訣:「子絕父相」
初學者使用 position: absolute 最常遇到的問題就是:「為什麼我設了 top: 0; right: 0;,元素卻一路飛到整個網頁的最右上角?」
這是因為 position: absolute 會一層一層往上找父元素,直到找到第一個有設定定位(也就是 position 不是預設 static)的祖先元素,以它的 padding 邊框範圍作為對齊邊界;如果一路往上找都沒人設定,它就會改以「初始包含區塊」(initial containing block,大小等同第一個畫面的 Viewport,位於頁面最上方)為基準,看起來就是貼齊整個網頁的左上或右上角。
另外要留意:祖先元素即使維持 static,只要設定了 transform、perspective、filter(none 以外的值)或 contain: paint 等屬性,同樣會成為 absolute 子元素的定位基準。
因此實務切版有一句黃金口訣——「子絕父相」:
- 內層要浮動對齊的子元素設為
position: absolute; - 外層作為邊界基準的父容器設為
position: relative;
/* 父層卡片:加上 relative,把自己變成子元素的座標原點 */
.product-card {
position: relative;
width: 280px;
padding: 16px;
}
/* 子層「熱銷」標籤:加上 absolute,精準貼在卡片右上角 */
.hot-badge {
position: absolute;
top: 12px;
right: 12px;
background-color: #ef4444;
color: #ffffff;
padding: 4px 8px;
}
2. fixed(固定定位):永遠停留在瀏覽器視窗的某個角落
設定為 position: fixed 的元素會完全脫離頁面排版,直接固定在瀏覽器可視視窗(Viewport)的指定座標上。無論使用者怎麼上下捲動網頁,它都紋絲不動:
/* 右下角固定「回到頂端」按鈕 */
.back-to-top-btn {
position: fixed;
right: 24px;
bottom: 24px;
z-index: 50; /* 確保按鈕浮在內文上方 */
}
注意事項:當任一層祖先元素設有
transform、perspective、filter或backdrop-filter(none以外的值)、contain: paint(或layout、strict、content),或will-change: transform時,該祖先元素會變成fixed子元素的定位基準,導致fixed看起來像變成absolute一樣跟著捲動。因此全站燈箱(Modal)或固定按鈕建議直接放在<body>第一層。
3. sticky(黏性定位):結合 relative 與 fixed 的滾動吸附神器
position: sticky 在使用者還沒滑到它之前,表現就跟一般 relative 元素一樣正常排列;一旦畫面往下捲動,讓它碰到你設定的 top 距離(例如 top: 0 或 top: 80px)時,它就會像 fixed 一樣吸附在畫面上,直到它的父容器底部捲上來、把它一起帶走為止:
/* 文章右側目錄:滑動到距離視窗頂部 24px 時自動停住吸附 */
.article-toc {
position: sticky;
top: 24px;
align-self: flex-start; /* 若在 Flex 容器內,必加這行防止高度被拉伸為 100% */
}
常見問題:為什麼我的 position: sticky 完全沒效果?
如果你寫了 position: sticky 卻發現元素還是直接被捲走,通常是踩到以下 3 個原因之一:
- 忘記寫
top(或bottom/left/right)偏移值:只寫position: sticky而四個偏移值都是auto時,元素的表現就跟relative一樣,不會觸發吸附,必須同時指定觸發距離,例如top: 0;。 - 外層某一個祖先容器設定了
overflow: hidden、overflow: auto或overflow: scroll:這是最多人卡關的原因!overflow設為hidden、auto或scroll的祖先都會成為滾動容器,sticky改以這個容器的捲動作為吸附依據;這個容器本身沒在捲動時,sticky就無法感知視窗的捲動。請將外層的overflow: hidden移除,或改用overflow: clip。 - 元素的高度已經跟父容器一樣高(完全沒有可滑動的軌道空間):例如在
display: flex雙欄排版中,左右兩欄預設會被align-items: stretch拉成一樣高。只要替sticky那一欄加上align-self: flex-start;,讓它縮回自身內容高度,就能正常吸附了。
若固定定位元素上需要搭配半透明毛玻璃背景模糊效果(
backdrop-filter),請進一步閱讀 CSS Filters 濾鏡效果。
發佈留言