Media Query
這件事情應該是講到爛掉了,我們稍微複習一下就好,
@media (min-width: 32rem) {}
收工(欸)!
爾或者是,
/* 請不要這樣做 */
@media (min-width: 90ch) {}
等等好歹也解釋一下
ch
好的,這邊這個單位 ch
是一種字元長度單位,但是他不代表你的 字有多長,以下是 w3c 的解釋,
Equal to the used advance measure of the "0" (ZERO, U+0030) glyph found in the font used to render it. (The advance measure of a glyph is its advance width or height, whichever is in the inline axis of the element.)
根據 caniuse.com 的回報,普及率也算高。這個單位很適合用來規劃文字內容區塊的排版。然而如果無法正確量測尺寸,這個單位會使用 0.5em
來當作預設值。
通常這個單位會搭配一些運算,並且放入 Flex 或 Grid 當中,最外面的 Media Query 只是輔助。也就是說,我們在面對排版的大前提下,針對「尺寸」這件事情,所配用的順序是這樣,
@media
指定各種裝置尺寸所需要的外層容器尺寸。- Grid 用以規劃容器內的元件流。
- Flex 用以規劃元件內更小級別的元件流。
所以,當你不需要針對特殊斷點做設定的話,甚至連 @media
都可以省略。
Flex 與 Grid
我先來兩個比較魔術的寫法,
.grid {
grid-template-columns: repeat(auto-fit, minmax(15ch, 1fr));
}
.flex-item {
flex-grow: 1;
flex-shrink: 1;
flex-basis: calc((48rem - 100%) * 9999);
}
可以不解釋嗎?
好的,為了防止路上被人賭到,我先解釋一下上面這些個魔術方法在做什麼事情。首先,請先自行複習一下 repeat
跟 auto-fit
這兩件事情,後面的 minmax(15ch, 1fr)
我來解釋解釋,
首先,我們的尺寸使用了 minmax
亦即他的尺寸會介於 15ch
跟 1fr
之間。我知道這是廢話,然後那個 15ch
是依照字元寬度來設定成 最小 尺寸,接著使用 1fr
來當作最大尺寸,我知道這還是廢話。這樣設定主要的用意就是,
- 格線容器的內容會自動緊湊符合(
auto-fit
)。 - 當格線容器寬度小於
15ch
的時候,會變成只有一個column
,這個column
的尺寸是1fr
。 - 當格線容器大於
15ch
的時候,會從15ch
開始分column
排列,然後自動切斷成row
。 - 當有多欄(
column
)出現時,每個欄位的寬度都會是1fr
,然後會套用自動緊湊符合(auto-fit
)。
所以我們會有一下這些結果,
我們接著來看 Flex 的設定,
.flex-item {
flex-grow: 1;
flex-shrink: 1;
flex-basis: calc((48rem - 100%) * 9999);
}
上面的 flex-grow: 1;
, flex-shrink: 1;
就不解釋了。這邊的魔法在於 calc()
這個方法。一般來說,我們在設定 flex-basis
的時候,通常會指定一個數值,或是項這樣透過 calc()
做運算,但是,這邊混合了一個包含單位的絕對數值,與一個相對數值,然後後面還乘上了一個無單位數字。那,到底這樣會發生什麼事情?
- 當尺寸大於
48rem
的時候,他會變成多欄(column
)的形式呈現。 - 多欄的形式會呈現出不固定的欄位寬度,此時是因為
flex-grow
的關係會將欄位寬度撐滿容器。 - 如果尺寸小於
48rem
的時候,他會變成單欄多行(row
)的形式。 - 這個時候的欄位寬度,會因為
flex-grow
的關係會將欄位寬度撐滿容器。 - 後面那個
* 9999
是為了避免中間值誤差。
所以,我們會有以下兩種結果,
何謂 中間值誤差,我們看圖,
為何會稱他為誤差,請回頭看一下 Grid 那邊的操作,照理來說,我們會希望 1
, 2
, 3
, 4
這四個元件的尺寸會相同,頂多就是因為寬度不夠而被換行,但是,在 Flex 的呈現,卻變成了 4
填滿了整個容器。所以,為了避免這種偏差值存在,所以我們後面再加上 * 9999
這樣的設定。
我再解釋一次 calc()
在 48rem - 100%
這邊的操作,
- 當容器尺寸為
900px
,是大於48rem
的狀況(假設1rem = 16px
),運算結果為:-132
然後乘上9999
變成了:-1319868px
。 - 當
calc()
計算出負數,對於flex-basis
來說負數是不被允許的數值,會自動變成auto
。 - 當容器尺寸為
600px
,是小於48rem
的狀況,運算結果為:1679832px
。 - 此時對於
flex-basis
來說是正確數值,但是由於flex-shrink: 1;
的關係,他會縮小到符合容器尺寸。
這樣可以理解 flex-basis
到底發生了什麼事情了吧。另外,你要把 9999
換成 999
應該也是可以,只要你確認你的裝置不會這麼巨大的話應該是沒有問題的。
你說,誰還會需要
@media
呢?
所以說那個手機版
話說我今天去換輪胎,然後四傳一次要換四顆。換完師傅試車後跟我說,我的輪軸有異音應該要換了。
我難過。
所以如果你使用了 Media Query,在搭配上面兩種魔術方法,基本上可以更彈性的來調整內容。不過,這邊有一個比較大的前提是,你的內容不會因為彈性大小而造成差異,也就是我一開始說的,這些方式比較適合在文字展示區塊。