利用 srcset 進行圖片最佳化的方法

在網路上搜尋了與 srcset 相關的文章後,我認為〈img 的 srcset、sizes 和 picture 元素〉(簡體中文)這篇文章的敘述最淺顯易懂,所以主要的說明會根據這篇文章的介紹,改寫成我自己的理解。

這次的實作使用了 WordPress 外掛 Advanced Custom Fields (ACF)。ACF 是一套可以將 WordPress 客製化能力更上一層樓的外掛,非常適合有客製化需求的人使用。

問題

為了幫助客戶寫客製化的精選圖片功能:在手機與桌面使用完全不同設計的兩張圖,因此一開始使用了 wp_is_mobile() 來判斷,並針對不同的裝置,直接載入對應的圖片。

但是由於加裝了快取外掛,因此頁面快取後,會出現「在桌機上看到行動裝置專用的圖片」的狀況,因此重新改用 img 標記中的 srcset 屬性來實作。

思考步驟

原本做法

一開始是透過 wp_is_mobile 這個方法去判斷,在行動裝置上載入比較小的圖片。會這麼做最主要的原因,是因為行動裝置上顯示的,並非是使用 WordPress 自動產生的縮圖。但是誠如一開始提到的,這個做法,一旦頁面被快取了,很有可能在桌機上看到手機上快取的版本,也就是畫質比較差的圖片。

<?php
if ( ! function_exists( 'huanyi_post_thumbnail' ) ) :
  /**
   * Displays an optional post thumbnail.
   *
   * Wraps the post thumbnail in an anchor element on index views, or a div
   * element when on single views.
   */
    function huanyi_post_thumbnail() {
        if ( post_password_required() || is_attachment() || !has_post_thumbnail() ) {
            return;
        }
        if ( wp_is_mobile() ) :
        //如果是行動裝置,用自訂的 mobile_fv 圖片取代原本的精選圖片
        ?>
        <div class="post-thumbnail">
            <?php if (!empty(get_field('mobile_fv'))) :
                $img = get_field('mobile_fv');?>
            <img src="<?php echo $img['url']; ?>"
                 alt="<?php echo $img['alt']; ?>"
                 title="<?php echo $img['title']; ?>">
            <?php else : //如果沒有設定 mobile_fv 的圖案,維持預設精選圖片
                the_post_thumbnail();
            endif; ?>
        </div><!-- .post-thumbnail -->
        <?php
        elseif ( is_singular() ) :
        ?>
        <div class="post-thumbnail">
            <?php the_post_thumbnail(); ?>
        </div><!-- .post-thumbnail -->
        <?php else : ?>
        <a class="post-thumbnail"
           href="<?php the_permalink(); ?>" aria-hidden="true" tabindex="-1">
        <?php
            the_post_thumbnail( 'post-thumbnail', array(
                'alt' => the_title_attribute( array(
                    'echo' => false,
                ) ),
            ) );
        ?>
        </a>
        <?php
        endif; // End is_singular().
    }
endif;

調整作法:srcset

  1. 只要內容裡包含了自訂的 mobile_fv 圖片,就啟用 srcset 的設定。
  2. 手機用的圖片寬度為 480px,中斷點設定為 768px

雖然上網查了文件,嘗試了幾次,但是因為在設定 srcset 的時候,使用的單位並非我們習慣看到的 px,而是 w,因此花了較多的時間去消化。看到喵不留行寫的文章,很仔細的介紹了這些單位應該如何運用,建議可以去參考他的說明。

<!-- 一般的 img 標記長得像這樣:-->
<img src="path/to/image.png" alt="alt text" title="title" />
<!-- 加入 srcset 的屬性會是這樣 -->
<img src="path/to/image.png"
     sizes="(max-width: 768px) 50vw, 100vw"
     srcset="image-480px.png 480w,
             image-1024px.png"
     alt="alt text" title="title />

一般來說,會將 w 設定為圖片的原始寬度,而不是在頁面上的寬度。對我來說主要是易讀性,讓開發者比較容易預期會讀取哪一張圖片。

至於實際上瀏覽器的判斷流程是這樣的:

  1. 裝置查詢的斷點是 768 px
  2. 面對小於 768 px 的裝置 (例如 600px),要尋找視窗 50% 寬度的圖片 (50vw,也就是 300px)
  3. 大小大於 300px 的最小圖片是 image-480px.png,所以寬度 600 的裝置會顯示 image-480px.png

這裡稍微再補充一下,這種做法對於 Retina 顯示的螢幕也有效。瀏覽器在偵測到 Retina 時,會自動將媒合圖片的基準乘以相對應的倍數,藉此找到適合的圖片。

實際步驟

將原本的程式做以下的改寫:

  1. 將 wp_is_mobile 的判斷改成 if ( !empty( get_field( ‘mobile_fv’ ) ) )
  2. 將輸出的 img 標記加入 srcset 的屬性
<?php
  function huanyi_post_thumbnail() {
    if ( post_password_required() || is_attachment() || !has_post_thumbnail() ) {
    return;
}
    if ( !empty( get_field( 'mobile_fv' ) ) ) :
    ?>
    <div class="post-thumbnail">
        <?php
        $img = get_field('mobile_fv');?>
        <img src="<?php echo $img['url']; ?>"
             sizes="(max-width: 768px) 50vw, 100vw"
             srcset="<?php echo $img['url']; ?> 480w,
                     <?php echo get_the_post_thumbnail_url(); ?>"
             alt="<?php echo $img['alt']; ?>"
             title="<?php echo $img['title']; ?>">
    </div><!-- .post-thumbnail -->
    <?php
    elseif ( is_singular() ) :
    ?>
    <div class="post-thumbnail">
        <?php the_post_thumbnail(); ?>
    </div><!-- .post-thumbnail -->
    <?php else : ?>
    <a class="post-thumbnail"
       href="<?php the_permalink(); ?>" aria-hidden="true" tabindex="-1">
    <?php
        the_post_thumbnail( 'post-thumbnail', array(
            'alt' => the_title_attribute( array(
                'echo' => false,
            ) ),
        ) );
    ?>
    </a>
    <?php
    endif; // End is_singular().
}

總結

一開始會看不懂相關的文件,很重要的原因是不懂 vw 這個單位。vw 代表的是佔螢幕畫面的百分比寬度,也就是說,在寬度 1440px 的裝置裡,10vw 就相當於 144px、在 768px 的裝置裡則是 76.8px。

其實還有更直覺的做法,就是使用 HTML 5 中的 picture 標記,但是在最後呈現的時候,就會比 img 標記的做法多出了兩個標籤,作法上比較不那麼輕巧。

這篇文章提出的寫法,主要是在 WordPress 中自訂 tag 的時候使用。除了這種自訂的 tag 之外,應該也能夠透過 apply_filter 這種勾點的方法,覆寫原本 the_post_thumbnail() 呈現圖片的方式。

參考資料

預設圖片
Eric Chuang
正職是廣告行銷人員,因為 Google Tag Manager 的關係開始踏入網站製作的領域,進一步把 WordPress 當成 PHP + HTML + CSS + JavaScript 的學習教材。此外,因為工作的關係,曾經用 Automattic 的 Underscores (_s) 替客戶與公司官網進行全客製化佈景主題開發。

發佈留言

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料

Physical Address

304 North Cardinal St.
Dorchester Center, MA 02124