收藏!40 個 CSS 佈局技巧

阿里技術發表於2020-07-22
收藏!40 個 CSS 佈局技巧

阿里妹導讀:CSS是Web開發中不可或缺的一部分,隨著Web技術的不斷革新,CSS也變得更加強大。CSS的眾多屬性你知道了多少?具體開發中該使用什麼屬性才最適合恰當?如今的一些CSS屬性可以讓我們節約更多的時間。比如在Web佈局中,現代CSS特性就可以更好的幫助我們快速實現如等高佈局,水平垂直居中,經典的聖盃佈局、寬高比例、頁尾保持在底部等效果。淘系前端技術專家大漠將詳細介紹一些不同的CSS屬性來實現這些效果,希望對同學們有所幫助。

一  水平垂直居中

如何實現水平垂直居中可以說是CSS面試題中的經典面試題,在多年前這個面試題給很多同學都帶來了困惑,但Flexbxo佈局模組和CSS Grid佈局模組的到來,可以說實現水平垂直居中已是非常的容易。

Flexbox中實現水平垂直居中

在Flexbox佈局模組中,不管是單行還是多行,要讓它們在容器中水平垂直居中都是件易事,而且方法也有多種。最常見的是在Flex容器上設定對齊方式,在Flex專案上設定 margin:auto。

先來看在Flex容器上設定對齊方式。

Flex容器和Flex專案上設定對齊方式

你可能已經知道在Flex容器上設定 justify-content、align-items 的值為 center 時,可以讓元素在Flex容器中達到水平垂直居中的效果。來看一個示例:

<!-- HTML --><div class="flex__container">    <div class="flex__item"></div></div>/* CSS */.flex__container {    display: flex;    justify-content: center;    align-items: center;}

效果如下:

收藏!40 個 CSS 佈局技巧

這種方式特別適應於讓Icon圖示在容器中水平垂直居中,不同的是在Icon圖示容器上顯示設定display: inline-flex。比如下面這個示例:

<!-- HTML --><div class="flex__container">    <svg> </svg></div>/* CSS */.flex__container {    display: inline-flex;    align-items: center;    justify-content: center;}

效果如下:

收藏!40 個 CSS 佈局技巧

在這種模式之下,如果要讓多個元素實現水平垂直居中的效果,那還需要加上 flex-direction: column,比如:

<!-- HTML --><div class="flex__container">    <div class="avatar">:)</div>    <div class="media__heading"></div>    <div class="media__content"></div>    <div class="action"></div></div>/* CSS */.flex__container  {    display: flex;    flex-direction: column;    justify-content: center;    align-items: center;}

效果如下:

收藏!40 個 CSS 佈局技巧

在Flexbox佈局中,還可以像下面這樣讓Flex專案在Flex容器中達到水平垂直居中的效果:

<!-- HTML --><div class="flex__container">    <div class="flex__item"></div></div>/* CSS */.flex__container {    display: flex; // 或inline-flex    justify-content: center;}.flex__item {    align-self: center;}

效果如下:

收藏!40 個 CSS 佈局技巧

如果在Flex容器中有多個Flex專案時,該方法同樣有效:

.flex__container {    display: flex; // 或inline-flex    justify-content: center;}.flex__container > * {    align-self: center;}

比如下面這個效果:

收藏!40 個 CSS 佈局技巧

除此之外,還可以使用 place-content: center 讓Flex專案實現水平垂直居中:

.flex__container {    display: flex;    place-content: center;}.flex__item {    align-self: center;}

效果如下:

收藏!40 個 CSS 佈局技巧

或者換:

.flex__container {    display: flex;    place-content: center;    place-items: center;}

效果如下:

收藏!40 個 CSS 佈局技巧

這兩種方式同樣適用於Flex容器中有多個Flex專案的情景:

.flex__container {    display: flex;    flex-direction: column;    place-content: center;}.flex__container > * {    align-self: center;}// 或.flex__container {    display: flex;    flex-direction: column;    place-content: center;    place-items: center;}

效果如下:

收藏!40 個 CSS 佈局技巧


可能很多同學對於 place-content 和 place-items 會感到陌生。其實 place-content 是 align-content 和 justify-content 的簡寫屬性;而 place-items 是 align-items 和 justify-items 的簡寫屬性。即:

.flex__container {    place-content: center;    place-items: center;}


等效於:

.flex__container {    align-content: center;    justify-content: center;    align-items: center;    justify-items: center;}


雖然擴充套件出來有四個屬性,但最終等效於:

.flex__container {    display: flex;    align-items: center;    justify-content: center;}// 多行.flex__container {    display: flex;    flex-direction: column;    align-items: center;    justify-content: center;}


在Flex專案上設定margin: auto


如果在Flex容器中只有一個Flex專案,還可以顯式在Flex專案中顯式設定 margin 的值為auto,這樣也可以讓Flex專案在Flex容器中水平垂直居中。例如:

.flex__container {    display: flex; // 或 inline-flex}.flex__item {    margin: auto;}


效果如下:


收藏!40 個 CSS 佈局技巧

整個過程,你可以透過下面這個示例來體驗。嘗試著選中不同方向的 margin 值:

收藏!40 個 CSS 佈局技巧

Grid中實現水平垂直居中

CSS Grid佈局可以說是現代Web佈局中的銀彈。它也是到目前為止佈局系統中唯一一個二維佈局系統。

在CSS Grid佈局中,只需要僅僅的幾行程式碼也可以快速的幫助我們實現水平垂直居中的效果。比如下面這個示例:

<!-- HTML --><div class="grid__container">    <div class="grid__item"></div></div>/* CSS */.grid {    display: grid; // 或 inline-grid    place-items: center}

效果如下:

收藏!40 個 CSS 佈局技巧

在CSS Grid佈局模組中,只要顯式設定了 display: grid(或 inline-grid)就會建立Grid容器和Grid專案,也會自動生成網格線,即行和列(預設為一行一列)。

收藏!40 個 CSS 佈局技巧

在沒有顯式地在Grid容器上設定 grid-template-columns 和 grid-template-rows,瀏覽器會將Grid容器預設設定為Grid內容大小:

收藏!40 個 CSS 佈局技巧


這種方法也適用於CSS Grid容器中有多個子元素(Grid專案),比如:

<!-- HTML --><div class="grid__container">    <div class="avatar">:)</div>    <div class="media__heading"></div>    <div class="media__content"></div>    <div class="action"></div></div>

這個時候你看到的效果如下:

收藏!40 個 CSS 佈局技巧

而且 palce-items 適用於每個單元格。這意味著它將居中單元格的內容。比如下面這個示例:

<!-- HTML --><div class="grid__container">    <div class="grid__item">        <h3>Special title treatment</h3>        <p>With supporting text below as a natural lead-in to additional content.</p>        <div class="action">Go somewhere</div>    </div></div>/* CSS */.grid__container {    display: grid;    place-items: center;    grid-template-columns: repeat(2, 1fr);    gap: 2vh;}.grid__item {    display: grid;    place-items: center;}

效果如下:

收藏!40 個 CSS 佈局技巧

二  等高佈局

等高佈局也是Web中非常常見的一種佈局方式,而且實現等高佈局的方案也有很多種。這裡我們主要來看Flexbox佈局模組和Grid佈局模組給我們帶來了什麼樣的變化。

在Flexbox和Grid佈局模組中,讓我們實現等高佈局已經是非常的簡單了,比如:


<!-- Flexbox --><flex__container>    <flex__item></flex__item>    <flex__item></flex__item>    <flex__item></flex__item></flex__container>/* CSS */.flex__container {    display: flex; // 或 inline-flex}


簡單地說,在容器上顯式設定了 display 的值為 flex 或 inline-flex,該容器的所有子元素的高度都相等,因為容器的 align-items 的預設值為 stretch。

這個時候你看到的效果如下:

收藏!40 個 CSS 佈局技巧

這種方式特別適用於卡片元件中:

收藏!40 個 CSS 佈局技巧

在Grid佈局模組中類似:

<!-- HTML --><grid__container>    <grid__item></grid__item>    <grid__item></grid__item>    <grid__item></grid__item></grid__container>/* CSS */.grid__container {    display: grid;    grid-template-columns: 20vw 1fr 20vw; /* 根據需求調整值*/}

效果如下:

收藏!40 個 CSS 佈局技巧

同樣在一些卡片類佈局中運用:

收藏!40 個 CSS 佈局技巧

如果需求有所調整,比如在Flex專案 或 Grid專案的子元素高度和容器高度相同。

<!-- HTML --><flex__container>    <flex__item>        <content></content>    </flex__item></flex__container>/* CSS */.flex__container {    display: flex;}.content {    height: 100%}// 或.grid__container {    display: grid;    grid-auto-flow: column;}.content {    height: 100%;}

效果如下:

收藏!40 個 CSS 佈局技巧

三  Sticky Footer

首先用下圖來描述什麼是Sticky Footer佈局效果:

收藏!40 個 CSS 佈局技巧


Sticky Footer實現方案和等高、垂直居中一樣,同樣有很多種方案可以實現。

比如像下面這樣的結構:

<!-- HTML --><header></header><main></main><footer></footer>


先來看Flexbox佈局模組中的實現方案:

body {    display: flex;    flex-direction: column;}footer {    margin-top: auto;}


收藏!40 個 CSS 佈局技巧


可以嘗試著在 main 區域右下角向下拖動,改變主內容區域的高度,你會發現“當內容不足一屏時,<footer> 會在頁面的最底部,當內容超出一屏時,<footer> 會自動往後延後”。

在Flexbox佈局中,還可以在 <main> 區域上設定下面的樣式,達到相等的效果:

body {    display: flex;    flex-direction: column;}main {    flex: 1 0 auto;}

效果如下:

收藏!40 個 CSS 佈局技巧

<main> 中的 flex: 1 0 auto 相當於是:

main {    flex-grow: 1; /*容器有剩餘空間時,main區域會擴充套件*/    flex-shrink: 0; /*容器有不足空間時,main區域不會收縮*/    flex-basis: auto; /*main區域高度的基準值為main內容自動高度*/}

如果你想省事的話,可以在 main 上顯式設定 flex-grow:1,因為 flex-shrink 和 flex-basis 的預設值為 1 和 auto。

在CSS Grid佈局中我們可以藉助 1fr 讓 <main> 區域根據Grid容器剩餘空間來做計算。

.grid__container {    display: grid;    grid-template-rows: auto 1fr auto;}

效果如下:

收藏!40 個 CSS 佈局技巧

四  均分列

在Web佈局中,很多時候會對列做均分佈局,最為常見的就是在移動端的底部Bar,比如下圖這樣的一個效果:

收藏!40 個 CSS 佈局技巧

在Flexbox和Grid還沒出現之前,如果希望真正的做到均分效果,可以用 100%(或 100vw)除以具體的列數。比如:

<!-- HTML --><container>    <column></column>    <column></column>    <column></column></container>/* CCSS */.container {    inline-size: 50vw;    min-inline-size: 320px;    display: flex-row;}.column {    float: left;    width: calc(100% / 3);}

效果如下:

收藏!40 個 CSS 佈局技巧

透過瀏覽器偵錯程式中可以發現,現個列的寬度都是相等的:

收藏!40 個 CSS 佈局技巧

在Flexbox和Grid佈局中,實現上面的效果會變得更容易地多。先來看Flexbox中的佈局:

<!-- HTML --><flex__container>    <flex__item></flex__item>    <flex__item></flex__item>    <flex__item></flex__item></flex__container>/* CSS */.flex__container {    inline-size: 50vw;    display: flex;}.flex__item {    flex: 1;}

效果如下:


收藏!40 個 CSS 佈局技巧

在Flexbox佈局模組中,當flex取的值是一個單值(無單位的數),比如示例中的 flex:1,它會當作顯式的設定了 flex-grow: 1。瀏覽器計算出來的 flex:

收藏!40 個 CSS 佈局技巧

接下來看Grid中如何實現上例的效果:

<!-- HTML --><grid__container>    <grid__item></grid__item>    <grid__item></grid__item>    <grid__item></grid__item></grid__container>/* CSS */.grid__container {    display: grid;    grid-template-columns: repeat(3, 1fr); /*這裡的3表示具體的列數*/}

最終的效果是相同的:

收藏!40 個 CSS 佈局技巧

這樣的佈局方式也適用於其他的佈局中。但不管是Flexbox還是Grid佈局中,都存在一定的缺陷,當容器沒有足夠的空間容納Flex專案(或Grid專案)時,Flex專案或Grid專案會溢位(或隱藏,如果Flex容器或Grid容器顯式設定了 overflow:hidden):

收藏!40 個 CSS 佈局技巧

修復這種現象最簡單的方式是在Flex容器或Grid容器顯式設定一個 min-width(或 min-inline-size):

.flex__container {    min-inline-size: 300px;}

不過話又說回來,比如我們的Flex專案(或Grid專案)是一個卡片,每張卡片寬度是相等之外,更希望容器沒有足夠空間時,Flex專案(或Grid專案)會自動斷行排列。

我們繼續透過示例向大家展示。先來看Flexbox實現方案:

.flex__container {    display: flex;    flex-wrap: wrap;}.flex__item {    flex: 0 1 calc((100vw - 18vh) / 4); /* calc(100vw -18vh) / 4 是flex-basis的基準值 */}

收藏!40 個 CSS 佈局技巧

你可以嘗試著調整瀏覽器的視窗寬度,當瀏覽器的視窗越來越小時,Flex容器寬度也就會越來越小,當Flex容器小到沒有足夠的空間容納四個Flex專案(就此例而言),那麼Flex專案就會斷行排列:

收藏!40 個 CSS 佈局技巧

基於該例,如果把Flex專案的 flex 值改成:

.flex__item {    flex: 0 0 400px;}

這個時候,當Flex容器沒有足夠空間時,Flex專案會按 flex-basis: 400px 計算其寬度,Flex容器沒有足夠空間時,Flex就會斷行:


收藏!40 個 CSS 佈局技巧


反過來,如果Flex專案的值 flex 改成:

.flex__item {    flex: 1 0 400px;}

當Flex容器沒有足夠空間排列Flex專案時,Flex專案會按 flex-basis: 400px 計算其寬度,Flex會斷行,並且同一行出現剩餘空間時,Flex專案會擴充套件,佔滿整個Flex容器:

收藏!40 個 CSS 佈局技巧

在Grid中實現類似的效果要更復雜一點。可以使用 repeat() 函式,1fr 以及 auto-fit 等特性:

.grid__container {    display: grid;    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));    gap: 2vh;}

效果如下:

收藏!40 個 CSS 佈局技巧

如果你對這方面知識感興趣的話,還可以移步閱讀《Container Query Solutions with CSS Grid and Flexbox》一文。

其實在Grid中與 auto-fit 對比的值還有一個叫 auto-fill。但兩者的差異是非常地大,用下圖來描述 auto-fit 和 auto-fill 的差異:

收藏!40 個 CSS 佈局技巧


另外這種方式也是到目前為止一種不需要藉助CSS媒體查詢就可以實現響應式佈局效果。


五  聖盃佈局


聖盃佈局(Holy Grail Layout))是Web中典型的佈局模式。看上去像下圖這樣:


收藏!40 個 CSS 佈局技巧

對於聖盃佈局而言,HTML結構是有一定的要求,那就是內容為先:

<!-- HTML --><header></header><main>    <article></article> <!-- 主內容 -->    <nav></nav>    <aside></aside></main><footer></footer>


在這裡主要還是和大家一起探討,如何使用Flexbox和Grid佈局模組來實現聖盃佈局。先來看Flexbox實現方案:

body {    width: 100vw;    display: flex;    flex-direction: column;}main {    flex: 1;    min-height: 0;    display: flex;    align-items: stretch;    width: 100%;}footer {    margin-top: auto;}nav {    width: 220px;    order: -1;}article {    flex: 1;}aside {    width: 220px;}

效果如下:

收藏!40 個 CSS 佈局技巧

透過在 nav、aside 和 article 上顯式設定 order 的值,可以很好的控制這三個區域的佈局順序。比如說,希望 <aside> 在 <article> 之前排列,只需要在上面的示例基礎上做一點點調整:

nav {    order: 0;}aside {    order: -1;}

效果如下:

收藏!40 個 CSS 佈局技巧

注意,order的預設值為0,值越大越排在後面!


在上例的基礎上,藉助CSS媒體物件的特性,可以很容易實現響應式的聖盃佈局效果:

@media screen and (max-width: 800px) {    main {        flex-direction: column;    }    nav, aside {        width: 100%;    }}

效果如下:

收藏!40 個 CSS 佈局技巧

嘗試著拖動瀏覽器來改變視窗大小,你可以看到如下圖的效果:

收藏!40 個 CSS 佈局技巧

在Grid佈局模組中,實現聖盃佈局要比Flexbox佈局模組中更容易,而且更靈活。在CSS Grid佈局模組中,HTML結構可以更簡潔:

<!-- HTML --><body>    <header></header>    <main></main>    <nav></nav>    <aside></aside>    <footer></footer></body>


在CSS方面有很多種方案可以實現聖盃佈局效果。我們先來看第一種:

body {    display: grid;    grid-template: auto 1fr auto / 220px 1fr 220px;}header {    grid-column: 1 / 4;}main {    grid-column: 2 / 3;    grid-row: 2 / 3;}nav {    grid-column: 1 / 2;    grid-row: 2 / 3;}aside {    grid-column: 3 / 4;    grid-row: 2 / 3;}footer {    grid-column: 1 / 4;}


效果如下:

收藏!40 個 CSS 佈局技巧

上面示例採用的是網格線來給每個區域進行定位的:

收藏!40 個 CSS 佈局技巧

和Flexbox佈局類似,在媒體查詢中可以改變每個網格區域的位置:

@media screen and (max-width: 800px) {    body {        grid-template-rows: auto;        grid-template-columns: auto;    }    header,    main,    nav,    aside,    footer {        grid-column: 1 / 2;        min-height: auto;    }    main {        grid-row: 3 / 4;        margin: 0;    }    nav {        grid-row: 2 / 3;    }    aside {        grid-row: 4 / 5;    }    footer {        grid-row: 5 / 6;    }}

收藏!40 個 CSS 佈局技巧

除了 grid-template(即 grid-template-columns 和 grid-template-rows)之外,在Grid佈局中還可以使用 grid-area 和 grid-template-areas 屬性的結合,也能很方便的實現CSS聖盃佈局。基於上面的示例上,只需要把你的CSS調整為:

body {    display: grid;    grid-template-areas:        "header header header"        "nav main aside"        "footer footer footer";}header {    grid-area: header;}main {    grid-area: main;}nav {    grid-area: nav;}aside {    grid-area: aside;}footer {    grid-area: footer;}@media screen and (max-width: 800px) {    body {        grid-template-areas:            "header"            "nav"            "main"            "aside"            "footer";    }}

效果如下:

收藏!40 個 CSS 佈局技巧

你可能發現了它們之間的差異性:

收藏!40 個 CSS 佈局技巧

後面這個示例中,<nav>、<main> 和 <aside> 區域寬度相等。這是因為我們示例中透過 grid-template-areas 來宣告網格,在使用 grid-template-areas 建立網格時,其實也隱式的建立了網格線,只不過他和 grid-template 不同的是 grid-template 可以顯式的指定網格軌道大小,而grid-template-areas 在該示例中相當於網格軌道大小都是 1fr。

收藏!40 個 CSS 佈局技巧

如果我們希望 <main> 的區域變得更大,那麼可以在 grid-template-areas 上做個調整:

body {    display: grid;    grid-template-areas:        "header header header header header"        "nav main main main aside"        "footer footer footer footer footer";}

效果如下:

收藏!40 個 CSS 佈局技巧

這個時候網格區域的劃分像下圖這樣:

收藏!40 個 CSS 佈局技巧

雖然在效果有所調整了,但還是均分狀態。更好的解決方案是,將 grid-template-areas 和 grid-template 結合起來使用:

body {    display: grid;    grid-template-areas:        "header header header"        "nav main aside"        "footer footer footer";    grid-template-columns: 220px 1fr 220px;    grid-template-rows: auto 1fr auto;}header {    grid-area: header;}main {    grid-area: main;}nav {    grid-area: nav;}aside {    grid-area: aside;}footer {    grid-area: footer;}@media screen and (max-width: 800px) {    body {        grid-template-areas:            "header"            "nav"            "main"            "aside"            "footer";        grid-template-columns: 1fr;        grid-template-rows: auto auto 1fr auto auto;    }    main {        margin-left: 0;        margin-right: 0;    }}

效果如下:

收藏!40 個 CSS 佈局技巧

你可以發現,這個時候,網格線的區域的命名像下圖這樣:

收藏!40 個 CSS 佈局技巧

六  12列網格佈局

12列網格佈局最早是由960.gs提出的網格佈局系統:

收藏!40 個 CSS 佈局技巧

12列網格佈局在設計系統和CSS Framework中經常使用,比如業內經典的Bootstrap就採用了12列網格佈局系統:

收藏!40 個 CSS 佈局技巧

在社群中也有很多線上工具,幫助我們快速構建12列網格系統,比如 Free CSS Grid Tools & Resources For Developers 一文中羅列的工具。

收藏!40 個 CSS 佈局技巧

不過這裡主要是想和大家一起看看在Flexbox和Grid佈局模組中是如何實現12列的網格佈局系統。

先來看Flexbox佈局模組。12列網格佈局的HTMl結構一般類似於下面這樣:

<!-- HTML --><flex__grid>    <flex__row>        <flex__item col4></flex__item col4>        <flex__item col4></flex__item col4>        <flex__item col4></flex__item col4>    </flex__row></flex__grid>

注意,12列網格中,一般同一行的列數值和剛好等於12。比如上面的HTML結構,行中有三列,每列的寬度剛好四個網格寬度加兩個列間距。並且在計算的時候有一套成熟的計算公式:

收藏!40 個 CSS 佈局技巧

而且還設計上也會有所差異,比如說距離容器兩側有沒有間距等:

收藏!40 個 CSS 佈局技巧


這些的差異對於計算公式和樣式程式碼的設計都略有差異。我們用其中一個為例:

:root {    --gutter: 10px;    --columns: 12;    --span: 1;}.flex__container {    display: flex;    flex-direction: column;    padding-left: var(--gutter);    padding-right: var(--gutter);}.flex__row {    display: flex;    margin-left: calc(var(--gutter) * -1);    margin-right: calc(var(--gutter) * -1);}.flex__row + .flex__row {    margin-top: 2vh;}.flex__item {    flex: 1 1        calc((100% / var(--columns) - var(--gutter)) * var(--span));    margin: 0 var(--gutter);}.flex__item1 {    --span: 1;}.flex__item2 {    --span: 2;}.flex__item3 {    --span: 3;}.flex__item4 {    --span: 4;}.flex__item5 {    --span: 5;}.flex__item6 {    --span: 6;}.flex__item7 {    --span: 7;}.flex__item8 {    --span: 8;}.flex__item9 {    --span: 9;}.flex__item10 {    --span: 10;}.flex__item11 {    --span: 11;}.flex__item12 {    --span: 12;}

你會看到的效果如下:

收藏!40 個 CSS 佈局技巧

在該示例中採用了CSS自定義屬性相關的特性,讓整個計算變得更容易一些。

對於使用CSS Grid佈局模組來實現12列網格佈局,相對而言,不管是HTML結構還是CSS程式碼都會更簡易一些。在使用CSS Grid佈局模組實現12列網格佈局,將會運用到repeat()、minmax()、gap 和 fr 等特性。具體的來看一個示例吧。

<!-- HTML --><grid__container>    <grid__item></grid__item></grid__container>

我們來看CSS程式碼:

  • 使用 fr 將網格均分為相等的值,即每列寬度都是 1 個 fr;配合 repeat() 函式,即repeat(12, 1fr) 建立了12列網格。
  • 使用 gap 可以用來控制網格之間的間距。
  • 配合 minmax() 還可以設定網格最小值。

具體的程式碼如下:

:root {    --columns: 12;    --gap: 10px;    --span: 1;}.grid__container {    display: grid;    grid-template-columns: repeat(var(--columns), 1fr);    grid-template-rows: 1fr;    gap: var(--gap);    padding-left: calc(var(--gap) / 2);    padding-right: calc(var(--gap) / 2);}.grid__item {    min-block-size: 10vh;    grid-column: span var(--span);}.col1 {    --span: 1;}.col2 {    --span: 2;}.col3 {    --span: 3;}.col4 {    --span: 4;}.col5 {    --span: 5;}.col6 {    --span: 6;}.col7 {    --span: 7;}.col8 {    --span: 8;}.col9 {    --span: 9;}.col10 {    --span: 10;}.col11 {    --span: 11;}.col12 {    --span: 12;}

你將看到的效果如下:

收藏!40 個 CSS 佈局技巧

就該示例而言,grid-template-columns: repeat(12, 1fr) 建立網格如下圖所示:

收藏!40 個 CSS 佈局技巧

除了上述這種粗暴的方式,還可以更靈活一些,將 auto-fit、minmax() 以及 grid-auto-flow: dense 等來建立:

.grid__container {    padding: 1em;    display: grid;    grid-template-columns: repeat(auto-fit, minmax(60px, 1fr));    gap: 1em;    grid-auto-flow: dense;}

對於 .grid__item 可以透過 grid-column、grid-row 來控制網格專案的位置:

收藏!40 個 CSS 佈局技巧

加上 grid-auto-flow: dense 會根據Grid容器空間,Grid專案會自動流到合適的位置:

收藏!40 個 CSS 佈局技巧

這種佈局對於雜誌類的佈局非常的適用。有關於這方面更詳細的介紹可以閱讀@Keir Watson的《Responsive Grid Magazine Layout in Just 20 Lines of CSS》一文。

七  兩端對齊

在Web佈局中時常碰到兩端對齊的需求。在Flexbox佈局中,時常在Flex容器中顯式設定 justify-content 的值:

.flex__container {    display: flex;    flex-wrap: wrap;    justify-content: space-between;    width: 100%;}

但在末尾行,如果和前面行的個數不相同(Flex專案)就會出現下圖這樣的效果:

收藏!40 個 CSS 佈局技巧

像上圖這樣的效果,並不是我們所需要的,因為我們希望在最後一行的Flex專案不足夠排列滿一行時,希望Flex專案一個緊挨一個的排列:

收藏!40 個 CSS 佈局技巧

在Flexbox要實現上圖這樣的效果,只需要在Flex容器中新增一個偽元素:

.flex__container::after {    content: "";    display: flex;    flex: 0 1 32vw;}

注意,偽元素的 flex-basis 建議設定的和卡片的 flex-basis(或寬度)等同。這個時候你將看到像下面這樣的示例:

收藏!40 個 CSS 佈局技巧

不過這種方式也不是最佳的方式,當末尾行的個數不只少一個時,就會出現下圖這樣的效果:

收藏!40 個 CSS 佈局技巧

面對這樣的場景,我們需要給Flex容器新增額外的空標籤元素:

佔位符元素數量 = 每行最大的列數 - 2

但是 gap屬性出現之後,要實現這樣的效果就不難了:

body {    padding: 1vh;}.flex__container {    display: flex;    flex-wrap: wrap;    gap: 2vh;    width: 100%;}.flex__item {    flex: 0 1 calc((100vw - 8vh) / 4);}

效果如下:


收藏!40 個 CSS 佈局技巧

注意,gap 運用在Flexbox中到目前為止,僅得到了Firefox瀏覽器的支援。上面的示例,使用Firefox瀏覽器,你看到的效果如下:

收藏!40 個 CSS 佈局技巧

在CSS Grid佈局中,就可以直接使用 gap:

body {    padding: 1vh;}.grid__container {    display: grid;    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));    gap: 1vh;}

效果如下:

收藏!40 個 CSS 佈局技巧

八  選擇最佳的值

很多時候,針對不同的場景,設計師會為我們提供不同的設計風格,比如元素大小:

收藏!40 個 CSS 佈局技巧

隨著 clam() 函式的到來,這一切都變得容易地多。

clam() 函式接受三個引數,即 clam(MIN, VAL, MAX),其中 MIN 表示最小值,VAL 表示首選值,MAX 表示最大值。它們之間:

  • 如果 VAL 在 MIN 和 MAX 之間,則使用 VAL 作為函式的返回值。
  • 如果 VAL 大於 MAX,則使用 MAX 作為函式的返回值。
  • 如果 VAL 小於 MIN,則使用 MIN 作為函式的返回值。


我們來看一個示例:

.element {    /**    * MIN = 100px    * VAL = 50vw ➜ 根據視窗的寬度計算    * MAX = 500px    **/    width: clamp(100px, 50vw, 500px);}

比如瀏覽器視窗現在所處的位置是1200px的寬度,那麼 .element 渲染的結果如下:

收藏!40 個 CSS 佈局技巧

這個時候 .element 元素的 width 是 500px。此時,clamp(100px, 50vw, 500px) 相當於clamp(100px, 600px, 500px),對應的 VAL 值是 600px,大於 MAX 值,那麼這個時候clamp() 函式返回的值是 MAX,即 500px,這個時候 .element 的 width 值就是 500px(即MAX 的值)。

如果我們把瀏覽器視窗縮小至 760px:

收藏!40 個 CSS 佈局技巧

這個時候 .element 元素的 width 是 50vw。此時,clamp(100px, 50vw, 500px) 相當於clamp(100px, 380px, 500px),對應的 VAL 值是 380px,該值大於 MIN 值(100px),小於MAX 值(500px),那麼這個時候 clamp() 函式返回的值是 VAL,即 50vw,這個時候.element 的 width 值就是 50vw(即 VAL 的值)。

如果繼續將瀏覽器的視窗縮小至 170px:

收藏!40 個 CSS 佈局技巧

這個時候 .element 元素的 width 是 100px。此時,clamp(100px, 50vw, 500px) 相當於clamp(100px, 85px, 500px),對應的 VAL 值是 85px,該值小於 MIN 值(100px),那麼這個時候 clamp() 函式返回的值是 MIN,即 100px,這個時候 .element 的 width 值就是100px(即 MIN 的值)。

就該示例而言,clamp(100px, 50vw, 500px) 還可以這樣來理解:

  • 元素 .element 的寬度不會小於 100px(有點類似於元素設定了 min-width: 100px)。
  • 元素 .element 的寬度不會大於 500px(有點類似於元素設定了 max-width: 500px)。
  • 首選值 VAL 為 50vw,只有當視窗的寬度大於 200px 且小於 1000px 時才會有效,即元素.element 的寬度為 50vw(有點類似於元素設定了 width:50vw)。

九  Logo圖示的對齊

我想你在Web開發中可能碰到過類似下圖的這樣的場景:

收藏!40 個 CSS 佈局技巧

正像上圖所示,Logo影像的有大有小(寬度和高度都不一樣)。面對這樣的業務場景,很多時候都希望設計師能提供相同尺寸的影像。但這樣勢必會影響Logo影像的外觀。

前段時間看到@Ahmad Shadeed專門寫了一篇博文《Aligning Logo Images in CSS》,就是介紹如何實現上圖這樣的佈局效果。

其實實現這樣的佈局效果,主要運用到的就是CSS的 object-fit 屬性,而這個屬性早在多年前就得到了各大主流瀏覽器的支援。

這裡我們用一個簡單的示例,來看看具體實現過程。先來看HTML結構:

<!-- HTML --><ul class="brands">    <li class="brands__item">        <a href="#">            <img src="img/logo.png" alt="">        </a>    </li>    <li> <!-- ... --> </li></ul>

居中對齊前面已經介紹過了,這裡主要是看影像大小方面的處理:

.brands {    display: grid;    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));    grid-gap: 1rem;}.brands__item {    background: #eee;}.brands__item a {    display: flex;    justify-content: center;    align-items: center;    height: 100%;}.brands__item img {    width: 130px;    height: 75px;    object-fit: contain;}

這樣就能實現上圖的效果。你可能發現了,有些Logo影像帶有背景顏色,如果讓效果更好一些,可以把CSS混合模式相關的特性運用進來:

.brands__item img {    width: 130px;    height: 75px;    object-fit: contain;    mix-blend-mode: multiply;}

這個時候,你看到的效果如下:

收藏!40 個 CSS 佈局技巧

object-fit 除了取值 contain 之外,還有其他幾個值:

收藏!40 個 CSS 佈局技巧

其實這個方案也適用於產品圖片,人物頭像等佈局。

小結

文章中主要介紹了Web中一些佈局的實現思路和具體方案。其實文章提到的效果,比如水平垂直居中、等高佈局、平均分佈列和Sticky Footer等,在CSS中一直有多種解決方案,只不過隨著CSS Flexbox佈局模組和CSS Grid佈局模組的到來,實現這些效果變得更為靈活和簡潔。

當然,文章中提到的只是一些最為常見的一些效果,其實在Web佈局中,特別是Flexbox佈局和Grid佈局中還存在著很多有意思的東西,只不過因為篇幅的原因沒有一一羅列。如果你感興趣可以再挖掘一些出來,如果你在這方面有更好的經驗或方案,歡迎在下面的評論中分享。最後希望這篇文章對你平時的工作有所幫助。