博客 / 詳情

返回

【Mobile Dev Weekly #383】移動先行 or 桌面先行

🥳 歡迎有興趣的小夥伴,一起做點有意義的事!本文譯者:一緒

我發起了一個週刊翻譯計劃,倉庫地址,訪問地址

現在還很缺志同道合的小夥伴,純屬個人興趣,當然對於提升英語和前端技能也會有幫助,要求:英語不要差的離譜、github熟練使用、有恆心、謙虛、對自己做的事負責。

想參與的小夥伴,可以wx私信,也可以給倉庫發issue留言,我博客也有具體的個人聯繫方式:daodaolee.cn

不知道你是否經常考慮新項目首先應該適配移動端還是桌面端?最近,我在Twitter發起了一次關於此項的投票,總票數為648票,比例如下:

  • 移動優先:33.3%
  • 桌面優先:21.9%
  • 兩者混合:24.7%

在下文中,我們將一起了解每種方法的含義和一些響應式設計技巧,然後再去討論在今天這些方法是否適用。

簡介:移動優先和桌面優先的含義

移動優先意味着在網站開發時,我們首先以較小的視口尺寸編寫CSS,然後使用CSS媒體查詢來優化大視口的體驗

考慮以下示例:

.section {
    padding: 2rem 1rem;
}

@media (min-width: 62.5rem) {
    .section {
        display: flex;
        align-items: center;
        gap: 1rem;
        padding: 4rem 2rem;
    }
}

我們為移動端設備配置了一個padding屬性,當視口大小足夠大時,他應該會是個擁有更大padding的彈性盒

這僅僅是一個簡單的例子,可以想象一下們有一個足夠大的網站或移動APP,那麼我們要設置的東西就會多得多。

而當我們採取桌面優先的方式時,情況剛好相反

.section {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 4rem 2rem;
}

@media (max-width: 62.5rem) {
    .section {
        display: block;
        padding: 2rem 1rem;
    }
}

我們首先為較大的視口編寫CSS,然後再使用媒體查詢為小視口更改CSS

移動優先的開發流程是怎麼樣的?

你是喜歡直接在瀏覽器F12調成移動設備進行開發,不去適配桌面?還是更喜歡兩者同時進行?也就是在優先寫移動設備樣式的同時,也去適配桌面的視口尺寸。

這是我能夠設想到的兩種情況:

  1. 先處理移動設備所有頁面的CSS樣式,最後再去適配桌面端
  2. 同時進行,每做好一個移動端的頁面或組件,都先對於大視口進行適配。

你通常使用哪一種哪?對我來説,第二種是更適合我的方式,這樣能使我更專注我當前組件或頁面,而且也會減少編寫CSS的錯誤。

當你使用第一種方法時,很可能會為平板電腦或者桌面端重寫CSS,我們來看下面這張圖:

我們拿.hero選擇器來做例子:

.hero {
  display: flex;
  align-items: flex-end;
  background-image: url('hero.jpg');
  background-size: cover;
  background-repeat: no-repeat;
}

.hero__title {
  font-size: 1rem;
}

.hero__thumb {
  display: none;
}

@media (min-width: 60rem) {
  .hero {
    align-items: center;
    background-image: initial;
    background-color: #7ecaff;
  }

  .hero__title {
    font-size: 2rem;
  }

  .hero__thumb {
    max-width: 320px;
    display: block;
  }
}

就像上述代碼所寫的那樣,.hero選擇器在移動端有一個背景圖片,而在桌面端則是一個純色背景,並且有一張位於最右邊的圖片。就像你所看到的那樣,這是移動端優先的CSS樣式 ,除了font-sizebackground之外,我們沒有太多需要重寫的地方。

那麼導航哪,移動端優先的方式會怎麼寫?

.nav {
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    overflow-y: auto;
    padding-top: 2rem; /* 導航按鈕的空隙 */
}

.nav__toggle {
    position: absolute;
    right: 1rem;
    top: 1rem;
}

.nav__item {
    padding: 1rem;
    display: block;
}

.nav__item:not(:last-child) {
    border-bottom: 1px solid #fff;
}

/* 桌面端樣式 */
@media (min-width: 60rem) {
    .nav {
        position: initial;
        width: initial;
        height: initial;
        overflow-y: initial;
        display: flex;
        align-items: center;
        padding-top: 0;
        background-color: blue;
    }

    .nav__toggle {
        display: none;
    }

    .nav__item:hover {
        color: blue;
        background-color: initial;
    }

    .nav__item:not(:last-child) {
        border-bottom: 0;
        border-left: 1px solid #fff;
    }
}

不知道你有沒有看出來,桌面端要重寫的樣式大概跟移動端的已有樣式持平,這可不是件好事。

另外,有時候也會因為CSS特性導致一些莫名其妙的問題,比如説我希望從.nav_item中刪除border-bottom

.nav__item {
    border-bottom: 0;
}

這並不會起作用,因為:not偽類在這種情況下擁有更高的優先級

使用如下方法,會使之生效:

.nav .nav__item {
    border-bottom: 0;
}

/* 或者 */

.nav__item:not(:last-child) {
    border-bottom: 0;
    border-left: 1px solid #fff;
}

桌面端優先的開發流程是怎樣的?

依舊還是導航欄的案例,我們來看一下桌面優先的方案是怎樣的?

.nav {
    display: flex;
    align-items: center;
    background-color: blue;
}

.nav__toggle {
    position: absolute;
    right: 1rem;
    top: 1rem;
}

.nav__item {
    padding: 1rem;
    display: block;
}

.nav__item:hover {
    color: blue;
    background-color: initial;
}

.nav__item:not(:last-child) {
    border-bottom: 0;
    border-left: 1px solid #fff;
}

@media (max-width: 25rem) {
    .nav {
        display: block;
        position: fixed;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        overflow-y: auto;
        padding-top: 2rem; /* Space for the toggle */
    }

    .nav__toggle {
        display: block;
    }

    .nav__item:not(:last-child) {
        border-bottom: 1px solid #fff;
    }
}

當以桌面端為先時,我們可以看出,覆蓋次數相對於移動端優先少了許多。這不是很有意思嗎?主要的原因是我們通過媒體查詢的max-width審查了特定視口所有的特定樣式。

我提倡我們應該先為桌面端編寫CSS樣式,然後再去適配移動端。

通過下面這張對比圖我們可以看出,以桌面優先編寫CSS樣式看起來更短並且沒有不必要的重複(好吧,他有一點點~~)

小學生才做選擇,成年人兩個都要

對我而言,我不願去拘泥於任何一種方法。而我更願意嘗試去將兩種方法結合起來。
這意味着,我們需要先編寫基本的樣式,然後再去考慮在移動端和桌面端下會發生什麼?
我喜歡Elad Shechter在這篇文章中提到的。

讓我們來舉一個抽象的例子:

.nav {
    /* 基礎樣式:不涉及任何窗口尺寸 */
}

/* 桌面端樣式 */
@media (min-width: 800px) {
    .nav { ... }
}

/* 移動端樣式 */
@media (max-width: 799px) {
    .nav { ... }
}

就像你看到的那樣,媒體查詢的範圍對應着不同的窗口大小,這意味着我們不會做任何覆蓋屬性的操作。這種方法對於在移動端和桌面端看起來完全不同的組件很有用。在我們的例子中,他就是導航。

但是,對於像<section>這樣的,在移動端和桌面端區別不大的,混合方式起不到太大的作用

.section {
    padding: 1rem;
}

/* 桌面樣式 */
@media (min-width: 800px) {
    .section {
        padding: 2rem 1rem;
    }
}

我應該如何處理響應式設計

在有些時候,我會覺得討論移動先行還是桌面先行沒那麼重要,因為現代CSS給我們提供了用更少CSS代碼編寫響應式佈局CSS樣式的方法

話雖如此,我認為移動先行和桌面先行的爭論將僅限於在特定的視口下顯示或隱藏元素。除了那些特別複雜的和特定視口下變化很大頁面或組件。

讓我們找一個現實中的案例去説明這些概念:

在移動設備和桌面設備上有一些不同的組件,比如導航欄和標題,其餘地方僅有一些細微的差別。對於標題,我們可以通過min-widthmax-width的混合使用來確定特定視口下的樣式設計。

但是,<section>和文章網格就需要使用基本樣式,然後將min-width用在必要的地方。

把思想放開,不要把他關在籠子裏。這只是我手頭上的一個設計,不需要嚴格的按照我的方式去做。現在讓我們展示更多細節

如果標題和導航採用移動優先的方式,就會導致大量的CSS屬性重複,這不是我們提倡的方式。下面是我想到的方法:

.header {
    /* 基礎樣式 */
}

/* 桌面端樣式 */
@media (min-width: 1000px) {
    .nav__toggle,
    .nav__close {
        display: none;
    }
}

/* 移動端樣式 */
@media (max-width: 999px) {
    .nav {
        position: fixed;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        background-color: #4777dB;
    }
}

對於<section>部分,我們使用彈性盒去處理行與列的樣式,也可以用於重新排序或移動元素

<section class="hero">
    <div class="wrapper">
        <img src="thumb.jpg" alt="" />
        <h2><!-- Headline --></h2>
        <p><!-- Description --></p>
    </div>
</section>
.hero {
    display: flex;
    flex-direction: column;
}

@media (min-width: 1000px) {
    flex-direction: row;
}

@media (max-width: 999px) {
    .hero__thumb {
        order: -1;
    }
}

在這裏,order:-1這個屬性我只在max-width確定範圍中使用了一次。
我可以做這樣的事:

.hero__thumb {
    order: -1;
}

@media (min-width: 1000px) {
    .hero__thumb {
        order: initial;
    }
}

怎麼樣?沒有看到重複吧哈哈哈~
此外,請注意如果在彈性盒中使用了order,會導致視覺順序與HTML中的DOM順序不匹配

在下面這個可視化圖表中,解釋了我如何抉擇移動先行還是桌面先行:

避免雙斷點媒體查詢

min-widthmax-width使用相同的視口大小可能會導致難以想象的問題。

@media (max-width: 500px) {
    .nav {
        display: none; 
    }
}

@media (min-width: 500px) { 
    .nav__toggle {
        display: none; 
    }
}

上面這段代碼看起來可以做到無縫銜接,但是在大多數的情況下,你會忘記測試一個重要的斷點:500px,即兩個斷點之間那一像素的間隔。在這個斷點處,導航和展開按鈕都不可見。

在F12的移動模式下,如果不手動輸入500px,很難發現這個問題。
為防止出現這種問題,請儘量避免在min-widthmax-width中使用相同的值。

@media (max-width: 499px) {
    .nav {
        display: none; 
    }
}

@media (min-width: 500px) { 
    .nav__toggle {
        display: none; 
    }
}

你以為這個問題是我發現的嗎?
哈哈哈哈,其實是我從Debugging CSS這本書中借來的。

設計師怎麼看移動先行

我自己也是一名設計師,坦白了講,我不喜歡移動先行的設計。

  • 移動先行的設計圖是有限制的,很難發揮創意
  • 處理過高的設計很令人心煩,因為你要不斷的將設計圖上下滾動

而桌面先行的設計圖就要好得多,至少對我來説,它可以立即嘗試我的新想法,而且我不需要通過頻繁的上下滾動來查看設計圖有哪些不合理的地方。

現代CSS減少了考慮移動先行還是桌面先行的必要

有很多當下和即將推出的CSS功能,它將使響應式設計更容易實現

Flexbox Wrapping

在 Geoffrey Crofte 的文章 如何不適用媒體查詢製作響應式卡片中,他探索瞭如何在不使用媒體查詢的情況下製作響應式卡片。我會在這裏解釋他的基本概念,你也可以選擇閲讀原文了解更多細節。

設置一個固定的flex-basis值,並允許item在需要的時候增長和伸縮,這可以實現一個無媒體查詢的響應式組件。

這個示例展示了空間不足時卡片的外觀

CSS網格佈局和minmax函數

幸虧有了CSS Grid,我們可以擁有不依賴媒體查詢的響應式網格佈局,考慮以下示例:

.wrapper {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  grid-gap: 1rem;
}

這是一個響應式網格,為每個項目提供最小200px的寬度。
如果沒有CSS網格,我們就需要使用媒體查詢來根據視口改變元素寬度。

在本文了解更多有關CSS GirdMinmax()

視口單位與clamp函數

將視口單位和clamp函數結合使用可以有效減少有關font-size,padding,margin等元素尺寸的使用。

.title {
    font-size: clamp(16px, (1rem + 5vw), 50px);
}

.hero {
    padding: clamp(2rem, 10vmax, 10rem) 1rem;
}

.sidebar {
    flex-basis: max(30vw, 150px);
}

容器查詢

CSS新特性 容器查詢現在在Chrome下可用了。有了他們,我們可以在不使用媒體查詢的情況下做很多事。

考慮以下示例:

這是一個基於容器寬度的響應式分頁。不需要媒體查詢!

.wrapper {
  contain: layout inline-size;
}

@container (min-width: 250px) {
  .pagination {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  .pagination li:not(:last-child) {
    margin-bottom: 0;
  }
}

@container (min-width: 500px) {
  .pagination {
    justify-content: center;
  }

  .pagination__item {
    display: block;
  }
}

就像我展示的這樣,現代CSS支持我們不通過媒體查詢的方式製作響應式佈局。那麼問題來了,我們還需要考慮移動先行還是桌面先行的問題嗎?

相關鏈接

The State Of Mobile First and Desktop First - AHMAD SHADEED

翻譯計劃原文

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.