【CSS 教學】position 系列語法彙整,絕對、相對定位的開發、除錯技巧

2021/12/05閱讀時間約 16 分鐘
回想自己一路上在前端開發的路上,position 系列的語法絕對可以排上前幾名花最多時間研究的語法之一。
不論是在基礎或是進階的版面排列,幾乎離開不了 position 系列的 CSS 語法,如果對於這些語法不熟悉,要快速完成畫面需求幾乎是不可能的,甚至會延宕整個團隊的開發速度(對,position 語法就是這麽重要)。
這也是為什麼 position 系列語法的應用 ,常常被列為前端面試考題的原因。
那 position 語法究竟要解決什麼問題呢?
根據 MDN:「The position CSS property sets how an element is positioned in a document. The top, right, bottom, and left properties determine the final location of positioned elements.」
position 語法的設定,會影響在整個網頁中元素是如何被放置,而 top、right、bottom 及 left 屬性會決定元素最終的位置。
這篇文章就要來跟大家聊聊以下這些 position 系列的 CSS 語法,會如何在實務上進行應用,本篇文章中會提及以下語法:
在提及 position 語法前,我們先來聊聊 top、right、bottom、left 這四個語法是做什麼的,這四個方向性的屬性主要是用來定義元素的位置要從什麼方向起算延伸,也就是前文提到,這四個方向屬性設定會影響元素最終位置的原因。
舉例來說:
在之後的範例中,我們會大量使用到這四個方向性的屬性來輔助解釋 position 語法。

position 的預設值: static

當我們沒有給網頁元素加上 position 語法時,網頁元素會自己帶有 position: static 的特性。
帶有這種特性的元素,會按照原有的 HTML flow 來進行排列,而 top、right、bottom、left 及 z-index 是不會生效的!
如果你發現自己設定的 top、right、bottom、left 或是 z-index 並沒有生效,很有可能是你根本沒有啟用 position 的其他語法(稍後會提及)。
由於元素預設就帶有這個語法效果,通常並不會額外拿出來使用,或是當作效果加在元素上。

相對定位

再來我們來看看 MDN 文件對於相對定位的定義是什麼:「The element is positioned according to the normal flow of the document, and then offset relative to itself based on the values of top, right, bottom, and left.」
簡單來說,相對定位是以元素自己原本的位置作為參考點,依照 top、right、bottom、left 屬性來決定元素最後的位置,並在元素原本的位置產生留白空間(offset),讓我們看看這個範例:
從上方範例中,你可以看到帶有 position: relative 的紅色方塊,會以自己原始的位置作為參考點,以上方起算 300px 的距離作為最終位置。
那另外一個問題來了,如果當網頁有其他元素的狀態下,帶有 position: relative 的元素會影響其他元素的排列順序嗎?
答案是:不會。
同樣都是 300* 300 的方塊,藍色的方塊並沒有因為紅色方塊帶有 position: relative 且向下推擠 100px 的關係也跟著向下推擠。
那我們會怎麼在實務上使用這個語法呢?很抱歉,我目前還沒有遇過「單一」使用 position: relative 的狀況,因為一旦我們使用這個語法來排列元素時,雖然元素不在原來的的位置上了,但被空下來元素原本的空間卻還是會佔有「位置」。
在大部分的狀況下,我們不會希望那邊的位置是被佔滿但卻是空白的。
但不要緊張,這不代表 position: relative 是沒有用的語法,他需要與其他的 position 語法一起使用才會有意義。

絕對定位

接著我們要來看另外一個語法,他叫做 position: absolute。
我們一樣先來看看官方文件對於這個語法的定義:「The element is removed from the normal document flow, and so space is created for the element in the page layout. It is positioned relative to its closest positioned ancestor, if any; otherwise, it is placed relative to the initial containing block, Its final position is determined by the value if top, right, bottom and left.」
首先,帶有 position: absolute 的元素會被移出原有的 HTML flow,產生新的堆疊環境,也就是說帶有此語法特性的元素不會影響到其他的元素的排列順序。
再者,帶有 position: absolute 的元素會以最接近且同樣也帶有額外設定的 position 語法的父元素作為參考點,並以 top、right、bottom、left 屬性來決定屬性的最後位置。
如果外層沒有父元素,或是父元素本身並沒有帶有額外設定 position 語法的話,像是 position: relative、position: absolute、position:sticky 或是 position: fixed 語法等,就會以最外層的 body 作為參考點,讓我們先來看個程式碼範例:
在這個範例中,在綠色的容器中帶有兩個分別為紅色及粉紅色的方塊,且按照正常的 HTML flow 排列來說,粉紅色的方塊應該是要在紅色方塊的上方。
但問題來了,現在粉紅色方塊帶有 position: absolute 的屬性,依照此語法的特性粉紅色方塊就會被挪出原本的 HTML flow ,並以 body 作為參考點,出現在距離 body 上方 200px 、左方 200px 的位置。
因為粉紅色方塊被挪出 HTML flow,所以其他的元素就會去填補空缺的位置,於是紅色方塊的位置就會向上移,也就是先前我提到,一旦使用 position: absolute 語法,粉紅色的方塊會出現在另外一個堆疊環境(stacking context),實際上他們並不存在在同一個 z-index 上。
也就是說,不論你怎麼移動帶有 position: absolute 語法的元素,都不會推擠到其他元素!
這裡需要注意的是,此時的粉紅與紅色方塊並不是以綠色容器作為參考點(雖然看起來很像),而是以 body 作為參考點,因為此時綠色的容器並沒有帶有 position: relative、position: absolute、position:sticky 或是 position: fixed 語法。
再讓我們看看另外一個範例:
在這個範例中,綠色的容器中裝了紅色的方塊,而紅色的方塊中又放了一個粉紅色的方塊,與先前範例不同的地方是,紅色方塊與粉色方塊的階層關係由平行階層,轉換成父子階層。
由於粉紅色方塊的參考點,由一開始綠色容器,轉換成紅色方塊,於是粉紅色方塊現在會出現在以紅色方塊上方起算的 50px 、左方起算 50px 的位置。
為了驗證帶有 position: absolute 語法的元素會以上一層的帶有 position 特性之父元素作為參考點,於是我在紅色方塊上加了 position: relative 語法,讓紅色方塊以自己的原始位置作為參考點也向下向右移動,你會發現粉紅色的位置永遠都會出現在以紅色方塊上方起算的 50px 、左方起算 50px 的位置。
在實務上 position: absolute 很常會用來處理裝飾性的畫面細節,像是特價、特惠,或是某個商品、列表項目的裝飾性元素,譬如未閱讀的通知,讓我們來看看這個範例:
方格子在前陣子更新了文章的頁面內容,可以看到 premium 列表上多了一個紅色點點,若點開瀏覽器的 DevTool 就可以發現其實這個頁面的提示功能,就是透過 position: absolute 來實現的。
於是我也寫了一個類似的列表上帶有通知點點的效果,請參考以下範例:
什麼樣的狀況下 position:absolute 不會生效?
如果發現此語法沒有生效,或是沒有以預期的方式呈現效果,請務必檢查自己程式碼,帶有 position: absolute 的元素之父元素是否帶有 position: relative、position: absolute、position:sticky 或是 position: fixed 語法,這件事真的很重要,重複了這麼多遍是希望大家在遇到 position: absolute 沒有生效時,可以第一時間想要這個可能性。

position: fixed 創造固定效果

position: fixed 語法是一個非常方便,但在開發初期很容易被忽略的一個語法,老樣子,我們先來看看這個語法官方的定義:「The element is removed from the normal document flow, and no space is created for the element in the page layout.」
跟 position: absolute 非常類似,一旦元素帶有 position: fixed 的特性,就會被移出原本的 HTML flow,並且被移到另外的堆疊環境,簡單來說,它會與其他元素帶有不同的 z-index,所以不會影響到其他元素的排列狀況。
再者,MDN 提到:「It is positioned relative to the initial containing block establish ed by the viewport, expect when one of its ancestors has a transform, perspective or filter property set to something other than none, in which case that ancestor behaves as the containing block. Its final position is determined by the values of top, right, bottom and left.」
position: fixed 會以 viewport 創造的區域,這裡可以暫且想像成以整個瀏覽器的「畫面」作為參考點,以 top、right、bottom 及 left 屬性來決定元素的最後位置。
讓我們來看看範例:
看到這裡可能會發現,不同的 position 語法會有不同的參考點。
在這裡 position: fixed 的參考點會是整個畫面,所以你會發現不論你怎麼滾動,「我被固定住了」的這段話永遠會停在 top: 50%、right: 0 的位置。
然而 MDN 還有提到一個例外的狀況,當帶有 position: fixed 元素之父元素, transform 、perspective 或是 filter 屬性值不為 none 時,帶有 position: fixed 元素的參考點就會從 viewport 改為此父元素了!
這是什麼意思呢?讓我們來看看這個範例:
在此範例中,你會發現我在粉紅色方塊中帶有 transform 的效果,並進行了位移的效果設定,但此時你會發現,position: fixed 的參考點從 viewport 改變為粉紅色方塊,如果你嘗試把 transform 的效果拿掉,就會發現參考點就回從粉紅色方塊變回 viewport 。
什麼樣的狀況下,position: fixed 的效果會不如預期呢?
  1. 若你是想要讓元素一直固定在 viewport 的某個地方,但語法卻沒有生效,請檢查看看該元素的父元素是否帶有 transform、perspective 或是 filter 效果,帶有這些效果的父元素會使參考點改變。
  2. 如果你想要透過 position: fixed 將某元素固定在某個父元素特定位置,而不是固定在 viewport 上,但語法卻沒有生效,請檢查父元素是否有正確帶有 transform、perspective 或是 filter 效果。

position: sticky 在視窗滾動時情況下固定元素

跟 position: fixed 不相上下,初學者很常不會使用的語法就屬 position: sticky 了!
MDN 是這麼描述 position: sticky 的:「The element is positioned according to the normal flow of the document, and then offset relative to its nearest scrolling ancestor and containing block(nearest block-level ancestor), including table-related elements, base on the value of top, right, bottom, and left. 」
帶有 position: sticky 的元素不會被挪出 HTML flow,並且會跟最近的區塊滾動元素碰觸時,在原有的 HTML flow 中產生一個留白空間,並以 top、right、bottom 及 left 屬性來決定元素的最後位置:
從上方範例來看,你會發現帶有 position:sticky 的元素一旦碰到最近、帶有 overflow: scroll 特性的父元素,就會以該父元素作為參考點,並依照你撰寫的 top、right、bottom 或 left 屬性來進行定位(取決於你在滾動頁面時,會從哪個方向觸碰到父元素)。
也就是在一般的狀況下,帶有 position: sticky 的元素會以整個 document 作為參考點,一旦碰到 viewport 的上方,就會黏在 viewport 的上方。
除了以上應用方式外,更多有關 position 的應用,大家可以參考此官方文件,基本上我們常看到那些複雜、精美的網站的定位效果,都是從這些基本功衍生出來的。
相信透過這篇文章,大家可以更加了解不同 position 語法間的使用差異,關於網頁開發你有沒有什麼問題想要跟我分享的呢?歡迎你在下方留言與我分享。
希望今天的文章有幫助到正在閱讀的你,如果你喜歡我的文章的話,可以留下你的愛心或是收藏我的文章,也或者可以點選「贊助」,你的一杯咖啡絕對是我持續寫下去的動力!或是透過拍拍手,用你小小的行動支持我的創作!
我是Vivian,我們下次見。

關於我:
一名從英文系畢業的前端工程師,喜歡閱讀、寫東西及自我成長。
|聯絡我:[email protected]
為了追求可以窩在座位上、可以心無旁騖思考問題、座位可以亂七八糟沒關係、不需要到處哈腰點頭跑客戶,不用腳踩十公分、連妝都可以不用化的職場人生,文組少女毅然決然踏上RD的養成日常。
留言0
查看全部
發表第一個留言支持創作者!