跳至主要内容

Flexbox Row + OverflowX issue

· 閱讀時間約 1 分鐘
Imagine Chiu
Front End Engineer @ Bearests

在用 Flexbox 排版時,有時候會遇到類似的問題,內容物 當 overflow 時無法撐開, 導致背景無法顯示完整區塊

Flex(Row) + Overflow-x issue

向右捲動檢查 overflow-x問題,背景顏色不是全寬

CurrentRank
11~20
x1.60%
x1.70%
x1.80%
x1.90%
x2.00%
x2.00%
x2.00%
x2.00%
x2.00%
Next Level
Friends Rolling
Rebate
Number Withdrawal
Friends Rolling
Friends Rolling
Friends Rolling
Friends Rolling
Friends Rolling
Friends Rolling
Next Rank
21~30
x1.60%
x1.70%
x1.80%
x1.90%
x2.00%
x2.00%
x2.00%
x2.00%
x2.00%
<section className="d-flex flex-column overflow-X">
<div>curr level</div>
<div>title</div>
<div>next level</div>
</section>

修正後的版本

向右捲動檢查,背景顏色全寬,主要將 flex column 跟 overflow-x 隔開

CurrentRank
11~20
x1.60%
x1.70%
x1.80%
x1.90%
x2.00%
x2.00%
x2.00%
x2.00%
x2.00%
Next Level
Friends Rolling
Rebate
Number Withdrawal
Friends Rolling
Friends Rolling
Friends Rolling
Friends Rolling
Friends Rolling
Friends Rolling
Next Rank
21~30
x1.60%
x1.70%
x1.80%
x1.90%
x2.00%
x2.00%
x2.00%
x2.00%
x2.00%
<section className="d-flex overflow-X">
<div className="flex-column">
<div>curr level</div>
<div>title</div>
<div>next level</div>
</div>

</section>

GridThemeProvider 覆寫樣式問題

· 閱讀時間約 2 分鐘
Imagine Chiu
Front End Engineer @ Bearests

v5 版本使用 GridThemeProvider 覆寫樣式問題

bug-sample.png

下面為示意程式範例

const Dialog = ({type, title, message, buttons}) => {
return (
<DialogRoot>
<Title type={type}>{title}</Title>
<MessageContent dangerouslySetInnerHTML={{__html: message}} />
<GridThemeProvider gridTheme={{
gutter: '5px',
}}>
<Container fluid>
<Row>
{buttons.map(row => (
<Col key={row.id} col>
<ModalButton>{row.text}</ModalButton>
</Col>
))}
</Row>
</Container>
</GridThemeProvider>

</DialogRoot>
);
};

const App = () => {
return (
<GridThemeProvider>
<Dialog/>
</GridThemeProvider>
);
};

可以發現在為了讓 gutter 的間距設定變更,在 Modal 進行的覆寫, 但因為v5版本改為使用 styled-componentcreateGlobalStyle 設定 :root CSS變數,所以導致當光箱插入Dom時, createGlobalStyle又再次將新的設定插入到dom之中,讓原本的CSS設定覆蓋了,導致跑版。

警告

請勿在下層再次使用 GridThemeProvider 造成二次產生 :root 參數覆蓋原本參數

覆寫樣式是在 v4.x 版本中使用,v5.x版本 請善用 utils className gx-? 或是 CSS變數 --bear-gutter-x

前端切版的原則

· 閱讀時間約 4 分鐘
Imagine Chiu
Front End Engineer @ Bearests

前端設計開發,包含了設計與開發

過度依賴內容,靜態寫死佈局

  • 高度寫死
  • Padding

因為設計稿是死的,在沒規範過的設計稿的情況下,我們應該以前端規範的的情況,或是第一版的設計規範繼續往下進行, 不應該在沒規範的情況下跟著做,「響應式設計」考慮的不只是在不同尺寸中的不同顯示,而是「適應空間」, 我們不管今天設計師是以平面設計角度出發,我們都應該要以「響應式設計」為思考出發點。

一個最大的問題,「過度依賴內容」

文字修改、異動、不同語系文字長度,算得剛剛好,各尺寸一種高度設定(xs, sm, md, lg, xl, xxl)

高度內容應該要被撐開,還是 過溢字元

寫死寬高,各Padding, Margin 按照設計稿,並依照每個尺寸細緻的設定 (xs, sm, md, lg, xl, xxl 各一種設定)

識別出通用設定,設計稿不會動,不該 微距調整例 如 變成只有 xs -> md -> xxl

不考慮滿版,還是由內容撐開寬度,直接寫死寬度,按照設計稿,並依照每個尺寸細緻的設定

識別出來是滿版還是內容撐開高度+Padding

項目卡片列表,項目增加的情況,計算幾px

100px切為4等分應該為 25%,而不是25px

Margin 與 Padding

項目與項目間的間隔,是 Margin

統一使用 margin-bottom 原則頂開下面,要隔開多少

項目內的補間,為 Padding

由於在設計中偶爾會遇到 通用為 padding, 但特定元素為滿版,所以建議在每個區塊間設定 padding, 而不是一個大區塊設定 padding,而這個 Padding 為固定的CSS參數設定

可以的話,多一層也無所謂,不要只想著複寫

有時候把前端設計切為 layout 層跟 樣式層,是對後續維護閱讀調整有相當大的幫助 可以讓你的視覺中直接隔開類別

至於命名問題,命名空間

使用 Styled-component 沒有 BEM命名問題,因為他會幫你做 BEM 這個命名問題也包含明確定義 dom 結構的內容,

Container 就是 Container,Grid 就是 Grid, 元件切分可以讓我們更容易的對命名也獨立的空間

例如:

Title、Desc,在每個地方幾乎都會有,如果沒切分命名空間,就會是 ProductTitle, GoodsTitle

不管如何,一定要有網格系統、ZIndex 原則

你需要有一個負責排版的系統 boostrap grid system 或是 tailwind grid system 也好,都行。 只要不是瞎所有自定義,「一句我想跟設計稿一樣」

使用 CSS Grid 的姿勢

· 閱讀時間約 6 分鐘
Imagine Chiu
Front End Engineer @ Bearests

Grid 是一個柵欄系統,你可以把它想像成他是一個 Table,有一些像是 Table 的概念例如合併儲存格 行列、直列

與 Flexbox 相比,就是從一維變成了二維,佔比是可由內外部決定,大部分情況是由外部宣告

來看一下語法

先確認一下 CSS Grid 會長什麼樣子

.grid-wrapper{
display: grid;
grid-auto-flow: column dense;
grid-auto-columns: 1fr 1fr;
grid-auto-rows: 1fr;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
gap: 0px 0px;
}

or

.grid-wrapper{
grid-template-areas:
". head"
"nav main"
". footer";
}
.header { grid-area: 1 / 1 / 2 / 4 }
.main { grid-area: 2 / 1 / 4 / 2 }
.anv { grid-area: 2 / 3 / 5 / 4 }
.footer { grid-area: 4 / 1 / 5 / 2 }

看起來有點雜,但其實我們主要會用到 grid-template-columngap

  • grid-template-column 代表橫列放幾個,並且佔比多少
  • grid-template-row 代表直列放幾個,並且佔比多少,不過如果我們想要做到 flexbox 那樣自動超出佔比換行,設定為 1fr 即可
  • gap 內間距,下面會提到

內間距 Gap

在 Grid 中,不使用 百分比做網格,而是真的實際的佔用幾塊 (ex: 5fr),所以不會有 Gap 不被百分比計算的問題 (ex: Flexbox), 這部分對 Grid 來說是相對優勢,因為就不需要在外層使用 Row 負margin 來做抵銷 Col Padding

確認對齊

先測試一下對齊方式,深入你記憶中。

gridAutoFlow: Row

Flex Col
justify-self
Flex Col
Align Item
Align Content
Justify Item
Justify Content

gridAutoFlow: Column

Flex Col
align-self
Flex Col
Align Item
Align Content
Justify Item
Justify Content

為什麼排版是填滿的,明明我的寬度就是設定 auto?

沒錯,這就是 Flexbox 跟 Grid 的對齊特性,在 Normal 的情況下子項目會填滿,如果你不想填滿,那你需要給他對齊模式。

然後我們會發現,他一樣像 Flexbox 一樣,雖然一樣有 Column、Row, 但沒有 的主軸與交錯線不同的問題,

另外 items 跟 content 的定義也需要明確釐清 (ex: align-items、align-content)

  • items: 個別項目對齊
  • content: 內容對齊方式
  • place-content: 同時設定 align-content 和 justify-content
  • place-items: 同時設定 align-items 和 justify-items

排列方向

左到右排列,還是上到下排列,類似 flex-direction

Flexbox column 的對齊演示,就是使用這樣的方式,我希望他從上到下 超過換行,而不是從左到右 超過換行 Sample

.grid-wrapper{
grid-auto-flow: column;
}

使用元件來做

import {Grid} from '@acrool/react-grid';

<Grid col={3} className="g-4">
<div>child</div>
<div>child</div>
<div>child</div>
</Grid>

這樣代表 grid-auto-columns: repeat(3, 1fr)

Gap 為 var(--bear-gutter-4)

但如果你今天是要做商品列表,你可以指定佔比:

import {Grid, auto} from '@acrool/react-grid';

<Grid col={auto(3)} className="g-3">
<div>child 1</div>
<div>child 2</div>
<div>child 3</div>
<div>child 4</div>
<div>child 5</div>
<div>child 6</div>
</Grid>

這樣就會 3個一列,多出3個自動換行

相關參數可參照 CSS Grid Component

對齊 與 響應式

如果要對齊,你可以使用公用類樣式:

import {Grid} from '@acrool/react-grid';

<Grid col={3} className="justify-content-start align-content-start g-3"
>
<div>child 1</div>
<div>child 2</div>
<div>child 3</div>
</Grid>

公用類樣式也有提供響應式設定

合併

如果你有合併需求,你可以:

import {Grid} from '@acrool/react-grid';

<Grid col={3} className="g-3">
<div className="g-col-2">child 1</div>
<div>child 2</div>
<div className="g-col-2">child 1</div>
<div>child 2</div>
</Grid>

響應式

如果你有響應式的需求,你可以:

import {Grid, auto} from '@acrool/react-grid';

<Grid col={1} md={`200px ${auto(2)}`} className="g-3">

<div className="g-col-md-2">child 1</div>
<div>child 2</div>
<div>child 3</div>
<div>child 4</div>
</Grid>

結論

在常規的時候,我建議直接使用組合技

  • Layout
    • Container(ex: g-?) > Row(ex: g-?) > Col + Utilities CSS
    • Container(ex: g-?) > Col + Utilities CSS
    • Col + Utilities CSS
  • Card List in % (不是依卡片本身的寬度)
    • Grid + Utilities CSS(ex: g-?)

      因為 Flex not use % + gap

  • Card
    • Flex + Utilities CSS(ex: gap-?)
    • Grid + Utilities CSS(ex: g-?) (如果Flex不好處理就使用)

例如

import {auto,Flex,Grid} from '@acrool/react-grid';

<Flex className="gap-3">

等同於

<Grid col={auto(2)} className="justify-content-start">

<Flex col="column" className="g-3">

等同於

<Grid col={1}>

可以 Flex,就不一定需要 Grid,因為你可能還需要處理 對齊的問題來取消自動撐開

而對於複雜樣式的時候,例如一個甘特圖,切分各區塊的命名,那就額外宣告一個 Styled-component 去定義 grid area template 配置

這邊也推薦一個方便製作複雜 Grid 的工具 https://grid.layoutit.com/

Flexbox+Gap替代Grid System?

· 閱讀時間約 4 分鐘
Imagine Chiu
Front End Engineer @ Bearests

Flexbox 可以 Gap,直接看來說解決了 Grid System 想做的事情,就是在 Row 使用 負數 Margin 將 一排中的開頭與結尾的 Col 的 Padding 抵銷

那... 就沒問題了嗎?

我想,如果比較好的話,Bootstrap 5 應該早就改了

我們可以發現,Gap 的長度不會計算 包含在 flex item 內 (使用比例去分攤空間的話 25% * 4),也就是 Gap 會從100% 多出來導致跑版

是可以用一個算法來使用 flex-basis: 0 0 佔比,但是又能夠使用 gap。

<Container>
<Row style={{'--bear-gutter-x': '20px'} as CSSProperties}>

<Col col={12}>
<Row style={{'--bear-gutter-x': '20px'} as CSSProperties}>
<Col col={8}>Col 1-1</Col>
<Col col={8}>Col 1-2</Col>
<Col col={8}>Col 1-3</Col>
</Row>
</Col>

<Col col={12}>
<Row style={{'--bear-gutter-x': '20px'} as CSSProperties}>
<Col col={8}>Col 2-1</Col>
<Col col={8}>Col 2-2</Col>
<Col col={8}>Col 2-3</Col>
</Row>
</Col>

</Row>
</Container>
Container
Row
Col
Grid System Nest
Col 1
Col 2
Col 1-1
Col 1-2
Col 1-3
Col 2-1
Col 2-2
Col 2-3
Flex + Gap Nest
Col 1
Col 2
Col 1-1
Col 1-2
Col 1-3
Col 2-1
Col 2-2
Col 2-3
<Container>
<GapRow gap="20px">

<GapCol col={12}>
<GapRow gap="20px">
<GapCol col={8}>Col 1-1</GapCol>
<GapCol col={8}>Col 1-2</GapCol>
<GapCol col={8}>Col 1-3</GapCol>
</GapRow>
</GapCol>

<GapCol col={12}>
<GapRow gap="20px">
<GapCol col={8}>Col 2-1</GapCol>
<GapCol col={8}>Col 2-2</GapCol>
<GapCol col={8}>Col 2-3</GapCol>
</GapRow>
</GapCol>

</GapRow>
</Container>
const totalColumn = 24;

/**
* 一個Container 幾個子 Col
* @param colVal
*/

const totalColCount = (colVal: number) => {
return Math.floor(totalColumn / colVal);
}

/**
* 一個Col佔比
* @param colVal
*/
const oneColP = (colVal: number) => {
return colVal / totalColumn * 100;
}

/**
* 一個Col佔比
* @param colVal
*/
const totalGap = (colVal: number) => {
return totalColCount(colVal) - 1;
}


const GapCol = styled.div<{
col?: number
}>`
${props => css`
flex: 0 0 calc(${oneColP(props.col)}% - (var(--flex-basic-gap) * (${totalGap(props.col)}) / ${totalColCount(props.col)}));
`}
`;

const GapRow = styled.div<{
gap?: string
}>`
${props => props.gap && css`
--flex-basic-gap: ${props.gap};
`}

box-sizing: border-box;
display: flex;
flex-wrap: wrap;
gap: var(--flex-basic-gap);
`;

上面是用。Grid System,下面是用 Flex + 計算Gap。看起來是有對齊到,但好像更複雜一點?有點像是為了想 GapGap

另一個思考:Bootstrap 5 嵌套 gutter ?

需要注意的一個點,Bootstrap 5 的設計是覆寫 --bs-gutter-x 之後

這樣做有好處是,往往我們是引入很多不同的元件,這樣就不會被影響

在嵌套的下一層不會受到影響,如果需要下面也一樣的話,需要再蓋一次下層, 或是從最設定檔中設定,等於是說,gutters 其實是需要的, 因為我們會需要在不同尺寸中的網格有不同的 gutter, 並且統一下他們的 gutter, 然後根據有些區塊做不同的 gutter

結論

那在哪邊才適合使用 Flex + Gap 呢?

不需要使用佔比來分配容器空間的地方

就是比較常見的使用 mr-? 這種推開的地方

需要網格列表還是乖乖使用 Grid System,或是 Flex + CSS Grid Gap

Flexbox 對齊方式記憶

· 閱讀時間約 2 分鐘
Imagine Chiu
Front End Engineer @ Bearests

身為一個前端工程師,對於 Flexbox 的對齊方式一直沒有很有系統地方式去使用他,常常遇到要對齊置中的時候,就先用 align-item-center, 如果不行,然後再用 justify-content-center 試試看,如果再不行... 恩.. 應該就是父容器的高度問題了。

時至今日,應該要用一個方式來記憶他了

主軸 與 交錯軸

先搞清楚你是要控制 主軸 還是 控制 交錯軸

flexbox-alignment.png

  • justify-content 負責控制 主軸對齊
  • align-items 負責控制 交錯軸對齊

Row 水平排列

Row水平排列,所以控制主軸的對齊就是 水平對齊

Flex
align-self
Flex

Column 垂直排列

Column垂直排列,所以控制主軸的對齊就是 垂直對齊

Flex
align-self
Flex

結論

所以我們只需要記,現在是 flex-row,那我想改垂直置中,那麼就控制主軸的相反 交錯軸是 align-item 在控制的 反之,如果現在是 flex-column,那我想改垂直置中,那麼的主軸 justify-content 在控制的