探秘 flex 上下文中神奇的自動 margin

来源:https://www.cnblogs.com/coco1s/archive/2019/05/23/10910588.html
-Advertisement-
Play Games

為了引出本文的主題,先看看這個問題,最快水平垂直居中一個元素的方法是什麼? 水平垂直居中也算是 CSS 領域最為常見的一個問題了,不同場景下的方法也各不相同,各有優劣。嗯,下麵這種應該算是最便捷的了: 上面的 display: flex 替換成 display: inline-flex | grid ...


為了引出本文的主題,先看看這個問題,最快水平垂直居中一個元素的方法是什麼?

水平垂直居中也算是 CSS 領域最為常見的一個問題了,不同場景下的方法也各不相同,各有優劣。嗯,下麵這種應該算是最便捷的了:

<div class="g-container">
    <div class="g-box"></div>
</div>
.g-container {
    display: flex;
}

.g-box {
    margin: auto;
}

上面的 display: flex 替換成 display: inline-flex | grid | inline-grid 也是可以的。

CodePen Demo -- 使用 margin auto 水平垂直居中元素

 

如何讓 margin: auto 在垂直方向上居中元素

嗯。這裡其實就涉及了一個問題,如何讓 margin: auto 在垂直方向上生效?

換句話說,傳統的 display: block BFC(塊格式化上下文)下,為什麼 margin: auto 在水平方向可以居中元素在垂直方向卻不行?

通常我們會使用這段代碼:

div {
    width: 200px;
    height: 200px;
    margin: 0 auto;
}

讓元素相對父元素水平居中。但是如果我們想讓元素相對父元素垂直居中的話,使用 margin: auto 0是不生效的。

 

BFC 下 margin: auto 垂直方向無法居中元素的原因

查看 CSS 文檔,原因如下,在 BFC 下:

If both margin-left and margin-right are auto, their used values are equal, causing horizontal centring.

—CSS2 Visual formatting model details: 10.3.3

If margin-top, or margin-bottom are auto, their used value is 0.

CSS2 Visual formatting model details: 10.6.3

簡單翻譯下,在塊格式化上下文中,如果 margin-left 和 margin-right 都是 auto,則它們的表達值相等,從而導致元素的水平居中。( 這裡的計算值為元素剩餘可用剩餘空間的一半)

而如果 margin-top 和 margin-bottom 都是 auto,則他們的值都為 0,當然也就無法造成垂直方向上的居中。

 

使用 FFC/GFC 使 margin: auto 在垂直方向上居中元素

OK,這裡要使單個元素使用 margin: auto 在垂直方向上能夠居中元素,需要讓該元素處於 FFC(flex formatting context),或者 GFC(grid formatting context) 上下文中,也就是這些取值中:

{
    display: flex;
    display: inline-flex;
    display: grid;
    display: inline-grid;
}

 

FFC 下 margin: auto 垂直方向可以居中元素的原因

本文暫且不談 grid 佈局,我們業務中需求中更多的可能是使用 flex 佈局,下文將著重圍繞 flex 上下文中自動 margin 的一些表現。

嗯,也有很多前端被戲稱為 flex 工程師,什麼佈局都 flex 一把梭。

查看 CSS 文檔,原因如下,在 dispaly: flex 下:

  • Prior to alignment via justify-content and align-self, any positive free space is distributed to auto margins in that dimension.

CSS Flexible Box Layout Module Level 1 -- 8.1. Aligning with auto margins

簡單翻譯一下,大意是在 flex 格式化上下文中,設置了 margin: auto 的元素,在通過 justify-content和 align-self 進行對齊之前,任何正處於空閑的空間都會分配到該方向的自動 margin 中去

這裡,很重要的一點是,margin auto 的生效不僅是水平方向,垂直方向也會自動去分配這個剩餘空間。

 

使用自動 margin 實現 flex 佈局下的 space-between | space-around

瞭解了上面最核心的這一句 :

  • 在通過 justify-content 和 align-self 進行對齊之前,任何正處於空閑的空間都會分配到該維度中的自動 margin 中去

之後,我們就可以在 flex 佈局下使用自動 margin 模擬實現 flex 佈局下的 space-between 以及 space-around 了。

自動 margin 實現 space-around

對於這樣一個 flex 佈局:

<ul class="g-flex">
    <li>liA</li>
    <li>liB</li>
    <li>liC</li>
    <li>liD</li>
    <li>liE</li>
</ul>

如果它的 CSS 代碼是:

.g-flex {
    display: flex;
    justify-content: space-around;
}

li { ... }

效果如下:

image

那麼下麵的 CSS 代碼與上面的效果是完全等同的:

.g-flex {
    display: flex;
    // justify-content: space-around;
}

li { 
    margin: auto;
}

CodePen Demo -- margin auto 實現 flex 下的 space-around

 

自動 margin 實現 space-between

同理,使用自動 margin,也很容易實現 flex 下的 space-between,下麵兩份 CSS 代碼的效果的一樣的:

.g-flex {
    display: flex;
    justify-content: space-between;
}

li {...}
.g-flex {
    display: flex;
    // justify-content: space-between;
}

li {
    margin: auto;
}

li:first-child {
    margin-left: 0;
}

li:last-child {
    margin-right: 0;
}

CodePen Demo -- margin auto 實現 flex 下的 space-between

當然,值得註意的是,很重要的一點:

Note: If free space is distributed to auto margins, the alignment properties will have no effect in that dimension because the margins will have stolen all the free space left over after flexing.

CSS Flexible Box Layout Module Level 1 -- 8.1. Aligning with auto margins

意思是,如果任意方向上的可用空間分配給了該方向的自動 margin ,則對齊屬性(justify-content/align-self)在該維度中不起作用,因為 margin 將在排布後竊取該緯度方向剩餘的所有可用空間。

也就是使用了自動 margin 的 flex 子項目,它們父元素設置的 justify-content 已經它們本身的 align-self 將不再生效,也就是這裡存在一個優先順序的關係。

  

使用自動 margin 實現 flex 下的 align-self: flex-start | flex-end | center

自動 margin 能實現水平方向的控制,也能實現垂直方向的控制,原理是一樣的。

用 margin: auto 模擬 flex 下的 align-self: flex-start | flex-end | center,可以看看下麵幾個 Demo:

 

不同方向上的自動 margin

OK,看完上面的一大段鋪墊之後,大概已經初步瞭解了 FFC 下,自動 margin 的神奇。

無論是多個方向的自動 margin,抑或是單方向的自動 margin,都是非常有用的。

再來看幾個有意思的例子:

使用 margin-left: auto 實現不規則兩端對齊佈局

假設我們需要有如下佈局:

image

DOM 結構如下:

<ul class="g-nav">
    <li>導航A</li>
    <li>導航B</li>
    <li>導航C</li>
    <li>導航D</li>
    <li class="g-login">登陸</li>
</ul>

對最後一個元素使用 margin-left: auto,可以很容易實現這個佈局:

.g-nav {
    display: flex;
}

.g-login {
    margin-left: auto;
}

此時, auto 的計算值就是水平方向上容器排列所有 li 之後的剩餘空間。

當然,不一定是要運用在第一個或者最後一個元素之上,例如這樣的佈局,也是完全一樣的實現:

image

<ul class="g-nav">
    <li>導航A</li>
    <li>導航B</li>
    <li>導航C</li>
    <li>導航D</li>
    <li class="g-login">登陸</li>
    <li>註冊</li>
</ul>
.g-nav {
    display: flex;
}

.g-login {
    margin-left: auto;
}

marginauto

Codepen Demo -- nav list by margin left auto

  

垂直方向上的多行居中

OK,又或者,我們經常會有這樣的需求,一大段複雜的佈局中的某一塊,高度或者寬度不固定,需要相對於它所在的剩餘空間居中:

image

這裡有 5 行文案,我們需要其中的第三、第四行相對於剩餘空間進行垂直居中。

這裡如果使用 flex 佈局,簡單的 align-self 或者 align-items 好像都沒法快速解決問題。

而使用自動 margin,我們只需要在需要垂直居中的第一個元素上進行 margin-top: auto,最後一個元素上進行 margin-bottom: auto 即可,看看代碼示意:

<div class="g-container">
    <p>這是第一行文案</p>
    <p>這是第二行文案</p>
    <p class="s-thirf">1、剩餘多行文案需要垂直居中剩餘空間</p>
    <p class="s-forth">2、剩餘多行文案需要垂直居中剩餘空間</p>
    <p>這是最後一行文案</p>
</div>
.g-container {
    display: flex;
    flex-wrap: wrap;
    flex-direction: column;
}

.s-thirf {
    margin-top: auto;
}

.s-forth {
    margin-bottom: auto;
}

當然,這裡將任意需要垂直居中剩餘空間的元素用一個 div 包裹起來,對該 div 進行 margin: auto 0也是可以的。

嗯,非常的好用且方便:CodePen Demo -- 自動margin快速垂直居中任意段落

 

使用 margin-top: auto 實現粘性 footer 佈局

OK,最後再來看這樣一個例子。

要求:頁面存在一個 footer 頁腳部分,如果整個頁面的內容高度小於視窗的高度,則 footer 固定在視窗底部,如果整個頁面的內容高度大於視窗的高度,則 footer 正常流排布(也就是需要滾動到底部才能看到 footer),算是粘性佈局的一種。

看看效果:

margintopauto

嗯,這個需求如果能夠使用 flex 的話,使用 justify-content: space-between 可以很好的解決,同理使用 margin-top: auto 也非常容易完成:

<div class="g-container">
    <div class="g-real-box">
        ...
    </div>
    <div class="g-footer"></div>
</div>
.g-container {
    height: 100vh;
    display: flex;
    flex-direction: column;
}

.g-footer {
    margin-top: auto;
    flex-shrink: 0;
    height: 30px;
    background: deeppink;
}

Codepen Demo -- sticky footer by flex margin auto

上面的例子旨在介紹更多自動 margin 的使用場景。當然,這裡不使用 flex 佈局也是可以實現的,下麵再給出一種不藉助 flex 佈局的實現方式:

CodePen Demo -- sticky footer by margin/paddig

 

值得註意的點

自動 margin 還是很實用的,可以使用的場景也很多,有一些上面提到的點還需要再強調下:

  • 塊格式化上下文中margin-top 和 margin-bottom 的值如果是 auto,則他們的值都為 0

  • flex 格式化上下文中,在通過 justify-content 和 align-self 進行對齊之前,任何正處於空閑的空間都會分配到該方向的自動 margin 中去

  • 單個方向上的自動 margin 也非常有用,它的計算值為該方向上的剩餘空間

  • 使用了自動 margin 的 flex 子項目,它們父元素設置的 justify-content 以及它們本身的 align-self 將不再生效

 

最後

更多精彩 CSS 技術文章彙總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

好了,本文到此結束,希望對你有幫助 :)

如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 混跡VR屆的發燒友兼開發者們一定不要錯過這款FaceBook推出的跨端VR開發框架——React360,稱為360全景體驗框架更為準確,因為其前身是FaceBook和Oculus2017年發佈的一個叫作“Racet VR”的JS庫,用來在web端創建3D和VR體驗。後來Oculus使用該框架的 ...
  • 封裝的一般套路 AJAX封裝步驟 1.寫出 AJAX 發送請求與接收響應的模板 2.寫一個空函數然後將這個模板放進去 3.最後根據變化量抽象參數,以及使用返回值 回調函數 回調:將函數作為參數傳遞,就好比是將一件事情交給另一個人做(也可以理解為委托) 在這個例子中,ajax非同步請求由於函數內部包含返 ...
  • 這兩天研究了一下topjui的可編輯表格edatagrid,想在每一列的後面根據返回的數據判斷是使用 combobox 還是 numberbox,期間遇到了一些坑,下麵實現代碼,需要的朋友可以參考一下。 json數據 html js 頁面刷新的的時候顯示如下圖,是正常的 可是你一旦編輯完的時候它就又 ...
  • 前言 本篇博文出至於我的 倉庫: "web study" ,如果你覺得對你有幫助歡迎star,你們的點贊是我持續更新的動力,謝謝! 非同步編程在前端開發中尤為常見,從最早的 ,到後來的各種封裝 ,再到 事件觸發的回調,無不涉及非同步編程。今天咱們來聊聊 中新提出的非同步解決方案: 和`async/awai ...
  • ztree ...
  • 離線緩存 application cache 1. 什麼是離線緩存: 離線緩存可以將站點的一些文件緩存到本地,它是瀏覽器自己的一種機制,將需要的文件緩存下來,以便後期即使沒有連接網路,被緩存的頁面也可以展示。 例子:比如我們在手機或電腦上訪問一個網頁,下一次訪問即使不連網也可以訪問,因為當我們第一次 ...
  • 1、一般做法 一般我們會把所有的` ...
  • 一、後臺nginx環境搭建 web點數據採集後臺配置nginx:https://blog.csdn.net/weixin_37490221/article/details/80894827 下載數據源:wget -O lua-nginx-module-0.10.0.tar.gz https://gi ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...