# 新聞網頁製作(五)- Responsive Web Design 響應式網頁 ## Slides https://hackmd.io/HOasqwrrSSWbTUKtf4HYNw?view#/1 ## 學習大綱: - [新聞網頁製作 (一) - HTML 標記式語言](https://hackmd.io/svhFYKq4QyaarC_J0WRsig) - [新聞網頁製作(二) - CSS 串接樣式表](https://hackmd.io/Pekdv0mvT8qD_LXLzUo9iQ) - [新聞網頁製作(三)- CSS 選擇器與基礎網頁排版](https://hackmd.io/ccO-gvxFR5-49q3ePoNJkg) - [新聞網頁製作(四)- CSS Position 與 Flexbox 排版](https://hackmd.io/i1uBelrpRv2Uz5emQawIiw) - [新聞網頁製作(五)- Responsive Web Design 響應式網頁](https://hackmd.io/ojTXG2s0RQaJz85goqIz1w) - [新聞網頁製作(六)- 多媒體元素與動態效果](https://hackmd.io/J_YYk1YUSum1x3fVo75PXA) - [新聞網頁製作(七)- 使用 GitHub 部署網頁](https://hackmd.io/P9N34oIwS2G6Mfhag3Rqzg) ## 前言 ![](https://i.imgur.com/LAR4X9W.gif) *圖1. 響應式網頁範例* 在早期,我們只有電腦可以呈現網頁,因此對於網頁的版型並不會考慮太多,只要電腦螢幕可以呈現就好。 然而,隨著手機和平板的推出和普及,大部分的使用者,不再單單使用電腦瀏覽網頁,使用者使用手機的頻率逐年增加。對於很多網站來說,來自手機的流量已經超越桌機。 為了滿足手機和平板使用者的需求,許多網站紛紛開發出不同載具的網頁。當一個網頁,可以同時在桌機、平板和手機上呈現,即稱之為「響應式網頁」。 ## 讓網頁根據視窗(viewport)大小來呈現 在手機和平板出現之前,網頁是為電腦量身訂做的,在設定上有一定的大小,並不適合在手機和平板上呈現。如下圖2.,我們會發現,即便網頁的寬設定成 375px ,在 iPhoneX 上看到的網頁,並沒有撐滿整個裝置。 ![](https://i.imgur.com/XTEJ7kP.png) *圖2.用手機呈現網頁,會發現網頁變小了,網頁並沒有撐滿 375px 的 viewport。* 為了解決網頁在手機和平板上呈現的問題,我們得在`<head>`裡面加入`<meta name="viewport" content="width=device-width, initial-scale=1.0">`。 ``` <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> ``` 透過 `<meta>`,我們告訴瀏覽器要如何根據載具的大小來呈現網頁,見圖3.。 ![](https://i.imgur.com/nzk5851.png) *圖3. 透過 `<meta>`,瀏覽器採用載具的大小來呈現網頁。`* ## 響應式網頁製作 為了讓網頁能夠同時在不同的裝置(手機、平板、桌機)上呈現, CSS 提供了 Media Queries。 利用 Media Queries,我們可以在不同的螢幕大小(Viewport),選擇套用不同的 CSS 樣式。 如此一來,我們便可以在同一個網頁上,根據不同的載具,呈現不同的版型和風格。 ## Media Queries 語法 若要使用 Media Queries,有以下三種寫法: - **在 HTML 裡面使用:** 在`link` 元素中,加入 `media` 屬性。 ```htmlembedded=false <link rel="stylesheet" type="text/css" href="style.css" media="screen"> <link rel="stylesheet" type="text/css" href="style-for-print.css" media="print"> ``` - **在 CSS 中使用** ```htmlembedded=false @media screen { /* CSS 樣式 */ } @media print { /* CSS 樣式 */ } ``` - **使用@import** ``` @import "style.css"; @import "style-for-print.css" print; ``` 上述三種寫法,針對的是 Media 的類型。 Media 類型是大方向的分類,若我們很細部地使用 CSS 樣式,可以使用 Media 的特徵。 #### Media 類型(Media Types) | 類型 | 說明 | | -------- | -------- | | all | 預設值。針對所有的裝置。 | | print | 印刷裝置,包含預覽列印的PDF。| |screen|螢幕裝置,包括手機、平板和桌機等。| |speech|朗讀裝置。| #### Media 特徵(Media Features) | 特徵 | 說明 | | -------- | -------- | | height | 螢幕(viewport)高度 | | min-height | 螢幕最小高度| | max-heigth| 螢幕最大高度| | width | 螢幕寬度| | min-width|螢幕最小寬度| | max-width|螢幕最大寬度| |aspect-ratio|螢幕長寬比例| |min-aspect-ratio|螢幕最小長寬比例| |max-aspect-ratio|螢幕最大長寬比例| |orientation|螢幕旋轉方向:**portrait**(直擺) 和 **landscape** (橫擺)| 以上 Media 特徵,我只列出常用的特徵。然而,還有許多 Media 特徵沒有提及。關於更多的 Media 特徵,推薦各位看 [CSS Media Queries 詳細介紹](https://www.oxxostudio.tw/articles/201810/css-media-queries.html),裡面有詳細的 Media 特徵的說明。 ### 如何在 CSS 中使用 Media Queries? 在實務上,我們時常將 Media Queries 套用在 CSS 裡(使用 `@media`)。 接著,我們透過幾個例子來了解 `@media` 的使用方式。 ##### 針對 Media 類別 ```css=false /* 針對螢幕裝置,h1 的字級大小為 60px */ @media screen { h1 { font-size: 60px; } } /* 針對印刷裝置,h1 的字級大小為 48px */ @media print { h1 { font-size: 48px; } } ``` ##### 針對 Media 特徵 ```css=false /* 針對螢幕寬度為 768px 的裝置 */ @media (width: 768px) { h1 { font-size: 60px; } } /* 針對螢幕最小寬度為 768px 的裝置,意即螢幕寬度大於 768px 的都套用 */ @media (min-width: 768px) { h1 { font-size: 60px; } } /* 針對螢幕最大寬度為 768px 的裝置,意即螢幕寬度小於 768px 的都套用 */ @media (max-width: 768px) { h1 { font-size: 60px; } } /* 針對螢幕長寬比為 1:1 的裝置 */ @media (aspect-ratio: 1/1) { h1 { font-size: 60px; } } /* 針對螢幕最大長寬比為 1024:1366 的裝置 */ @media (max-aspect-ratio: 1024/1366) { h1 { font-size: 60px; } } /* 針對橫擺的裝置 */ @media (orientation: landscape) { h1 { font-size: 60px; } } ``` ##### 在 Media 類型前使用 not 或是 only ```css=false /* 針對非螢幕裝置時套用 */ @media not screen { h1 { font-size: 60px; } } /* 只針對螢幕裝置,且螢幕寬度為 768px 的套用 */ /* 加上 only 的主要原因是為了避免不支援 Media 特徵的老舊瀏覽器不小心套用到樣式而寫。 */ /* 然而,現今的瀏覽器都有支援 Media 特徵的寫法,因此可以不用特別寫 only 了。 */ @media only screen and (width: 768px) { h1 { font-size: 60px; } } ``` ##### 將特徵和類型使用 and 組合起來使用 ```css=false /* 針對螢幕裝置,且螢幕裝置的最小寬度為 768px 時套用 */ @media screen and (min-width: 768px) {} /* 針對螢幕裝置,且螢幕裝置的最小寬度為 768px,且螢幕裝置橫擺時套用 */ @media screen and (min-width: 768px) and (orientation: landscape) {} ``` ##### 將特徵和類型使用 or 組合起來使用 ```css=false /* 針對印刷裝置,或是螢幕裝置的最小寬度為 768px 時套用 */ @media print, (min-width: 768px) {} /* 針對印刷裝置,或是螢幕裝置的最小寬度為 768px,或是螢幕裝置橫擺時套用 */ @media print, (min-width: 768px), (orientation: landscape) {} ``` ##### 將特徵和類型使用 or、and 組合起來使用 ```css=false /* * 針對 * 1.印刷裝置 * 2.螢幕裝置的最小寬度為 768px 且螢幕橫擺 * 時套用 */ @media print, (min-width: 768px) and (orientation: landscape) {} ``` ## break points 在設計和程式上,我們可以事先設定螢幕(viewport) break points,<br/> 當螢幕的寬超過 break points 時,就讓網站的採取更適合的 CSS style。<br/> 一般來說,break points 可以根據載具的寬來設定。 下面範例,是 Bootstrap CSS 定義的 breakpoints。 ```css=false /* Small devices (landscape phones, 576px and up) */ @media (min-width: 576px) {} /* Medium devices (tablets, 768px and up) */ @media (min-width: 768px) {} /* Large devices (desktops, 992px and up) */ @media (min-width: 992px) {} /* Extra large devices (large desktops, 1200px and up) */ @media (min-width: 1200px) {} ``` 當然,你也可以設定你自己覺得適合的 break points。 舉例而言,報導者的 break points 設定如下: ```css=false /* Mobile */ @media (max-width: 767px) {} /* Tablet */ @media (min-width: 768px) and (max-width: 1023px) {} /* Desktop */ @media (min-width: 1024px) and (max-width: 1439px){} /* HD */ @media (min-width: 1440px) {} ``` ## 響應式圖片(Responsive Image) 針對圖片,我們使用的是 `<img>` 元素,透過 `height` 和 `width` 屬性,我們可以指定圖片的寬和高。例如:`<img src="800x600.jpg" width="800" height="600">`。 若我們不指定寬和高的話,瀏覽器會依照該圖片的原始寬高呈現。 然而,當我們指定圖片的寬和高時,圖片就不會隨著瀏覽器的視窗(viewport)動態調整。 為了讓圖片的大小能隨著螢幕大小或瀏覽器視窗動態調整,以下有幾種做法: ### 1. 使用 `width` 樣式 ```css=false img { width: 100%; heigth: auto; } ``` 或是 ```htmlembedded=false <img width="100%" height="auto" src="https://github.com/nickhsine/teach-at-nccu/raw/master/assets/images/image-1.jpg"> ``` 當圖片的寬度設定成百分比(%)時,圖片的寬度會隨著它要呈現的範圍動態調整大小,如下圖4。 ![圖4](https://i.imgur.com/s0SzgSH.gif) *圖4:透過 `width: 100%; height: auto` 的方式使圖片動態調整大小* ### 2. 使用 `max-width` 樣式 使用 `width:100%` 可以讓圖片動態調整。 但有時候,圖片寬和長不夠大,讓圖片動態調整大小,可能會讓圖片看起來解析度不足,糊糊的。 倘若我們想限制圖片的大小,當圖片放大到某個程度後,就不再放大,我們可以使用 `max-width: 800px` 搭配 `width: 100%`(`800px` 是示意,你可以換成你想要的寬度),來限制圖片的寬度。 ```css=false /* css */ img { max-width: 800px; } ``` ```htmlembedded=false <!-- html --> <img width="100%" heigth="auto" src="https://github.com/nickhsine/teach-at-nccu/raw/master/assets/images/image-1.jpg"> ``` 上面的程式碼會產生圖5的結果。 ![圖5](https://i.imgur.com/9yqKkNw.gif) *圖5:透過 `max-width: 100%` 的方式使設定圖片動態調整的上限。* ### 3. 使用 Background Image 在[新聞網頁製作(二) - CSS 串接樣式表](https://hackmd.io/Pekdv0mvT8qD_LXLzUo9iQ)的內容裡,我們有教過`background-image`、`background-size`、`background-position` 等樣是,而透過這些樣式的組合,我們亦可讓圖片動態調整大小。 #### 3.1 使用 `background-size: contain` 當 `background-size` 樣式設定成 `contain` 時,背景圖會動態調整大小,試圖讓背景的圖完整呈現在內容區塊中,該圖不會被裁切,亦不會被調整長寬比。 ```css=1 div.bg-size-contain { width: 100%; height: 400px; background-image: url('https://github.com/nickhsine/teach-at-nccu/raw/master/assets/images/image-1.jpg'); background-repeat: no-repeat; background-size: contain; background-position: center; } ``` 上述程式碼可以產生圖6。 ![圖6](https://i.imgur.com/HruQc3V.gif) *圖6:使用 `background-size: contain`,讓圖片動態調整大小。* #### 3.2 使用 `background-size: cover` 使用 `background-size: contain` 的好處是圖片不會被裁切,能完整呈現在背景。 然而,我們有時候會需要圖片完整填滿內容區塊。若有這個需求時,我們可以將 `background-size` 設定成 `cover`。 當 `background-size: cover` 時,瀏覽器會裁切圖片,但保留圖片的長寬比,接著將圖片等比例放大或是縮小,完整填滿內容區塊。 ```css=1 div.bg-size-cover { width: 100%; height: 400px; background-image: url('https://github.com/nickhsine/teach-at-nccu/raw/master/assets/images/image-1.jpg'); background-repeat: no-repeat; background-size: cover; background-position: center; } ``` 上述程式碼能產生圖7。 ![圖7](https://i.imgur.com/0hjfEAl.gif) *圖7:使用 `background-size: cover`,讓圖片動態調整大小。* #### 4. 使用`object-fit` 除了用 `background-image` 適當裁切照片,好符合瀏覽器的視窗大小之外,`object-fit` 也可達成類似效果的樣式。 透過 CSS 裡的 `object-fit`,我們可以簡易地針對照片採用幾種裁切方式。 `object-fit: none`: 不將圖片縮小,直接置入欲呈現圖片的區塊內。 `object-fit: fill`: 不保證圖片原始的比例,直接將圖片撐滿欲呈現圖片的區塊。 `object-fit: cover`: 保持圖片原始的比例,透過縮小或放大置入欲呈現圖片區塊,若欲呈現圖片的區塊的長寬比與圖片不同,圖片則不會完整呈現。 `object-fit: contain`: 保持圖片原始的比例,置入欲呈現圖片區塊,若欲呈現圖片的區塊的長寬比與圖片不同,則會留白。 `object-fit: scale-down`: 對圖片依序使用 `none` 和 `contain`,最終呈現選擇尺寸比較小的那個。 請見一下程式碼範例: <iframe height="300" style="width: 100%;" scrolling="no" title="Untitled" src="https://codepen.io/nickhsine/embed/KKGQMXX?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true"> See the Pen <a href="https://codepen.io/nickhsine/pen/KKGQMXX"> Untitled</a> by nickhsine (<a href="https://codepen.io/nickhsine">@nickhsine</a>) on <a href="https://codepen.io">CodePen</a>. </iframe> ### 不同載具用不同圖片 當我們了解圖片的呈現方式和 Media Queries 後,我們可以組合這兩個技巧,讓瀏覽器在不同的螢幕大小,呈現不同的圖片。 #### 1. 使用 `background-image` ```css=false div.bg-size-cover { width: 100%; height: 400px; background-image: url('https://github.com/nickhsine/teach-at-nccu/raw/master/assets/images/image-1.jpg'); background-repeat: no-repeat; background-size: cover; background-position: center; } @media screen and (max-width: 600px) { div.bg-size-cover { background-image: url('https://github.com/nickhsine/teach-at-nccu/raw/master/assets/images/image-2.jpg'); } } ``` 當內容區塊小於600px後,會呈現另外一張圖片。 見圖8。 ![圖8](https://i.imgur.com/YLOMXiW.gif) *圖8:`background-image` 搭配 Media Queries,讓瀏覽器在不同大小時,載入不同的圖片。* #### 2. 使用 `<picture>` 搭配 `<source>` 除了使用 Background Image 搭配 Media Queries 之外,我們也可以使用 `<picutre>` 元素搭配 `<source>` 元素,來根據不同的條件載入不同的圖片。 ```htmlembedded=false <picture> <source media="(max-width:600px)" srcset="https://github.com/nickhsine/teach-at-nccu/raw/master/assets/images/image-2.jpg"> <img src="https://github.com/nickhsine/teach-at-nccu/raw/master/assets/images/image-1.jpg"> </picture> ``` 上述程式碼預設會載入`<img>` 元素。但當瀏覽器視窗小於 600px 時,瀏覽器會載入`<source media="(max-width:600px)">` 元素的圖片。 在 `<picture>` 裡,`<source>` 元素可以不只一個,因此我們可以針對不同的 Media 類型和Media 特徵,載入不同的圖片。 ### RWD 課堂練習: <!-- https://www.figma.com/file/hDxOKN9XajmZDAPKV0mSrT/course-practice-media-queries?node-id=0%3A1 --> https://www.figma.com/design/lCr3y28UIOLA0APFTVAJqT/course-practice-media-queries?t=c2sX69M0j9Jq702c-0 下載檔案: https://github.com/nickhsine/teach-at-nccu/raw/master/111-02/05-09/exercise.zip 下載範例檔案: https://github.com/nickhsine/teach-at-nccu/raw/master/110-02/05-03/exercises/2022-05-03-exercise-finish.zip ###### tags: `teach-at-nccu`, `css`, `html`