我的Vue之旅、01 深入Flexbox佈局完全指南

来源:https://www.cnblogs.com/linxiaoxu/archive/2022/09/16/16699507.html
-Advertisement-
Play Games

我的前端之旅。本節整合了"A Complete Guide to Flexbox"最新版本,介紹了flexbox的所有屬性,外帶幾個實用的例子。 ...


花了幾個小時整合的"A Complete Guide to Flexbox"最新版本,介紹了flexbox的所有屬性,外帶幾個實用的例子。

傳統佈局、Flexbox

佈局的傳統解決方案,基於盒狀模型,依賴 display、position、float 三大屬性。它對於那些特殊佈局非常不方便,比如,垂直居中就不容易實現。

Flex佈局,可以簡便、完整、響應式地實現各種頁面佈局。目前,它已經得到了所有瀏覽器的支持,這意味著,現在就能很安全地使用這項功能。

Flex是Flexible Box的縮寫,意為”彈性佈局”,用來為盒狀模型提供最大的靈活性。任何一個容器都可以指定為Flex佈局。

背景

Flexbox提供了一種有效的方式來對容器內的元素佈局、對齊、分配空間。能在不知道子元素大小或動態變化情況下分配好各個子元素間的間隙。(正如其名flex

Flex佈局的主要思想是給父元素動態調整子元素的高度寬度的能力,使各元素適應可用佈局空間。(能夠適應不同的設備和不同大小的屏幕),一個flex容器可以放大子元素來填充可用空間,也可以縮小子元素來防止溢出。

最重要的是,與常規佈局相比(垂直的塊佈局和水平的內聯佈局)Flexbox佈局是方向未知的。傳統佈局對大型複雜應用的靈活性不是很好(特別是在改變方向,大小,伸展,收縮方面)

註:Flexbox佈局適合應用組件或小規模的佈局。Grid佈局適合大規模的佈局。

基本概念

Flex佈局是一個完整的模塊而不是一個單獨的屬性,它包括了完整的一套屬性。其中有的屬性是設置在容器(container,也可以叫做父元素,稱為flex container)上,有的則是設置在容器的項目上(item,也可以叫做子元素,稱為flex items)上。

如果我們可以說傳統佈局是建立在塊狀元素垂直流和行內元素水平流上的,那麼flex佈局就是建立在”flex-flow方向”上的,通過下圖解釋flex佈局的主要思想。

在flex佈局中,子元素要麼按照主軸也就是main axis(從main-start到main-end)排布,要麼按照交叉軸,也就是cross axis(從cross-start到cross-end)排布。

  • main axis: Flex 父元素的主軸是指子元素佈局的主要方向軸,註意主軸不一定是水平的,它由屬性flex-direction來確定主軸是水平還是垂直的。
  • main-start|main-end: 分別表示主軸的開始和結束,子元素在父元素中會沿著主軸從main-start到main-end排布。
  • main size: 子元素在主軸方向上的大小。包括長度和寬度。
  • cross axis: 交叉軸,與主軸垂直。
  • cross-start|cross-end: 分別表示交叉軸的開始和結束。子元素在交叉軸的排布從cross-start開始到cross-end。
  • cross size: 子元素在交叉軸方向上的大小。包括長度和寬度。

屬性介紹

.container 是設置在容器上的,.item 是設置在子元素上的。

display 設置佈局容器

img
.container {
  display: flex; /* or inline-flex */
}

用來定義父元素是一個flex佈局容器。如果設置為flex則父元素為塊狀元素,設置為inline-flex父元素呈現為行內元素。它為它所有的直接子元素啟用了一個伸縮上下文。

flex-direction 主軸排列方向

.container {
  flex-direction: row | row-reverse | column | column-reverse;
}

flex-direction定義flex佈局的主軸方向。flex佈局是單方向佈局,子元素主要沿著水平行或者垂直列佈局。

  • row(預設):在LTR排版方式下從左到右; RTL從右到左
  • row-reverse:LTR 從右到左; RTL 從左到右
  • column:從上到下
  • column-reverse:從下到上

flex-warp 是否換行

.container {
  flex-wrap: nowrap | wrap | wrap-reverse;
}

預設情況下,flex佈局中父元素會把子元素儘可能地排在同一行,通過設置flex-wrap來決定是否允許子元素這行排列。

  • nowrap(預設值): 不折行,所有的子元素會排在一行。
  • wrap: 折行,子元素會從上到下根據需求折成多行。
  • wrap-reverse: 折行,子元素會從下到上根據需求折成多行。

flex-flow 縮寫形式

.container {
  flex-flow: row nowrap; /* column wrap */
}

flex-flow是flex-direction和flex-wrap屬性的縮寫形式。預設值是row nowrap

justify-content 元素對齊、主軸

.container {
  justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly | start | end | left | right ... + safe | unsafe;
}

justify-content屬性定義了子元素沿主軸方向的對齊方式,當子元素大小最大時(如長度最大化不可再增加),分配主軸上的剩餘空間(如寬度)。也可以當子元素超出主軸的時候用來控制子元素的對齊方式。

  • flex-start (預設值):項目位於容器的開頭。
  • flex-end:項目位於容器的結尾。
  • center:項目沿著線居中
  • space-between:物品均勻分佈線上上; 第一項是在起始行,最後一項是在結束行
  • space-around:項目均勻分佈線上條周圍,空間相等。請註意,視覺上空間不相等,因為所有項目在兩側都有相等的空間。第一個項目將在容器邊緣上有一個空間單位,但在下一個項目之間有兩個單位的空間,因為下一個項目有自己適用的間距。
  • space-evenly:項目是分佈的,以便任何兩個項目之間的間距(和邊緣的空間)相等。

align-items 元素對齊、交叉軸

.container {
  align-items: stretch | flex-start | flex-end | center | baseline | first baseline | last baseline | start | end | self-start | self-end + ... safe | unsafe;
}

align-items定義了所在行的子元素在交叉軸方向的對齊方向。可以將其視為justify-content豎軸的版本(垂直於主軸)。

  • stretch(預設值): 拉伸子元素使之填充整個父元素。(遵守min-width,max-width

  • flex-start / start / self-start: 按照交叉軸的起點對齊。

  • flex-end / end / self-end: 按照交叉軸的終點對齊。

  • center: 沿交叉軸方向居中。

  • baseline: 按照項目的第一行文字的基線對齊。

align-content 各行對齊、交叉軸

.container {
  align-content: flex-start | flex-end | center | space-between | space-around | space-evenly | stretch | start | end | baseline | first baseline | last baseline + ... safe | unsafe;
}

align-content是當父元素所包含的行在交叉軸方向有空餘部分時如何分配空間。與justify-content在主軸上如何對齊子元素很相似。

  • stretch (預設值):線條拉伸以占用剩餘空間

  • flex-start:元素位於容器的開頭

  • flex-end:元素位於容器的末尾

  • center:元素位於容器的中心

  • space-between:線條均勻分佈; 第一行是容器的開頭,而最後一行是在容器的最後

  • space-around:線條均勻分佈,每條線周圍的空間相等

註意當只有一行或flex-wrap為預設值的時候,該屬性並不起作用。

gap 子元素行列間距

.container {
  display: flex;
  ...
  gap: 10px;
  gap: 10px 20px; /* row-gap column gap */
  row-gap: 10px;
  column-gap: 20px;
}

gap 屬性明確控制子元素之間的空間。(邊緣與子元素之間沒效果)

order 子元素排列順序

.item {
  order: 5; /* default is 0 */
}

預設情況下,子元素按照代碼書寫的先後順序佈局,但order屬性可以更改子元素出現的順序。

註:order值一樣的子元素會按照預設按照代碼書寫的先後順序佈局。

flex-grow 子元素擴展比例

.item {
  flex-grow: 4; /* default 0 */
}

flex-grow規定在空間允許的情況下,子元素如何按照比例分配可用剩餘空間。如果所有的子元素的屬性都設定為1,則父元素中的剩餘空間會等分給所有子元素。如果其中某個子元素的flex-grow設定為2,則在分配剩餘空間時該子元素將獲得其他元素二倍的空間(至少會儘力獲得)。

註:flex-grow不接受負值。

flex-shrink 子元素縮小比例

.item {
  flex-shrink: 3; /* default 1 */
}

與flex-grow屬性類似,flex-shrink定義了空間不足時項目的縮小比例。

註:flex-shrink不接受負值。

flex-basis 子元素理想大小

.item {
  flex-basis:  | auto; /* default auto */
}

flex-basis表示在flex items被放入flex容器之前的大小,也就是items的理想或者假設大小,但是並不是其真實大小,其真實大小取決於flex容器的寬度,如min-width,max-width等。

flex-basis:auto指子元素基本尺寸根據其自身的尺寸決定。而這個自身尺寸與下麵這幾個方面有關

  • box-sizing 盒模型(flex-basis的尺寸是作用在content-box上的)
  • width/min-width/max-width等
  • content內容(min-content)
  • flex-grow產生的額外空間

flex-basis設置特定值時,同時設定width,最小內容寬度較大的時候,會按照了最小內容寬度顯示,而不是被width限制死尺寸。flex-basis優先順序是比width高

  • width:100px + flex-basis:auto = 元素自身100px
  • content + flex-basis:100px = max(content, flex-basis) = 大於等於100px
  • content + width:100px + flex-basis:100px = content + flex-basis:100px = max(content, flex-basis) = 大於等於100px

width只是flex-basis為auto時候間接生效,其餘時候使用優先順序更高的flex-basis屬性值;

/* 根據flex子項的內容自動調整大小 */
flex-basis: content; 尺寸根據內容決定

/* 內部尺寸關鍵字 */
flex-basis: fill;
flex-basis: max-content; 最大內容寬度。
flex-basis: min-content; 最小內容寬度。
flex-basis: fit-content;

註:由於瀏覽器相容性的問題,flex-basis數值屬性值和width數值屬性值不要同時使用。

flex 縮寫形式

.item {
  flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

flex是flex-grow、flex-shrink、flex-basis三個屬性的縮寫。其中第二個和第三個參數(flex-grow,flex-basis)是可選的。預設值為0 1 auto。

註:推薦使用縮寫形式而不是單獨地設置每一個屬性,縮寫形式中會智能地計算出相關值。

align-self 單個元素對齊、交叉軸

.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

通過設置某個子元素的align-self屬性,可以覆蓋align-items所設置的對齊方式。

註:float、clear、vertical-align 對flex子元素無影響。

例子

水平垂直居中

image-20220916144233953

<div class="parent">
<span class="child">水平垂直居中</span>
</div>
.parent {
  display: flex;
  height: 300px;
  border: 1px solid;
}

.child {
  width: 100px;
  height: 100px;
  line-height: 100px;
  margin: auto;
  border: 1px solid;
}

給子元素設置 marginauto,可以吸收額外的空間。使元素在兩個軸上完美居中。

響應式初體驗

考慮有6個子元素,有固定的大小,希望能夠在改變瀏覽器寬度的時候仍然可以在水平軸上完美地顯示。

image-20220916122457513

<ul class="flex-container">
  <li class="flex-item">1</li>
  <li class="flex-item">2</li>
  <li class="flex-item">3</li>
  <li class="flex-item">4</li>
  <li class="flex-item">5</li>
  <li class="flex-item">6</li>
</ul>
.flex-container {
  /* 設置flex容器 */
  display: flex;
  
  /* Then we define the flow direction 
     and if we allow the items to wrap 
   * Remember this is the same as:
   * flex-direction: row;
   * flex-wrap: wrap;
   */
  flex-flow: row wrap;
  
  /* Then we define how is distributed the remaining space */
  justify-content: space-around;
  
  padding: 0;
  margin: 0;
  list-style: none;
}

.flex-item {
  background: tomato;
  padding: 5px;
  width: 200px;
  height: 150px;
  margin-top: 10px;
  line-height: 150px;
  color: white;
  font-weight: bold;
  font-size: 3em;
  text-align: center;
}

https://codepen.io/css-tricks/embed/EKEYob

響應式導航欄

一個向右對齊的導航欄在網頁的最上端,我們希望它在中屏上顯示時為居中,在小屏上以單列顯示。

image-20220916122415234

<ul class="navigation">
  <li><a href="#">Home</a></li>
  <li><a href="#">About</a></li>
  <li><a href="#">Products</a></li>
  <li><a href="#">Contact</a></li>
</ul>
.navigation {
  display: flex;
  flex-flow: row wrap;
  justify-content: flex-end;
  
  list-style: none;
  margin: 0; 
  background: deepskyblue;
}

.navigation a {
  text-decoration: none;
  display: block; /* 變成塊級元素撐起整個navigation */
  padding: 1em;
  color: white;
}

.navigation a:hover {
  background: #1565C0;
}

/* 往中屏切換 */
@media all and (max-width: 800px) {
  .navigation {
    justify-content: space-around;
  }
}

/* 往小屏切換 */
@media all and (max-width: 600px) {
  .navigation {
    flex-flow: column wrap;
    padding: 0;
  }
  .navigation a { 
    text-align: center; 
    padding: 10px;
    border-top: 1px solid rgba(255, 255, 255,0.3); 
    border-bottom: 1px solid rgba(0, 0, 0, 0.1); 
  }
  .navigation li:last-of-type a {
    border-bottom: none;
  }
}

https://codepen.io/css-tricks/embed/YqaKYR

網頁結構佈局

image-20220916122948293

<div class="wrapper">
  <header class="header">Header</header>
  <article class="main">
    <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>  
  </article>
  <aside class="aside aside-1">Aside 1</aside>
  <aside class="aside aside-2">Aside 2</aside>
  <footer class="footer">Footer</footer>
</div>
.wrapper {
  display: flex;  
  flex-flow: row wrap;
  font-weight: bold;
  text-align: center; 
}

.wrapper > * {
  padding: 10px;
  flex: 1 100%;
}

.header {
  background: tomato;
}

.footer {
  background: lightgreen;
}

.main {
  text-align: left;
  background: deepskyblue;
}

.aside-1 {
  background: gold;
}

.aside-2 {
  background: hotpink;
}

@media all and (min-width: 600px) {
  .aside { flex: 1 0 0; }
}

@media all and (min-width: 800px) {
  .main    { flex: 3 0px; }
  .aside-1 { order: 1; } 
  .main    { order: 2; }
  .aside-2 { order: 3; }
  .footer  { order: 4; }
}

body {
  padding: 2em; 
}

https://codepen.io/anon/embed/vWEMWw

更美觀的標題

使用絕對定位的方式將文本放置在右邊,因為不在文檔流中,無法智能地決定何時換行。

使用float,在換行時不會有很好的左對齊效果。

使用表格,不會進行換行。

image-20220916123848055

<h3 class="title abs-title">
  <span class="title-main">Main Title Here</span>
  <span class="title-note">This is absolutely positioned.</span>
</h3>

<h3 class="title float-title">
  <span class="title-main">Main Title Here</span>
  <span class="title-note">This subtitle is floated.</span>
</h3>

<h3 class="title table-title">
  <span class="title-main">Main Title Here</span>
  <span class="title-note">I am a table cell.</span>
</h3>

<h3 class="title flex-title">
  <span class="title-main">Main Title Here</span>
  <span class="title-note">This is a good look, right here.</span>
</h3>
body {
  padding: 100px;
  font-size: 21px;
}

.title {
  border-bottom: 1px solid #ccc;
  max-width: 500px;
  margin: 40px auto;
}
.title-note {
  font-size: 60%;
  color: #999;
}

.abs-title {
  position: relative;
  .title-note {
    position: absolute;
    bottom: 2px;
    right: 0;
  }
}

.float-title {
  .title-note {
    float: right;
    position: relative;
    top: 12px;
  }
}

.table-title {
  display: table;
  width: 100%;
  > span {
    display: table-cell;
    white-space: nowrap;
  }
  .title-main {
    width: 99%;
  }
}

.flex-title {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  > span {
    white-space: nowrap;  /* 強制在同一行內顯示所有文本 */
  }
  .title-main {
    flex-grow: 1;  /* 讓標題利用多餘空間進行擴展,從而使副標題緊靠右邊 */
  }
}

https://codepen.io/chriscoyier/embed/doVXLV

使用海報

image-20220916125235514

下載:https://xiaonenglife.oss-cn-hangzhou.aliyuncs.com/static/pic/2022/09/20220916125123_css-flexbox-poster.png

參考資料

Flex 佈局語法教程 | 菜鳥教程

A Complete Guide to Flexbox | CSS-Tricks - CSS-Tricks

flex-basis_奔跑吧、GZB的博客


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

-Advertisement-
Play Games
更多相關文章
  • 好家伙, 我的飛機大戰部署上線了 胖虎的飛機大戰 感興趣的可以去玩一下 (怕有人接受不了這個背景,我還貼心的準備切換背景按鈕,然而這並沒有什麼用) 現在,我們停下腳步,重新審視這個游戲 現在基本的框架都弄出來了,敵機,英雄,子彈,分數,生命 但是,這個“游戲“有個非常致命的問題, 他不好玩,(不好玩 ...
  • 本文分別使用 SFC(模板方式)和 tsx 方式對 Element Plus *el-menu* 組件進行二次封裝,實現配置化的菜單,有了配置化的菜單,後續便可以根據路由動態渲染菜單。 ...
  • vue3中,新增了 defineComponent ,它並沒有實現任何的邏輯,只是把接收的 Object 直接返回,它的存在是完全讓傳入的整個對象獲得對應的類型,它的存在就是完全為了服務 TypeScript 而存在的。 我都知道普通的組件就是一個普通的對象,既然是一個普通的對象,那自然就不會獲得自 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一、前言 入職的第一個需求是跟著一位前端大佬一起完成的一個活動項目。 由於是一起開發,當然不會放過閱讀大佬的代碼的機會。 因為我的頁面中需要使用到倒計時功能,發現大佬的已經寫了個現成的倒計時組件,於是直接就拿過來用了。 傳個參數就實現了功 ...
  • 本人的工作項目中,需求是: 點擊“列印”按鈕,打開pdf預覽彈出框,彈出框有:頭部選擇列印模板、列印方式、印表機,都是下拉選擇框;中部是pdf預覽塊;底部是確定列印。 準備工作: 預覽pdf,後端介面返回了pdf預覽地址,可線上直接打開。vue-pdf插件可以滿足需求。 選擇方式如果選擇本地列印,下 ...
  • 1.如果只比較兩個值的話 效果是這種的 // 這是<template>的 <el-row> <el-col :span="12"> <el-form-item label="計劃評審日期(起)" prop="planPsDateStart"> <el-date-picker v-model="vm. ...
  • 每日3題 1 以下代碼執行後,控制臺中的輸出內容為? // 以下代碼執行後,瀏覽器的控制臺中輸出的內容是什麼 var arr = [0, 1, 2]; arr[10] = 10; var newArr = arr.filter((x) => x undefined); console.log(new ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 uniapp上如何實現安卓app微信登錄功能?下麵本篇文章給大家分享一下uniapp上實現安卓app微信登錄的許可權申請、開發的具體操作流程,希望對大家有所幫助! 微信開放平臺提供了微信的一些開放介面,比如微信登錄、分享支付等,為其他各平臺 ...
一周排行
    -Advertisement-
    Play Games
  • 1、預覽地址:http://139.155.137.144:9012 2、qq群:801913255 一、前言 隨著網路的發展,企業對於信息系統數據的保密工作愈發重視,不同身份、角色對於數據的訪問許可權都應該大相徑庭。 列如 1、不同登錄人員對一個數據列表的可見度是不一樣的,如數據列、數據行、數據按鈕 ...
  • 前言 上一篇文章寫瞭如何使用RabbitMQ做個簡單的發送郵件項目,然後評論也是比較多,也是準備去學習一下如何確保RabbitMQ的消息可靠性,但是由於時間原因,先來說說設計模式中的簡單工廠模式吧! 在瞭解簡單工廠模式之前,我們要知道C#是一款面向對象的高級程式語言。它有3大特性,封裝、繼承、多態。 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 介紹 Nodify是一個WPF基於節點的編輯器控制項,其中包含一系列節點、連接和連接器組件,旨在簡化構建基於節點的工具的過程 ...
  • 創建一個webapi項目做測試使用。 創建新控制器,搭建一個基礎框架,包括獲取當天日期、wiki的請求地址等 創建一個Http請求幫助類以及方法,用於獲取指定URL的信息 使用http請求訪問指定url,先運行一下,看看返回的內容。內容如圖右邊所示,實際上是一個Json數據。我們主要解析 大事記 部 ...
  • 最近在不少自媒體上看到有關.NET與C#的資訊與評價,感覺大家對.NET與C#還是不太瞭解,尤其是對2016年6月發佈的跨平臺.NET Core 1.0,更是知之甚少。在考慮一番之後,還是決定寫點東西總結一下,也回顧一下.NET的發展歷史。 首先,你沒看錯,.NET是跨平臺的,可以在Windows、 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 添加節點(nodes) 通過上一篇我們已經創建好了編輯器實例現在我們為編輯器添加一個節點 添加model和viewmode ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...
  • 類型檢查和轉換:當你需要檢查對象是否為特定類型,並且希望在同一時間內將其轉換為那個類型時,模式匹配提供了一種更簡潔的方式來完成這一任務,避免了使用傳統的as和is操作符後還需要進行額外的null檢查。 複雜條件邏輯:在處理複雜的條件邏輯時,特別是涉及到多個條件和類型的情況下,使用模式匹配可以使代碼更 ...
  • 在日常開發中,我們經常需要和文件打交道,特別是桌面開發,有時候就會需要載入大批量的文件,而且可能還會存在部分文件缺失的情況,那麼如何才能快速的判斷文件是否存在呢?如果處理不當的,且文件數量比較多的時候,可能會造成卡頓等情況,進而影響程式的使用體驗。今天就以一個簡單的小例子,簡述兩種不同的判斷文件是否... ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...