CSS實用技巧(中)

Gerryli發表於2021-09-06

前言

我們經常使用CSS,但是卻不怎麼了解CSS,本文主要對vertical-alignBFCposition中開發過程不怎麼注意的特性進行簡要總結,從本文中,你將瞭解到以下內容:

  • vertical-align為何時靈時不靈
  • BFC是什麼?有何作用
  • 絕對定位的奇淫技巧

CSS特性

vertical-align為什麼時靈時不靈

生效條件

只能應用在displayinlineinline-blockinline-tabletable-cell上。

有個高頻面試題,“如何使一個不定寬高div垂直水平居中?”,有的萌新竟然回答用vertical-align: middle。這個回答是減分的,至少在某種程度上給人一種感覺CSS基礎比較薄弱。

內聯元素垂直居中對齊

開發中會遇到用字幕x代替關閉icon,用...顯示溢位或者載入中。但是會發現字母x、省略號並沒有與文字垂直方向居中對齊,這是因為文字預設是基線對齊,x、省略號預設底部在基線處。如下圖所示:

如下,為文字對齊demo:

<div class="container">
  <span>你好,世界</span>
  <span class="more">...</span>
</div>

實際顯示效果如下:

如果要實現垂直居中,利用vertical-align,搭配line-height即可,vertical-align不僅可以設定middle/top/bottom/baseline...關鍵字,也可以設定常用的度量單位,正負值均可,使用比較靈活。為什麼要給.more設定line-height屬性呢?其實是因為line-height屬性可以繼承,如果不縮小.more的行高,就會撐大父元素的尺寸。

<style>
  .container{
    font-size: 64px;
    line-height: 64px;
  }
  .more{
    line-height: 16px;
    vertical-align: 16px;
  }
</style>

BFC究竟有什麼作用

什麼是BFC

BFC全稱block formatting context,即“塊狀格式化上下文”,與外界元素相對獨立的一片區域,具有以下特性:

  • 計算BFC高度時,浮動元素也參與計算
  • 屬於同一BFC容器的元素垂直方向的margin會合並
  • BFC容器是獨立容器,不會影響外部元素的佈局

利用BFC的特性,我們可以實現以下功能:

  1. 清除浮動
  2. 防止垂直方向margin合併
  3. 實現多欄彈性佈局

BFC的生效條件

以下CSS屬性會觸發元素生成BFC結界:

  • 根元素(<html>
  • 浮動元素(元素的 float 不是 none
  • 絕對定位元素(元素的 positionabsolutefixed
  • 行內塊元素(元素的 displayinline-block
  • 表格單元格(元素的 displaytable-cellHTML表格單元格預設為該值)
  • 表格標題(元素的 displaytable-captionHTML表格標題預設為該值)
  • 匿名錶格單元格元素(元素的 displaytabletable-rowtable-row-grouptable-header-grouptable-footer-group(分別- 是HTML tablerowtbodytheadtfoot 的預設屬性)或 inline-table
  • overflow 計算值(Computed)不為 visible 的塊元素
  • display 值為 flow-root 的元素
  • contain 值為 layoutcontentpaint 的元素
  • 彈性元素(displayflexinline-flex 元素的直接子元素)
  • 網格元素(displaygridinline-grid 元素的直接子元素)
  • 多列容器(元素的 column-countcolumn-width 不為 auto,包括 column-count 為 1)
  • column-spanall 的元素始終會建立一個新的BFc

BFC使用案例

  • 清除浮動
<style>
  .container{
    /* overflow: hidden; */
    /* position: absolute; */
    /* float: left; */
  }
  .left{
    float: left;
    width: 200px;
    height: 200px;
  }
</style>
<div class="container">
  <div class="left"></div>
</div>

以上程式碼,container容器高度為0,因為子元素left浮動。我們只需要把container容器轉成BFC容器,即可清楚浮動,註釋的幾種方法都可以。

  • 防止垂直方向margin合併
<style>
  .blue, .red-inner {
    height: 50px;
    margin: 10px 0;
  }

  .blue {
    background: blue;
  }

  .red-outer {
    overflow: hidden;
    background: red;
  }
</style>
<div class="blue"></div>
<div class="red-outer">
  <div class="red-inner">red inner</div>
</div>
  • 自適應佈局

左側固定,右側自適應。

<style>
  .left{
    height: 200px;
    width: 200px;
    float: left;
    background-color: burlywood;
  }
  .right{
    height: 200px;
    margin-left: 200px;
    background-color: cadetblue;
  }
</style>
<div class="container">
  <div class="left"></div>
  <div class="right"></div>
</div>

絕對定位還能玩出什麼花樣

簡介

絕對定位使用場景非常多。絕對定位元素脫離文件流,相對於最近的非 static 祖先元素定位,可以利用left/right/top/bottom定位元素位置。我們通常都是設定垂直方向與水平方向的的位置,如果四個方向都不設定或者四個方向都設定會出現什麼彩蛋呢?下文會給出揭曉。

left/top/right/bottom都有值的定位

  • 當對立位置(leftrighttopbottom)都設定值且元素沒用固定寬高

此時元素的寬高是根據元素位置決定的,張鑫旭大佬在《CSS世界》中定義為格式化寬高,如下程式碼,最終box-item的寬高計算為:width = 200 - 50 -50 = 100px;width = 200 - 50 -50 = 100px;

<style>
  .box{
    position: relative;
    width: 200px;
    height: 200px;
    margin: 50px;
    background-color: bisque;
  }
  .box-item{
    position: absolute;
    left: 50px;
    right: 50px;
    top: 50px;
    bottom: 50px;
    background-color: coral;
  }
</style>
 <div class="box">
    <div class="box-item"></div>
  </div>

這種行為特性對於我們做自適應佈局非常有用,而且相容性非常好,比如我們要做左側固定寬度,右側自適應,除了以上BFC的寫法,我們還可以採用以下方法:

<style>
  .container{
    position: absolute;
    top: 100px;
    bottom: 100px;
    left: 0;
    right: 0;
  }
  .left{
    position: absolute;
    top: 0;
    bottom: 0;
    width: 200px;
    background-color: burlywood;
  }
  .right{
    position: absolute;
    left: 200px;
    right: 0;
    top: 0;
    bottom: 0;
    background-color: cadetblue;
  }
</style>
<div class="container">
  <div class="left"></div>
  <div class="right"></div>
</div>
  • 當對立位置都設定了值且元素設定了固定寬高

這個時候你會發現,元素的寬高時以width/height為準,上述說的格式化寬度、高度並沒有生效。這是因為在高度計算過程中,元素的內部尺寸優先順序大於外部尺寸,width/height影響的是元素內部尺寸,絕對定位影響的是外部尺寸,當元素絕對定位四個方向都設定值,此時外部尺寸會被內部尺寸覆蓋,導致實際元素寬度是width/height的值。

我們經常用margin: 0 auto;實現元素水平居中,但是不定寬高元素垂直水平居中就有些麻煩。但是有個神奇的現象,絕對定位配合margin: auto;,可以實現元素垂直水平居中,如下所示:

<style>
  .box{
    position: relative;
    width: 200px;
    height: 200px;
    margin: 50px;
    background-color: bisque;
  }
  .box-item{
    position: absolute;
    margin: auto;
    width: 50px;
    height: 50px;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    background-color: coral;
  }
</style>
<div class="box">
  <div class="box-item"></div>
</div>

出現這種現象是因為margin:auto本質上是平分元素剩餘可用空間,塊級元素一般是水平方向自動充滿,垂直方向順序排列。平常我們用margin: 0 auto;之所以能夠使塊級元素水平居中,是因為水平方向元素存在剩餘可用空間,而auto平分剩餘可用空間,因此就產生居中效果。而垂直方向不存在剩餘可用空間,因此無法垂直居中。
上述demobox-item之所以能夠垂直居中,得益於top/bottom設定了值,使元素產生高度100%的外部尺寸,而width/height固定元素的內部尺寸,使得 外部尺寸高度-內部尺寸高度=元素剩餘可用空間高度,而auto等分剩餘可用空間,可以使元素達到垂直居中效果。可以嘗試調整四個方向的值,看看box-item位置是怎麼移動的。

無依賴的絕對定位

當絕對定位沒有設定四周定位尺寸時,會發生神奇的一幕,當前元素沒有相對於最近的非 static 祖先元素定位,而是在當前位置不變,並且當前元素脫離文件流,不佔據頁面空間。這個特性某些情況下非常有用,比如給box-card加一個圖示,藉助無依賴定位 + padding/margin即可。寫法比較簡潔,建議嘗試一下。

小結

比起其他的開發語言,想要深入瞭解CSS,並不是一件容易事,大多數人都是停留在用的基礎上,知道這個屬性/方法,至於為什麼會這樣瞭解較少。張鑫旭大佬CSS高度讓人歎為觀止,繼續加油吧!!!

參考資料

  • CSS世界》
  • BFC

相關文章