【Web前端HTML5&CSS3】11-定位

筆記來源:尚矽谷Web前端HTML5&CSS3初學者零基礎入門全套完整版

定位的簡介

需求分析

image-20210528210321699

按照我們之前所學知識,可以怎麼實現呢?

應該來說不難,很容易實現

.box2 {
    width: 200px;
    height: 200px;
    background-color: yellow;
    /* 左外邊距、上外邊距 */
    margin-left: 200px;
    margin-top: -200px;
}

.box3 {
    width: 200px;
    height: 200px;
    background-color: orange;
    /* 上外邊距 */
    margin-top: 200px;
}

我們分別給box2和box3添加了外邊距之後,就可以達到需求效果

image-20210528210703375

當然也可以使用浮動來解決上述問題,但稍微麻煩一點

不管怎樣,問題也是顯而易見。我們實際開發中,頁面上的元素可能很多,這樣改必然是 牽一髮而動全身

那麼僅僅靠我們之前學習的布局知識,不足以輕鬆應對這種場景

那麼就勢必需要一個方便我們處理這種場景的辦法,它就是定位

img

呸!不是!糟老頭子

定位(position)

定位是一種更加高級的布局手段

通過定位可以將元素擺放到頁面的任意位置

使用position屬性來設置定位

可選值 含義
static 不開啟定位,元素是靜止的,默認值
relative 開啟元素的絕對定位
absolute 開啟元素的絕對定位
fixed 開啟元素的固定定位
sticky 開啟元素的粘滯定位

img

1. 相對定位

img

當元素的position屬性值設置為relative時,則開啟了元素的相對定位

偏移量(offset)

當元素開啟相對定位以後,可以通過偏移量來設置元素的位置

offset屬性 含義
top 定位元素和定位位置的上邊距離
bottom 定位元素和定位位置的下邊距離
left 定位元素和定位位置的左側距離
right 定位元素和定位位置的右側距離

定位元素垂直方向的位置由topbottom兩個屬性控制,通常情況下只會使用其中之一

  • top值越大,定位元素越靠下
  • bottom值越大,定位元素靠上

定位元素水平方向的位置由leftright兩個屬性控制,通常情況下只會使用其中之一

  • left越大,定位元素越靠右
  • right越大,定位元素越靠左

ok,介紹完相對布局,我們的需求是不是變得so easy!

img

.box2 {
    width: 200px;
    height: 200px;
    background-color: yellow;
    /* 開啟相對定位 */
    position: relative;
    top: -200px;
    left: 200px;
}

我們給box2設置相對定位,就得到了我們想要的頁面效果

image-20210528212227760

可以看出,使用了相對定位後,只會移動自身的布局位置,而不會對已存在的其他元素產生任何影響

現在我們所舉的例子不是很明顯,但當頁面布局比較複雜,特別是頁面元素很多的時候,其優越性就可以大大體現出來

img

相對定位的特點

  1. 當元素開啟相對定位以後,如果不設置偏移量元素,則元素不會發生任何變化(這裡注意,不僅僅是位置)

  2. 相對定位是參照於元素在文檔流中的位置進行定位的(可以理解為相對於自身原始位置)

  3. 相對定位會提升元素的層級(表現為可以覆蓋其他元素)

  4. 相對定位不會改變元素的性質:塊還是塊,行內還是行內

動畫2021-25

Q1:如果給上述三個div都設置相對定位,那麼它們的層級關係會是什麼樣的呢?或者說誰會被誰覆蓋呢?

A:百聞不如一見光說不練假把式,我們直接進行測試驗證

image-20210528214204685

可以看到覆蓋關係是:box3 >> box2 >> box1

我們再稍微調整下box3和box2的前後位置

image-20210528214718203

會發現覆蓋關係變成了:box2 >> box3 >> box1

可以大概猜測:在頁面文檔流中,越靠下的元素開啟相對定位後,其層級越高 (這裡也只是我個人的揣測,待後續學習中驗證)(在後續學習中已得到驗證:沒有設置層級或層級z-index設置相同值時,優先顯示靠下的元素)

Q2:相對定位的第三個特點相對定位會提升元素的層級,是不是就類似於浮動一樣脫離了文檔流?

A:我們可以對比下,浮動和相對定位的區別

  • 參考系不同:浮動的參考系是其父元素;相對定位是相對於自身
  • 可移動方向不同:浮動只能左右移動;相對定位是上下左右移動
  • 影響不同:浮動會影響頁面布局(包括下方元素位置影響和高度塌陷問題);相對定位不對影響頁面布局
  • 性質不同:浮動會改變元素的性質(不再獨佔一行,其寬高都會被內容撐開);相對定位不會改變元素的性質
  • 文字環繞:浮動不會覆蓋文字;相對定位可以覆蓋文字(這個可以自行驗證,不再贅述)

當然,浮動和相對定位也有其相似之處

  • 浮動和相對定位都是移動位置(貌似是廢話)
  • 浮動和相對定位不會從父元素中移出

可以看出,浮動和相對定位的區別是更多的

最後回答一點:浮動脫離了文檔流,不再佔據頁面位置;相對定位仍然佔據頁面位置(所以怎麼能夠叫 脫離文檔流 呢?)

img

Q3:相對定位的第四個特點相對定位不會改變元素的性質:塊還是塊,行內還是行內,但是上述例子中元素開啟相對定位後好像就不再獨佔一行了,這個怎麼理解?

A:相比於浮動元素的特點,相對定位不會改變元素的性質其實是一個相對不容易理解的問題。但其實也不難,可以把相對定位認為是元素的靈魂出竅。其位置發生改變以後,布局並沒有產生影響,因為它的肉體(結構)仍然佔據著原來的那個位置。只是其靈魂(內容)發生了移動。

img

Q4:相對定位的第四個特點中塊還是塊,行內還是行內,意味著行內元素也可以使用相對定位是嗎?

A:眼見為實,耳聽為虛,直接看示例效果

動畫2021-24

善於思考是好事,但也別忘了自動動手,豐衣足食。自己實操一遍,勝過千言萬語

img

2. 絕對定位

img

當元素的position屬性值設置為absolute時,則開啟了元素的絕對定位

絕對定位的特點

  1. 開啟絕對定位後,如果不設置偏移量,元素的位置不會發生變化
  2. 開啟絕對定位後,元素會從文檔流中脫離
  3. 絕對定位會改變元素的性質:行內變成塊,塊的寬高被內容撐開(與相對定位相反)
  4. 絕對定位會使元素提升一個層級
  5. 絕對定位元素是相對於其包含塊進行定位的(與相對定位不同)

動畫 (2)

包含塊(containing block)

正常情況下:

  • 包含塊就是離當前元素最近的開啟了定位的祖先塊元素
  • 如果所有的祖先元素都沒有開啟定位,則html(根元素、初始包含塊)就是它的包含塊
<body>
    <!-- 如果box1開啟定位,則box2的包含塊是box1,否則就是body -->
    <div class="box1">
        <div class="box2"></div>
    </div>

    <!-- 如果box3開啟定位,則em的包含塊是box3,否則就是body -->
    <div class="box3">
        <span>
            <em>hello</em>
        </span>
    </div>
</body>

示例

<div class="box2">2
    <div class="box3">3
        <div class="box4">4</div>
    </div>
</div>

動畫 (4)

  • 不給box2、box3開起定位,box4的包含塊是html
  • 只給box3開啟定位之後,box4的包含塊是box3
  • 只給box2開啟定位之後,box4的包含塊是box2
  • 給box2、box3都開起定位之後,box4的包含塊是box3

注意:這裡上述的條件是開啟定位,也就是說只要position不是static(默認值),那麼就滿足了其成為包含塊的必要條件

上述示例中,我們給其祖先元素都設置了相對定位。其實改成其他幾種定位方式也是可行的,我們可以看下面示例

動畫 (5)

這裡就不一一舉例了,大家可以對另外幾種定位方式進行驗證

img

水平方向的布局

我們之前說過,水平方向的布局等式:

margin-left + border-left + padding-left + width + padding-right + border-right + margin-right = 其父元素的寬度

當使用絕對定位時,需要添加leftright兩個值(此時規則和之前一樣,只是多添加了兩個值)

left + margin-left + border-left + padding-left + width + padding-right + border-right + margin-right + right = 其父元素的寬度

當發生過度約束時

  • 如果9個值中沒有auto,則自動調整right值以使等式滿足(之前7個值是margin-right
  • 如果9個值中有auto,則自動調整auto的值以使等式滿足

可設置auto的值:margin-left/margin-right /width /left /right

因為leftright的值默認是auto,所以如果沒有設置leftright,當等式不滿足時,則會自動調整這兩個值

img

水平居中

<style>
    .box1 {
        width: 500px;
        height: 500px;
        background-color: #bfa;
        position: relative;
    }

    .box2 {
        width: 100px;
        height: 100px;
        background-color: orange;
        /* 左右外邊距設置為auto */
        margin-left: auto;
        margin-right: auto;
        /* 絕對定位 */
        position: absolute;
        left: 0;
        right: 0;
    }
</style>

<div class="box1">
    <div class="box2"></div>
</div>

image-20210529213746069

垂直方向的布局

垂直方向布局的等式的也必須要滿足

top + margin-top + border-top + padding-top + height + padding-bottom + border-bottom + margin-bottom + top = 其父元素的高度

垂直居中

.box2 {
    width: 100px;
    height: 100px;
    background-color: orange;
    /* 左右外邊距設置為auto */
    margin-top: auto;
    margin-bottom: auto;
    /* 絕對定位 */
    position: absolute;
    top: 0;
    bottom: 0;
}

image-20210529221704973

水平垂直居中

目前,我們可以根據絕對定位進行元素的水平垂直雙方向居中,所以這個方法只是其中之一

.box2 {
    width: 100px;
    height: 100px;
    background-color: orange;
    /* 左右外邊距設置為auto */
    margin: auto;
    /* 絕對定位 */
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
}

image-20210529221953142

小結

  • 水平布局等式:left + margin-left + border-left + padding-left + width + padding-right + border-right + margin-right + right = 其父元素的寬度
  • 垂直布局等式:top + margin-top + border-top + padding-top + height + padding-bottom + border-bottom + margin-bottom + top = 其父元素的高度
  • 上述等式的過度約束規則與《06-盒模型》中介紹的規則基本一致
  • 只是在沒有auto時,會自動調整top/bottom/left/right

img

3. 固定定位

img

將元素的position屬性設置為fixed,則開啟了元素的固定定位

固定定位的特點

固定定位也是一種絕對定位,所以固定定位的大部分特點都和絕對定位一樣

唯一不同的是,固定定位永遠參照於瀏覽器的視口(viewport,可視窗口)進行定位,不會隨網頁的滾動條滾動

示例

動畫 (6)

我們再給body設置一個較大的高度,讓瀏覽器滾動起來,看下效果

動畫 (7)

會發現,box4並沒有因為滾動而發生未知的變化,這也驗證了上述知識,同時也應該明白了視口的概念

我們再對比下絕對定位

動畫 (8)

相信到這裡,大家應該又進一步地理解了固定定位與絕對定位的區別

因為固定定位跟絕對定位除了具有上述差別之後,其他的特點跟絕對定位是一樣的,所以這裡便不再贅述了

4. 粘滯定位

img

將元素的position屬性設置為sticky,則開啟了元素的固定定位

這次,我們換個方式,直接來看粘滯定位的效果

動畫 (9)

大家可以看到,右側邊欄部分在一定的情況下是固定的,滾動到上方一定位置開始發生變動

我們先帶著這個疑問,打開Zeal官方手冊,找到positionsticky的相關描述

image-20210529190939459

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, based on the values of top, right, bottom, and left. The offset does not affect the position of any other elements.

This value always creates a new stacking context. Note that a sticky element “sticks” to its nearest ancestor that has a “scrolling mechanism” (created when overflow is hidden, scroll, auto, or overlay), even if that ancestor isn’t the nearest actually scrolling ancestor. This effectively inhibits any “sticky” behavior (see the GitHub issue on W3C CSSWG).

不要慌,這裡大概翻譯一下(我這裡稍微進行了下省略精簡和整理總結)

  • 該元素是根據文檔流進行定位的,即相對於包含塊進行偏移
  • 偏移量不會影響任何其他元素的位置
  • 粘性元素總是「粘」到其最近的具有「滾動機制」的祖先元素(當overflowhiddenscrollautooverlay時創建),即使該祖先不是最近的實際滾動祖先

這裡可能最後一點比較難理解,別著急,我們接著往下看

示例

我們拿之前的w3cschool頂部導航欄進行下魔改

/* 設置一個高度 */
body {
    height: 3000px;
}

.menu {
    width: 1211px;
    height: 48px;
    background-color: #E8E7E3;
    margin: 100px auto;
    /* 開啟粘滯定位 */
    position: sticky;
    top: 10px;
}

動畫 (10)

因為在影片中老師並沒有對sticky屬性做過多的介紹,只是要求我們了解一下,因為在實際開發中,也是結合js去實現的,所以我這裡同樣也就不再深入帶大家一起看了

粘滯定位的特點

  • 粘滯定位和相對定位的特點基本一致(影片中說是和相對定位一致,不過我對比了一下,很多特點是不同的,感覺倒是和固定定位更相似,這裡存疑)
  • 不同的是粘滯定位可以在元素到達某個位置時將其固定

需要注意的是,sticky屬性並不兼容IE(PS:不過微軟官方已經宣布將在2022年停止對IE的維護,IE將成為歷史。雖然我們經常詬病IE,但作為當年瀏覽器的一霸,在廢棄多年後,不知道還會不會有所懷念,畢竟它代表著我們不斷逝去的青春)

image-20210529192302342

5. 幾種定位的對比

我們通過上面的學習,知道position屬性有五個可選值

static是默認值,即不開啟定位,所以我們只需要對比4種定位方式即可

定位方式 是否不設置偏移量,元素不會發生改變 是否脫離文檔流 是否改變元素性質 是否提升元素層級 參考系
relative(相對定位) × × 參照於元素在文檔流中的位置
absolute(絕對定位) × 參照於其包含塊
fixed(固定定位) × 參照於瀏覽器的視口
sticky(粘滯定位) × 參照於瀏覽器的視口

6. 補充:元素層級

對於開啟了定位元素,可以通過z-index屬性來指定元素的層級

  • z-index需要一個整數作為參數,值越大元素的層級越高,元素的層級越高越優先顯示
  • 如果元素的層級一樣,則優先顯示靠下的元素
  • 祖先的元素的層級再高,也不會蓋住後代元素

img

示例

<style>
    div {
        font-size: 40px;
    }

    .box1 {
        width: 200px;
        height: 200px;
        background-color: #bfa;
        position: absolute;
        top: 0;
        left: 0;
    }

    .box2 {
        width: 200px;
        height: 200px;
        background-color: orange;
        position: absolute;
        top: 50px;
        left: 50px;
    }

    .box3 {
        width: 200px;
        height: 200px;
        background-color: salmon;
        position: absolute;
        top: 100px;
        left: 100px;
    }

    .box4 {
        width: 100px;
        height: 100px;
        background-color: skyblue;
        position: absolute;
        bottom: 0;
        left: 0;
    }
</style>

<div class="box1">1</div>
<div class="box2">2</div>
<div class="box3">3
    <div class="box4">4</div>
</div>

image-20210529231649087

存疑問題

Q:浮動也有層級概念嗎?如果有,浮動和定位的層級關係是什麼樣的?

A:null / none / undefined 調了一下,出現幾種現象

  • float設置z-index多大都沒用,還是會被覆蓋
  • 默認情況,沒有設置z-index或設置z-index大小≥0時,浮動層級沒有定位的層級高
  • 設置z-index<0時,浮動層級可以定位的層級高

浮動層級(不知道有沒有這個概念,本身就是存疑問題,現在這種情況看起來應該是沒有這個概念了)

image-20210529232518584

7. 總結

一般情況下,

  • 頁面的整體結構大多採用浮動、塊進行布局
  • 頁面某些模組結構一般採用定位進行微調

img

8. 練習:京東輪播圖

css程式碼

/* 整體居中 */
.box {
    width: 590px;
    height: 470px;
    /* 水平垂直雙方向居中 */
    margin: auto;
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
}

/* ======輪播圖Start====== */

.img_list li {
    /* 每個輪播圖絕對定位,讓其重疊 */
    position: absolute;
}

.img_list li:nth-child(1) {
    /* 目前還沒有學習js,暫時做成靜態切換層級 */
    z-index: 1;
}

/* 全局影像大小 */
.img_list img {
    /* 我這裡之所以要設置寬高,是因為下載的圖片大小不全是一樣大的 */
    /* 但是一般情況下,這些圖片都會裁剪成統一大小,所以可以不用設置 */
    width: 590px;
    height: 470px;
}

/* ======輪播圖End====== */

/* ======輪播圓Start====== */

.circle_list {
    height: 20px;
    /* 開啟絕對定位 */
    position: absolute;
    bottom: 20px;
    left: 30px;
    z-index: 2;
    /* 參考京東原網頁,整體字體設置樣式,這種設置方式還不太懂 */
    /* 其實也可以不設置,不過每個輪播圓之間的間距跟原來就不太一樣了 */
    font-size: 0;
    text-align: center;
}

/* 輪播圓細節 */
.circle_list .circle {
    /* 這裡設置display: inline-block; 也是一樣的 */
    float: left;
    height: 8px;
    width: 8px;
    background-color: rgba(255, 255, 255, .4);
    margin-right: 4px;
    /* 畫圓,這個按照課程中的畫法,按照網頁源程式碼調出來的有點問題 */
    background-clip: content-box;
    border: 3px transparent solid;
    border-radius: 50%;
}

/* 輪播圓懸浮效果 */
.circle_list .circle:hover,
.circle_list .circle:nth-child(1) {
    background-color: #fff;
    border: 3px rgba(0, 0, 0, .1) solid;
}

/* ======輪播圓End====== */

html程式碼

<div class="box">
    <ul class="img_list">
        <li><a href="#"><img src="assets/lbt/1.jpg" alt=""></a></li>
        <li><a href="#"><img src="assets/lbt/2.jpg" alt=""></a></li>
        <li><a href="#"><img src="assets/lbt/3.jpg" alt=""></a></li>
        <li><a href="#"><img src="assets/lbt/4.jpg" alt=""></a></li>
        <li><a href="#"><img src="assets/lbt/5.jpg" alt=""></a></li>
        <li><a href="#"><img src="assets/lbt/6.jpg" alt=""></a></li>
        <li><a href="#"><img src="assets/lbt/7.jpg" alt=""></a></li>
        <li><a href="#"><img src="assets/lbt/8.jpg" alt=""></a></li>
    </ul>
    <!-- 我這裡結構並沒有完全按照課程中的結構來,但實現效果是一樣的 -->
    <ul class="circle_list">
        <li class="circle"></li>
        <li class="circle"></li>
        <li class="circle"></li>
        <li class="circle"></li>
        <li class="circle"></li>
        <li class="circle"></li>
        <li class="circle"></li>
        <li class="circle"></li>
    </ul>
</div>

別忘了,引入reset樣式

效果

動畫 (11)

等到後面學習了js,就可以實現自動輪播了,到時候再補充完善

主要運用

  • 水平垂直雙方向居中(水平垂直方向等式)
  • absolute開啟絕對定位,使其重疊,達到隱藏效果
  • z-index設置層級,實現圖片輪播
  • border-radius畫圓,transparent邊框透明,background-clip:content-box隱藏邊框

525344c2d5628535e09f7f7087ef76c6a7ef6363