iT邦幫忙

2024 iThome 鐵人賽

DAY 20
0

在前一篇文章中,我們討論了如何動態生成 Card 元件 並構建了基礎的 Service Section。今天,我們將繼續優化這個部分,重點放在如何使用 CSS Grid Layout 實現彈性且響應式的卡片佈局。CSS Grid 不僅讓我們能輕鬆處理不同螢幕尺寸下的佈局變化,還能夠與 Flexbox 互補,在每個 Card 元件內部提供精細的對齊與排列控制。

我們將展示如何使用 CSS Grid 管理整體卡片佈局,並通過 Flexbox 來簡化卡片內部內容的排列。本文會深入探討這些技術的具體應用,並解答開發中常見的佈局問題,例如 Grid 元素不對齊、如何針對不同瀏覽器進行佈局優化等。

為什麼選擇 CSS Grid?

在前端開發中,FlexboxGrid Layout 是常見的佈局工具。Flexbox 更適合處理一維佈局(水平或垂直方向上的排列),而 CSS Grid 則更加靈活,能夠處理二維佈局(行和列同時控制),特別適合像 Card 元件 這樣需要根據螢幕大小調整排列方式的設計。

Flexbox vs. CSS Grid 比較

特點 Grid Layout Flexbox
適用場景 二維佈局(同時控制行和列) 一維佈局(控制行或列的排列)
設計方式 元素在網格中按照行和列排列 元素按行或列方向排列
靈活性 更加靈活,適合處理複雜佈局 適合簡單的線性佈局
佈局控制 同時控制行和列,適合響應式卡片佈局 適合單方向的內容排列,比如導航或按鈕布局

在我們的佈局設計中,Grid Layout 主要負責整個 Service Section 的卡片排列,而每個 Card 元件 的內部佈局則使用 Flexbox,這樣可以更有效地控制卡片內部內容的垂直與水平對齊。

Flexbox 與 Grid 結合使用

在實際項目中,很多時候我們會同時使用 Grid LayoutFlexbox,因為它們各有不同的特點和適用場景。在這裡,我們使用 CSS Grid 來管理整個頁面中的卡片佈局,讓卡片根據螢幕尺寸動態調整列數,而在卡片內部,我們則使用 Flexbox 來簡化卡片內部的內容排列。

  • Grid Layout:適合用於二維佈局,比如我們的卡片網格展示。它能根據不同螢幕大小調整列數,讓卡片能夠自動適應各種裝置。
  • Flexbox:適合用於一維佈局,比如卡片內部的元素(圖標、標題、描述)垂直排列。

這樣的結合能夠讓我們在同一頁面中,既能靈活地調整整體卡片佈局,又能精細地控制卡片內部的對齊方式。

實際演練

Step 1: 在 ServiceSection 中使用 Grid Layout

首先,我們設置 Grid Layout 來處理 ServiceSection 中卡片的排列,根據不同的螢幕尺寸靈活調整列數和間距。

// src/pages/Portfolio/ServiceSection.module.scss
@import '@/styles/variables';

// 其他樣式... 
// 手機佈局:單列
.services {
    display: grid;
    grid-template-columns: repeat(1, minmax(180px, 1fr));  // 單列
    grid-auto-rows: 1fr;
    gap: 50px;  // 卡片之間的間距
}

// 平板佈局:多列
@media (min-width: $breakpoint-mobile) and (max-width: $breakpoint-tablet - 1px) {
    .services {
        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));  // 自動調整列數
        gap: 50px;
    }
}

// 桌機佈局:三列
@media (min-width: $breakpoint-tablet) {
    .services {
        grid-template-columns: repeat(3, minmax(200px, 1fr));  // 三列佈局
        gap: 50px;
    }
}

為什麼 Grid 元素不對齊?

  • 原因:不同卡片內的內容高度不一致,導致 Grid Layout 中的元素在垂直方向上無法對齊。這可能是因為卡片內部的標題、描述和底部細節各自佔用的空間不同。
  • 解決方案:使用 grid-auto-rows 為每個網格單元格設置統一的行高,這樣無論內容多少,Grid 的每個項目都會保持相同的高度。

Step 2: 使用 Flexbox 處理 Card 元件內部佈局

我們將使用 Flexbox 來控制卡片內部的圖標、標題、描述等內容的排列方式,確保它們能夠在垂直方向上自適應並居中對齊,保持卡片整體佈局的穩定性。

具體目標:

  • 圖標應該置頂並水平居中顯示。
  • 標題和描述應保持垂直排列,並在不同裝置上具有一致的間距。
  • 底部內容(例如分類和技術細節)應該靠近卡片底部,確保整體高度一致。

Step 2.1: 設置 Flexbox 的基本結構

首先,為每個卡片的外層元素設置基本的 Flexbox 結構,保證卡片內的內容可以垂直排列,並根據卡片內部的內容高度自適應。

scss
複製程式碼
// 卡片外層樣式:使用 Flexbox 進行排列,適應 Mobile First
.card {
    display: flex;
    flex-direction: column; // 垂直排列卡片內容
    justify-content: center; // 垂直居中
    background-color: var(--grey-light);
    padding: 1rem;
    box-sizing: border-box;
    position: relative;
    z-index: 1;
    min-height: 500px; // 卡片最小高度
}

.cardContent {
    display: flex;
    flex-direction: column;
    justify-content: space-between; // 在頂部和底部之間平衡分佈內容
    align-items: center; // 水平居中
    height: 100%; // 確保卡片內容佔滿卡片高度
    width: 100%;
}

這段代碼使用 Flexbox 將卡片內部的元素進行垂直排列,確保卡片內容在手機和小螢幕裝置上垂直顯示且自適應高度。

Step 2.2: 使用 flex-grow 將卡片內容按比例分佈

接下來,我們使用 Flexboxflex-grow 屬性,為卡片的各個區塊(cardTitlecardDescriptioncardFooter)分配不同的高度比例,確保它們在垂直方向上按比例佔用空間。

scss
複製程式碼
// 卡片標題、描述與底部的布局
.cardTitle {
    flex-grow: 2; // 標題區佔據2份高度
    font-size: var(--subtitle);
    margin-bottom: 0.5rem;
}

.cardDescription {
    flex-grow: 3; // 描述區佔據3份高度
    font-size: var(--body1);
    color: var(--text-primary);
    margin-bottom: 1rem;
}

.cardFooter {
    margin-top: 1.5rem;
    flex-grow: 1; // 底部區佔據1份高度,確保底部對齊
    min-height: 156px; // 保持卡片底部高度一致

    .cardCategory {
        font-weight: bold;
        font-size: var(--subtitle);
    }

    .cardDetails {
        font-size: var(--body1);
        color: var(--text-primary);
    }
}

這樣,我們可以確保卡片內的標題、描述和底部內容都能按比例自動調整,並且卡片的整體高度在各個區塊之間保持一致。

卡片之間的排版為什麼會不一致, 如下圖?

  • 原因:卡片內部區塊( cardTitlecardDescriptioncardFooter)的高度不一致,且缺少合理的空間分配,導致卡片在垂直方向上無法統一對齊。
  • 解決方案
    • 統一卡片內部高度:為每個區塊(cardTitlecardDescriptioncardFooter)設置不同的 flex-grow 值,確保它們按比例自動填充垂直空間。這樣可以使卡片內部的各區塊按預期的比例分配空間,避免卡片之間的高度不一致。
    • 固定底部對齊:通過設置 min-height: 156px 來確保 cardFooter 的高度一致,同時使用 justify-content: space-between 來平衡卡片內的元素,使卡片內部各部分保持一致的間距,從而實現卡片之間的整齊對齊。

https://ithelp.ithome.com.tw/upload/images/20240920/20168330xw62S10MB5.png

Step 3: 優化 StatsSection 的響應式間距

在不同的螢幕尺寸下,元素之間的間距有時會顯得不協調,特別是在行動裝置上,顯示內容可能過於擁擠或過於稀疏。我們可以利用 Flexbox 的靈活性,並通過媒體查詢(media queries)調整不同設備下的佈局。具體來說,我們會使用 Flexbox 的 gap 屬性來控制元素之間的間距,並根據不同的螢幕尺寸進行響應式調整。這樣可以確保在大螢幕和小螢幕上的間距都能保持協調一致。

以下是針對 Stats Section 的具體修改方案:

@import '@/styles/variables';

.statsContainer {
    display: flex;
    flex-direction: column;
    align-items: center;
    flex: 1;
    gap: 10vh;
}

@media (min-width: $breakpoint-tablet) {
    .statsContainer {
        flex-direction: row;
        justify-content: space-around;
        gap: 50px;
        margin-top: 60px;
    }
}

說明:

  • 小螢幕佈局:在手機或小尺寸裝置上,我們使用垂直佈局來確保元素之間有足夠的間距,同時讓內容在視覺上保持平衡。
  • 大螢幕佈局:當裝置的螢幕尺寸較大時,切換為水平佈局,並適當增加間距(gap: 50px),以確保畫面不會顯得太擁擠。

結語

在這篇文章中,我們成功地結合了 CSS GridFlexbox,構建了一個響應式的卡片佈局。Grid Layout 負責整體的卡片排列,而 Flexbox 則負責卡片內部的內容排列,這種結合使用提供了靈活且高效的佈局方式。

以下是最終在桌機、平板和手機上的顯示效果:
https://ithelp.ithome.com.tw/upload/images/20240920/20168330RrE78ghicJ.png

下一篇文章中,我們將深入探討 單頁應用的滾動與導航。當用戶點擊導航菜單中的不同項目時,如何平滑滾動到對應區塊,以及如何自動更新菜單狀態,這些功能將提升整體的互動性與使用體驗。如果你對這些技術感興趣,請繼續關注我們的後續文章!


流光館Luma<∕> ✨ 期待與你繼續探索更多技術知識!



上一篇
Day19: 動態生成 Card 元件,建構 Service 頁面
下一篇
Day 21 : 用 React 實現單頁應用的平滑滾動導航
系列文
從PM到前端開發:我的React作品集之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言