響應(yīng)式開(kāi)發(fā)中合理選定CSS媒體查詢(xún)分割點(diǎn)
本文響應(yīng)式開(kāi)發(fā)中合理選定CSS媒體查詢(xún)分割點(diǎn)翻譯自David Gilbertson的The-100%-Correct-Way-To-Do-CSS-breakpoints一文。本文唔看上去有些拗口,不過(guò)其核心是在于給出合適的Media Query命名與編寫(xiě)方式。
本文從屬于筆者的Web 前端入門(mén)與***實(shí)踐中的Web 響應(yīng)式開(kāi)發(fā)系列文章。
在閱讀本文的時(shí)候,反而希望你能先忘卻關(guān)于CSS、Web開(kāi)發(fā)那些你已經(jīng)知道的東西,我們今天討論的并不是多么復(fù)雜深?yuàn)W的內(nèi)容,如果你覺(jué)得準(zhǔn)備好了那我們可以從下面這個(gè)簡(jiǎn)單的點(diǎn)圖開(kāi)始:
上面這些點(diǎn)分布的有些隨意,分分合合,有近有遠(yuǎn),我們的問(wèn)題就是如何將這些點(diǎn)劃分入到五個(gè)組中。最簡(jiǎn)單的,我們可以在那些相距較遠(yuǎn)的兩個(gè)點(diǎn)之間設(shè)置為分隔區(qū)劃分到不同的組合中。
上面這幾個(gè)圈都是我隨手畫(huà)出來(lái)的,你當(dāng)然可以選擇其他的劃分方式,譬如將最右邊的兩個(gè)點(diǎn)劃分到一個(gè)分組中。其實(shí)這個(gè)問(wèn)題并無(wú)所謂錯(cuò)誤答案,不過(guò)如果你以如下方式劃分的話(huà):
看上去是不是覺(jué)得怪怪的?我問(wèn)這個(gè)問(wèn)題也不是無(wú)中生有,當(dāng)我們需要為不同尺寸的屏幕設(shè)置不同的CSS樣式稿時(shí),會(huì)有人喜歡按照最常見(jiàn)的尺寸作為分割點(diǎn),即320px,768px與1024px。
不知道你有沒(méi)有聽(tīng)過(guò)或者說(shuō)過(guò)下面這些話(huà):中等屏幕的話(huà)是不是按照768px來(lái)劃分?還是應(yīng)該把768px也劃分到中等屏幕的范圍內(nèi)?不過(guò)這個(gè)尺寸是iPad橫屏狀態(tài)下的尺寸,應(yīng)該算是大屏幕了吧?唔那大屏幕就是768px和以上尺寸咯?然后320px左右的是小屏幕?那319px算啥?區(qū)分螞蟻的嗎?本文的主旨即使討論如何選擇合適的分割點(diǎn)與分隔組。
選擇合適的分隔點(diǎn)
你在幼兒園里就會(huì)畫(huà)上面的這些圓吧,我現(xiàn)在用矩形度量來(lái)詳細(xì)闡述下:
我們?cè)谶@里選擇了600px,900px,1200px以及1800px作為分割點(diǎn),這些分隔組包含了最常見(jiàn)的14個(gè)機(jī)型:
我們把這兩張圖合并下,可以得出下面這個(gè)更適合你的老板、設(shè)計(jì)師、開(kāi)發(fā)者以及測(cè)試人員看的一張圖:
用更直觀的方式命名你的分組
你愿意的話(huà),也可以使用Papa-Bear與Baby-Bear來(lái)稱(chēng)呼你選定的分割點(diǎn)。不過(guò)當(dāng)你和設(shè)計(jì)師一起討論網(wǎng)站在不同屏幕上的展示效果時(shí),肯定希望雙方都能夠在腦海中形成感性直觀的認(rèn)知。如果你用平板豎屏尺寸來(lái)形容的話(huà),那到底是iPad還是Surface呢?特別是現(xiàn)在這種手機(jī)越來(lái)越大,平板越來(lái)越小的情況,你很難用單純的平板或者手機(jī)來(lái)劃分尺寸。不過(guò)好消息是蘋(píng)果已經(jīng)不做新產(chǎn)品了,他們只是不斷地將按鈕、耳機(jī)口從現(xiàn)在的產(chǎn)品中移除。這邊我也不好給出什么建議,只能說(shuō)設(shè)計(jì)師和產(chǎn)品之間需要多多溝通。
聲明式的設(shè)置響應(yīng)式布局
聲明式的概念在前端很是流行,譬如著名的React就是典型的聲明式組件庫(kù)。聲明式編程應(yīng)用到CSS中即是CSS應(yīng)當(dāng)定義What it wants,而不是How it should。我們上面討論過(guò)的一個(gè)關(guān)于分割點(diǎn)的容易混淆之處就是分割點(diǎn)同時(shí)代表了某個(gè)范圍。譬如$large:600px這種定義在large這個(gè)詞本身代表一個(gè)范圍值的時(shí)候就會(huì)混淆。因此在具體的某個(gè)組件或者標(biāo)簽中,我們應(yīng)該對(duì)其隱藏具體的尺寸設(shè)置,譬如:
- @mixin for-phone-only {
- @media (max-width: 599px) { @content; }
- }
- @mixin for-tablet-portrait-up {
- @media (min-width: 600px) { @content; }
- }
- @mixin for-tablet-portait-only {
- @media (min-width: 600px) and (max-width: 899px) { @content; }
- }
- @mixin for-tablet-landscape-up {
- @media (min-width: 900px) { @content; }
- }
- @mixin for-tablet-landscape-only {
- @media (min-width: 900px) and (max-width: 1199px) { @content; }
- }
- @mixin for-desktop-up {
- @media (min-width: 1200px) { @content; }
- }
- @mixin for-desktop-only {
- @media (min-width: 1200px) and (max-width: 1799px) { @content; }
- }
- @mixin for-big-desktop-up {
- @media (min-width: 1800px) { @content; }
- }
- // usage
- .my-box {
- padding: 10px;
- @include for-desktop-up {
- padding: 20px;
- }
- }
你會(huì)發(fā)現(xiàn)在上面的定義中我很推薦使用-up與-only后綴,在具體使用樣式的地方:
- .phone-only {
- @include for-phone-only { background: purple; }
- }
- .tablet-portait-only {
- @include for-tablet-portait-only { background: purple; }
- }
- .tablet-portrait-up {
- @include for-tablet-portrait-up { background: purple; }
- }
- .tablet-landscape-only {
- @include for-tablet-landscape-only { background: purple; }
- }
- .tablet-landscape-up {
- @include for-tablet-landscape-up { background: purple; }
- }
- .desktop-only {
- @include for-desktop-only { background: purple; }
- }
- .desktop-up {
- @include for-desktop-up { background: purple; }
- }
- .big-desktop-up {
- @include for-big-desktop-up { background: purple; }
- }
不過(guò)這種方式在需要大量自定義媒介查詢(xún)搭配的時(shí)候就顯得不是那么靈活,我們可以提供更加細(xì)粒度的控制方式:
- @mixin for-size($size) {
- @if $size == phone-only {
- @media (max-width: 599px) { @content; }
- } @else if $size == tablet-portrait-up {
- @media (min-width: 600px) { @content; }
- } @else if $size == tablet-portait-only {
- @media (min-width: 600px) and (max-width: 899px) { @content; }
- } @else if $size == tablet-landscape-up {
- @media (min-width: 900px) { @content; }
- } @else if $size == tablet-landscape-only {
- @media (min-width: 900px) and (max-width: 1199px) { @content; }
- } @else if $size == desktop-up {
- @media (min-width: 1200px) { @content; }
- } @else if $size == desktop-only {
- @media (min-width: 1200px) and (max-width: 1799px) { @content; }
- } @else if $size == big-desktop-up {
- @media (min-width: 1800px) { @content; }
- }
- }
- // usage
- .my-box {
- padding: 10px;
- @include for-size(desktop-up) {
- padding: 20px;
- }
- }
這種方式自然能夠達(dá)成預(yù)期的效果,不過(guò)如果某個(gè)粗心的開(kāi)發(fā)者傳入了某個(gè)未預(yù)定義的范圍名,那么久尷尬了,因此我們還是建議不要傳入某個(gè)具體的尺寸,而是傳入某個(gè)范圍:
- @mixin for-size($range) {
- $phone-upper-boundary: 600px;
- $tablet-portrait-upper-boundary: 900px;
- $tablet-landscape-upper-boundary: 1200px;
- $desktop-upper-boundary: 1800px;
- @if $range == phone-only {
- @media (max-width: #{$phone-upper-boundary - 1}) { @content; }
- } @else if $range == tablet-portrait-up {
- @media (min-width: $phone-upper-boundary) { @content; }
- } @else if $range == tablet-portait-only {
- @media (min-width: $phone-upper-boundary) and (max-width: #{$tablet-portrait-upper-boundary - 1}) { @content; }
- } @else if $range == tablet-landscape-up {
- @media (min-width: $tablet-landscape-upper-boundary) { @content; }
- } @else if $range == tablet-landscape-only {
- @media (min-width: $tablet-portrait-upper-boundary) and (max-width: $tablet-landscape-upper-boundary - 1px) { @content; }
- } @else if $range == desktop-up {
- @media (min-width: $tablet-landscape-upper-boundary) { @content; }
- } @else if $range == desktop-only {
- @media (min-width: $tablet-landscape-upper-boundary) and (max-width: $desktop-upper-boundary - 1px) { @content; }
- } @else if $range == big-desktop-up {
- @media (min-width: $desktop-upper-boundary) { @content; }
- }
- }
- // usage
- .my-box {
- padding: 10px;
- @include for-size(desktop-up) {
- padding: 20px;
- }
- }