收藏!40 個 CSS 佈局技巧

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

image.png

一 水平垂直居中

如何實現水平垂直居中能夠說是CSS面試題中的經典面試題,在多年前這個面試題給不少同窗都帶來了困惑,但Flexbxo佈局模塊和CSS Grid佈局模塊的到來,能夠說實現水平垂直居中已經是很是的容易。面試

Flexbox中實現水平垂直居中

在Flexbox佈局模塊中,不論是單行仍是多行,要讓它們在容器中水平垂直居中都是件易事,並且方法也有多種。最多見的是在Flex容器上設置對齊方式,在Flex項目上設置 margin:auto。segmentfault

先來看在Flex容器上設置對齊方式。瀏覽器

Flex容器和Flex項目上設置對齊方式ide

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

<!-- HTML -->
<div class="flex__container">
    <div class="flex__item"></div>
</div>

/* CSS */
.flex__container {
    display: flex;
    justify-content: center;
    align-items: center;
}

效果以下:函數

image.png

這種方式特別適應於讓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;
}

效果以下:佈局

image.png

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

<!-- 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;
}

效果以下:

image.png

在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;
}

效果以下:

image.png

若是在Flex容器中有多個Flex項目時,該方法一樣有效:

.flex__container {
    display: flex; // 或inline-flex
    justify-content: center;
}

.flex__container > * {
    align-self: center;
}

好比下面這個效果:

image.png

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

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

.flex__item {
    align-self: center;
}

效果以下:

image.png

或者換:

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

效果以下:

image.png

這兩種方式一樣適用於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;
}

效果以下:

image.png

可能不少同窗對於 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;
}

效果以下:

image.png

整個過程,你能夠經過下面這個示例來體驗。嘗試着選中不一樣方向的 margin 值:

image.png

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
}

效果以下:
image.png

在CSS Grid佈局模塊中,只要顯式設置了 display: grid(或 inline-grid)就會建立Grid容器和Grid項目,也會自動生成網格線,即行和列(默認爲一行一列)。

image.png

在沒有顯式地在Grid容器上設置 grid-template-columns 和 grid-template-rows,瀏覽器會將Grid容器默認設置爲Grid內容大小:

image.png

這種方法也適用於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>

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

image.png

並且 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;
}

效果以下:

image.png

二 等高佈局

等高佈局也是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。

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

image.png

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

image.png

在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; /* 根據需求調整值*/
}

效果以下:
image.png

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

image.png

若是需求有所調整,好比在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%;
}

效果以下:

image.png

三 Sticky Footer

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

image.png

Sticky Footer實現方案和等高、垂直居中同樣,一樣有不少種方案能夠實現。

好比像下面這樣的結構:

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

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

body {
    display: flex;
    flex-direction: column;
}

footer {
    margin-top: auto;
}

image.png

能夠嘗試着在 main 區域右下角向下拖動,改變主內容區域的高度,你會發現「當內容不足一屏時, 會在頁面的最底部,當內容超出一屏時, 會自動日後延後」。

在Flexbox佈局中,還能夠在 區域上設置下面的樣式,達到相等的效果:

body {
    display: flex;
    flex-direction: column;
}

main {
    flex: 1 0 auto;
}

效果以下:

image.png

中的 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 讓 區域根據Grid容器剩餘空間來作計算。

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

效果以下:
image.png

四 均分列

在Web佈局中,不少時候會對列作均分佈局,最爲常見的就是在移動端的底部Bar,好比下圖這樣的一個效果:

image.png

在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);
}

效果以下:

image.png

經過瀏覽器調試器中能夠發現,現個列的寬度都是相等的:

image.png

在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;
}

效果以下:

image.png

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

image.png

接下來看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表示具體的列數*/
}

最終的效果是相同的:

image.png

這樣的佈局方式也適用於其餘的佈局中。但不論是Flexbox仍是Grid佈局中,都存在必定的缺陷,當容器沒有足夠的空間容納Flex項目(或Grid項目)時,Flex項目或Grid項目會溢出(或隱藏,若是Flex容器或Grid容器顯式設置了 overflow:hidden):

image.png

修復這種現象最簡單的方式是在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的基準值 */
}

image.png

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

image.png

基於該例,若是把Flex項目的 flex 值改爲:

.flex__item {
    flex: 0 0 400px;
}

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

image.png

反過來,若是Flex項目的值 flex 改爲:

.flex__item {
    flex: 1 0 400px;
}

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

image.png

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

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

效果以下:

image.png

若是你對這方面知識感興趣的話,還能夠移步閱讀《Container Query Solutions with CSS Grid and Flexbox》一文。

其實在Grid中與 auto-fit 對比的值還有一個叫 auto-fill。但二者的差別是很是地大,用下圖來描述 auto-fit 和 auto-fill 的差別:
image.png

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

五 聖盃佈局

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

image.png

對於聖盃佈局而言,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;
}

效果以下:

image.png

經過在 nav、aside 和 article 上顯式設置 order 的值,能夠很好的控制這三個區域的佈局順序。好比說,但願 在 以前排列,只須要在上面的示例基礎上作一點點調整:

nav {
    order: 0;
}

aside {
    order: -1;
}

效果以下:

image.png

注意,order的默認值爲0,值越大越排在後面!

在上例的基礎上,藉助CSS媒體對象的特性,能夠很容易實現響應式的聖盃佈局效果:

@media screen and (max-width: 800px) {
    main {
        flex-direction: column;
    }

    nav, aside {
        width: 100%;
    }
}

效果以下:

image.png

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

image.png

在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;
}

效果以下:

image.png

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

image.png

和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;
    }
}

image.png

除了 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";
    }
}

效果以下:

image.png

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

image.png

後面這個示例中,、 和 區域寬度相等。這是由於咱們示例中經過 grid-template-areas 來聲明網格,在使用 grid-template-areas 建立網格時,其實也隱式的建立了網格線,只不過他和 grid-template 不一樣的是 grid-template 能夠顯式的指定網格軌道大小,而 grid-template-areas 在該示例中至關於網格軌道大小都是 1fr。

image.png

若是咱們但願 的區域變得更大,那麼能夠在 grid-template-areas 上作個調整:

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

效果以下:

image.png

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

image.png

雖然在效果有所調整了,但仍是均分狀態。更好的解決方案是,將 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;
    }
}

效果以下:

image.png

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

image.png

六 12列網格佈局

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

image.png

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

image.png

在社區中也有不少在線工具,幫助咱們快速構建12列網格系統,好比 Free CSS Grid Tools & Resources For Developers 一文中羅列的工具。
image.png

不過這裏主要是想和你們一塊兒看看在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結構,行中有三列,每列的寬度恰好四個網格寬度加兩個列間距。而且在計算的時候有一套成熟的計算公式:

image.png

並且還設計上也會有所差別,好比說距離容器兩側有沒有間距等:

image.png

這些的差別對於計算公式和樣式代碼的設計都略有差別。咱們用其中一個爲例:

: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;
}

你會看到的效果以下:

image.png

在該示例中採用了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;
}

你將看到的效果以下:

image.png

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

image.png

除了上述這種粗暴的方式,還能夠更靈活一些,將 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 來控制網格項目的位置:

image.png

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

image.png

這種佈局對於雜誌類的佈局很是的適用。有關於這方面更詳細的介紹能夠閱讀@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項目)就會出現下圖這樣的效果:

image.png

像上圖這樣的效果,並非咱們所須要的,由於咱們但願在最後一行的Flex項目不足夠排列滿一行時,但願Flex項目一個緊挨一個的排列:

image.png

在Flexbox要實現上圖這樣的效果,只須要在Flex容器中添加一個僞元素:

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

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

image.png

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

image.png

面對這樣的場景,咱們須要給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);
}

效果以下:

image.png

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

image.png

在CSS Grid佈局中,就能夠直接使用 gap:

body {
    padding: 1vh;
}

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

效果以下:

image.png

八 選擇最佳的值

不少時候,針對不一樣的場景,設計師會爲咱們提供不一樣的設計風格,好比元素大小:
image.png

隨着 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 渲染的結果以下:

image.png

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

若是咱們把瀏覽器視窗縮小至 760px:

image.png

這個時候 .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:

image.png

這個時候 .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開發中可能碰到過相似下圖的這樣的場景:

image.png

正像上圖所示,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;
}

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

image.png

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

image.png

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

小結

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

固然,文章中提到的只是一些最爲常見的一些效果,其實在Web佈局中,特別是Flexbox佈局和Grid佈局中還存在着不少有意思的東西,只不過由於篇幅的緣由沒有一一羅列。若是你感興趣能夠再挖掘一些出來,若是你在這方面有更好的經驗或方案,歡迎在下面的評論中分享。最後但願這篇文章對你平時的工做有所幫助。

相關文章
相關標籤/搜索