【前端Talkking】CSS系列——CSS深入理解之absolute定位

micstone發表於2018-05-05

1. 寫在前面

本篇將要介紹的絕對定位absolute屬性和此前介紹的CSS系列——CSS深入理解之float浮動有著幾分的相似性,可以認為兩者是兄弟關係,都具有“包裹性”、“高度塌陷”、“塊狀化”的特性,它們在很多場合都可以互相替代。很多人可能有這樣的疑問:一個屬性名是“position”,一個屬性名是“float”,從名字看起來,它們八竿子都打不著啊,怎麼還是兄弟關係呢?要說position: absoluteposition: relative是兄弟關係還能理解,要說和float是兄弟關係我就納悶!!!呵呵~~~~,別急,這就是寫作本文的目的。

2. absolute的特性

在介紹absolute之前,有以下公共CSS程式碼:

/* CSS程式碼 */
.father{
    border: 2px solid deeppink;
    width: 200px;
}
.son {
    position: absolute;
    font-size: 0;
    border: 2px solid blue;
    padding: 5px;
}
.father img {
    width: 128px;
}
複製程式碼

2.1 包裹性

然後有以下html程式碼:

<div class="father">
    <!--son1與son的唯一區別是son1的position設定為static-->
    <div class="son1">
        <img src="../../lib/img/mm1.png">
    </div>
</div>
<br/>
<br/>

<div class="father">
    <div class="son">
        <img src="../../lib/img/mm1.png">
    </div>
</div>
複製程式碼

最終顯示的效果如下圖所示:

【前端Talkking】CSS系列——CSS深入理解之absolute定位

在本例中,son1與son的唯一區別是son1的position設定為static.father元素的寬度設定為200pximg元素是一個128px寬度的圖片,則此時絕對定位元素寬度表現為"包裹性",其寬度也就是裡面圖片的寬度128px。

由於絕對定位元素寬度表現為"包裹性",因此,下面的CSS寫法就是多餘的:

.wrap{
    display: inline-block;// 沒有必要
    position: absolute;
}
複製程式碼

2.2 高度塌陷

基於上圖,父元素div的高度並沒有被子元素撐開(粉色區域),這種效果可以稱為"高度塌陷"。導致高度塌陷的原因是因為浮動元素脫離了正常的文件流,則div.father認為其沒有子元素,所以產生了高度塌陷。

如果在.father元素增加子元素,如下:

<!--HTML程式碼-->
<div class="father">
    <div class="son">
        <img src="../../lib/img/mm1.png">
    </div>
    美女1,美女2,美女3,美女4,美女5
</div>
複製程式碼

則在瀏覽器中的效果如下:

【前端Talkking】CSS系列——CSS深入理解之absolute定位

從圖中明顯看出文字被圖片遮蓋了,這一點和float不同。因為,float元素本身仍處於文件流中,文字會環繞著float元素,不會被遮蔽,而設定了absolute的圖片元素出現了層級關係,已經脫離了正常的文件流了,從父元素的視點看,圖片已經完全消失不見了,因此從最左邊開始顯示文字,而absolute的層級高,所以圖片遮蓋了文字。

2.3 塊狀化

塊狀化的意思是,一旦元素position的屬性為absolute或者fixed,則其display計算值就是block或者table。可以複製以下程式碼到瀏覽器控制檯中:

var span = document.createElement('span')
document.body.appendChild(span)
console.log('1.' + window.getComputedStyle(span).display)
// 設定元素絕對定位
span.style.position = 'absolute'
console.log('2.' + window.getComputedStyle(span).display)
document.getElementById("aa").style.display = "block"
複製程式碼

則在瀏覽器控制檯中的結果如下:

1.inline
2.block
複製程式碼

2.4 小結

對於上面對absolute的介紹,對比float屬性,是不是應該理解他們是兄弟關係呢?如果你非得不這樣認為可以,只要你明白absolute的特性即可。絕大多數前端開發人員應該都懂,但是如果本文只是介紹上面的知識點,就太對不起大家的期待了!下面將要介紹absolute的流體與相對特性才是本文的重點。

3. absolute流體與相對特性

3.1 absolute的相對特性

在介紹absolute的相對特性之前,先丟擲以下問題: 如果一個元素的定位屬性設定成了:position: absolute後,沒有設定left/top/right/bottom,並且其祖先元素全部都是非定位元素,請問它將在哪裡顯示?

包括我自己,在深入瞭解absolute的特性之前,認為該元素是在瀏覽器視窗的左上方顯示,其實這是對absolute絕對定位屬性錯誤的認識。因此,很多人在使用absolute定位屬性的時候,必定先要設定父元素position: relative,同時設定絕對定位元素的left/top/right/bottom,甚至還要設定絕對定位元素層級z-index實際上,該元素還是在當前的位置。我們拿下面的這個例子驗證:

 <!--HTML程式碼-->
<div class="father">
    <div class="pa box"></div>
</div>
複製程式碼
/* CSS程式碼 */
.father{
    border: 2px solid deeppink;
    width: 100px;
    height: 100px;
}
.pa{
    position: absolute;
}
.box{
    background-color: #cdcdcd;
    width: 50px;
    height: 50px;
}
複製程式碼

如下圖所示,.box元素還是在當前的位置顯示,而不是在瀏覽器視窗的左上方顯示:

【前端Talkking】CSS系列——CSS深入理解之absolute定位

在京東商城首頁,有這樣的一個效果:

image-20180502200432543

然後我們開啟除錯視窗,檢視html和css程式碼如下:

image-20180502200712645

這裡css程式碼中的top:0;left:0完全是多餘的程式碼,可以省略不寫。因為,不設定left/top/right/bottom的絕對定位元素還是在當前的位置,只是脫離了正常的文件流了。

實際上,absolute是一個相對比較獨立的CSS屬性,它的樣式和行為表現不依賴其他的CSS屬性就可以完成。因此,如果元素設定了定位屬性為absolute絕對定位,並且沒有設定left/top/right/bottom,那麼可以將這種定位屬性稱為“無依賴絕對定位”,其本質就是"相對定位",特點僅僅是脫離文件流,不佔據任何CSS流的尺寸空間了。

無依賴絕對定位在實際開發中非常有用,下面舉幾個比較常用的例子。

1)各類圖示定位

我們以慕課網首頁上的課程列表舉例:

WX20180502-205632@2x

<div>
    <div class="box"></div>
    <i>Hot</i>
</div>
複製程式碼

核心CSS程式碼如下所示:

WX20180502-205758@2x

完全不需要藉助top/right/bottom/leftposition: relative的幫助就可以搞定小圖示的佈局啦。相比使用position:relativeright/top的佈局方式,這種佈局方式的優點是:

  • 維護成本低。如果後面想刪除這個圖片,只需要將圖示對應的html和css程式碼刪除掉就可以了,不會影響其他的元素
  • 健壯性高。如果圖片變大或者文字變長,我們不需要修改小圖示的css程式碼,仍然定位效果良好。

再舉一個在實際開發中用的比較多的一個例子,如下圖所示,在一段文字的前面有一個圖示:

【前端Talkking】CSS系列——CSS深入理解之absolute定位

這種佈局方式同樣可以藉助無依賴定位的實現,並且程式碼簡單高效,程式碼如下所示:

<div class="email-wrapper">
    <i class="icon-email"></i>
    <span class="icon-msg">請輸入您的郵箱:</span>
</div>
複製程式碼
.email-wrapper{
    display: inline-block;
    height: 20px;
    padding-left: 20px;
    /*font-size: 0;*/
}
.icon-email{
    position: absolute;
    margin-left: -20px;
    width: 20px;
    height: 20px;
    background: url("../../lib/img/email.png") center center no-repeat;
    background-size: contain;
}
.icon-msg{
    display: inline-block;
    line-height: 20px;
    vertical-align: top;
}
複製程式碼

2)校驗提示錯誤

在實際開發中,我們有很多表單校驗,當校驗不通過的時候,會有一些錯誤提示給使用者,如下圖所示:

【前端Talkking】CSS系列——CSS深入理解之absolute定位

通常,錯誤提示可以放到input框的下面,但是當出現錯誤提示的時候,下面的內容會整體下移,當錯誤提示消失的時候,下面的內容又會整體上移,使用者體驗不好。還有一種做法是放到input框的右側顯示,但是在預設狀態下部容器設定了水平居中, 寬度不大,如果再出現錯誤提示資訊,就會出現容器的寬度不夠的問題。此時,我們同樣可以藉助:"無依賴定位",直接給錯誤提示資訊增加一個CSS類,如下所示:

.msg-error{
	position: absolute;
	margin-left: 10px;
}
複製程式碼

無論將input框的寬度變大或者變小,提示資訊都會跟著input框。相比使用position:relativeright/top的佈局方式,這種方法程式碼量更少、容錯性更高、維護成本更低。

關於無依賴絕對定位的應用還有很多,這裡就不一一介紹了,有興趣的同學可以參看張鑫旭老師的《CSS世界》。

3.2 absolute的流體特性

只有absolute遇到left/top/right/bottom屬性的時候,absolute元素才真正變成絕對定位元素。如果使用者給absolute至少指定了left/right中的一個,則水平方向的相對特性丟失,垂直方向上繼續保持相對特性;如果使用者給absolute至少指定了top/bottom中的一個,則保持水平方向上的相對特性,垂直方向上的相對特性丟失。例如:

<div class='box'></div>
.box{
    position: absolute;
    right: 0;
}
複製程式碼

此時,元素水平方向相對特性丟失,具有了絕對定位特性,而垂直方向的定位依然保持了相對特性。

以上面的這個例子舉例,當只有left或者right屬性的時候,由於包裹性,此時div的寬度是0。但是,如果同時設定left:0;right:0的時候,寬度表現為"格式化寬度",寬度自適應於.box包含快的content-box,換句話說,如果包含快的conent-box寬度發生變化,則.box的寬度也會跟著一起變。舉個例子:

<div class='box'></div>
.box{
    position: absolute;
    right: 0;
    left: 0;
    top: 0;
    bottom: 0;
}
複製程式碼

如果.box的包含塊是根元素,則上面的程式碼可以讓.box元素正好完全覆蓋瀏覽器的可視視窗,同時,如果改變瀏覽器視窗的大小,.box的大小會隨著瀏覽器的大小自動變化。因此,對於設定了對立定位屬性的絕對定位屬性,無論設定padding還是margin,其佔據的空間一直不變,變化的就是content-box,這就是典型的流體表現特性。流體特性的具體用法在後面會介紹到。

4. absolute與其他屬性

CSS中的很多屬性需要和其他的屬性一起使用的時候會發生意向不到的效果。下面將介紹absolute與其他CSS一起使用產生的效果。

4.1 absolute與text-align

利用text-align可以控制絕對定位元素的位置,實現主視窗右側的"返回頂部"以及"反饋"等佈局的效果。效果圖如下:

WX20180502-210045@2x

核心程式碼如下:

<!--HTML程式碼-->
<div class="alignright">
    <span class="follow">
        <img src="../../lib/img/message.png">
        <img src="../../lib/img/top.png">
    </span>
</div>
複製程式碼
/* CSS程式碼 */
.alignright{
    overflow: hidden;
    text-align: right;
}
.alignright:before{
    content: "\2002"
}
.follow{
    position: fixed;
    bottom: 100px;
    z-index: 1;
}
.follow img{
    display: block;
    margin: 10px;
    width: 20px;
    height: 20px;
    background-size: contain;
}
複製程式碼

在本例中,利用:before偽元素,在其前面插入一個空格(\2002),然後設定text-aligin: right,則空格對齊主結構的右側邊緣,後面的固定定位元素(同絕對定位元素)由於"無依賴定位"特性,左邊緣正好就是主結構的右邊緣,自然就跑到主結構的外面顯示了。這種佈局在實際開發中用處非常大,比如說下圖中某寶的樓層導航效果都可以使用這種方式實現。

【前端Talkking】CSS系列——CSS深入理解之absolute定位

4.2 absolute與clip

在實際開發過程中,很多時候我們為了更好的SEO和無障礙識別,都會將頁面中的一些元素隱藏,例如隱藏下面程式碼中的本網站名字這幾個字:

/* CSS程式碼 */
<a href="#" class="logo">
	<h1>本網站名字</h1>
</a>
複製程式碼

為了隱藏上面的文字,有以下幾種方案可以供我們選擇:

  • 使用display:none或者visibility:hidden。缺點:螢幕閱讀裝置會忽略這些文字;
  • 使用text-align縮排。缺點:如果縮排過大到螢幕之外,螢幕閱讀裝置也是不會讀取的;
  • 使用color: transparent。原生IE8瀏覽器器並不支援,並且還是能夠選中文字。

藉助absolute和clip(關於clip用法不熟悉的同學可以自己百度下,很簡單)這兩個屬性,能夠同時滿足視覺上隱藏和螢幕閱讀裝置能夠讀取的要求,核心程式碼如下:

/* CSS程式碼 */
h1{
    position: absolute;
    clip: rect(0 0 0 0);
}
複製程式碼

4.3 absolute之margin:auto居中

在實際工作開發中,可能我們用的最多的是下面的方式來實現元素的水平垂直居中效果,核心程式碼如下:

/* CSS程式碼 */
.box{
    width: 20px;
    height: 20px;
    position: absolute;
    left: 50%;
    right: 50%;
    margin-left: -10px;
    margin-right: -10px;
}
複製程式碼

此方法有一個不足之處就是需要提前知道元素的尺寸,否則無法控制margin負值的大小。

如果不知道元素的尺寸,可以使用transform: translate(-50%, -50%)代替margin負值,然而這種方法存在一定的相容性問題,IE9(-ms-), IE10+以及其他現代瀏覽器才支援,在一定的場景下會導致微信閃退的問題。

在介紹下另外一種方法前,我們首先熟悉下margin: auto的填充規則:

  • 如果一側定值,一側auto,則auto為剩餘空間大小;
  • 如果兩側都是auto,則平分剩餘空間。

因此,利用絕對定位absolute元素的流體特性和margin: auto的自動分配特效能夠實現水平垂直居中的效果,核心程式碼如下:

/* CSS程式碼 */
.box{
    width: 20px;
    height: 20px;
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    margin: auto;
}
複製程式碼

顯示效果如下:

WX20180502-212501@2x

這種方法兼用性好,並且需要提前知道元素的尺寸,減少了依賴,後期維護改動的地方少,何樂而不為呢?

5. 結語

關於absolute的介紹就到這裡了,平時我們應該多思考,多總結,才會有新的體會。計劃下一篇文章介紹relative定位,最新文章都會第一時間更新在我的公眾號<前端Talkking>裡面,歡迎關注。

以上就是本文的全部內容,感謝閱讀,如果有表述不正確的地方,歡迎留言指正!

6.參考

  • 張鑫旭 《CSS世界》

 **遇見了,不妨關注下我的微信公眾號「前端Talkking」**

【前端Talkking】CSS系列——CSS深入理解之absolute定位

相關文章