# RWD響應式設計指南
> **響應式網頁的設計目的是為了在不同視窗大小的裝置上,減少使用者平移、縮放和捲動等操作行為**
不論是桌面電腦或行動裝置,使用者通常都習慣以**垂直滾動**的方式瀏覽網頁,而不是水平式的移動,因此當網頁的排版設計迫使使用者需要水平移動或縮小才能看到所有資訊時,會導致使用者體驗變差。
在設計時應避免介面上的資訊或圖片寬度大於螢幕寬度,讓使用者能輕易的垂直滾動瀏覽。當圖片大於界面寬度,可以把`max-width`設為`100%`。
```javascript=
{
maxWidth: 100%,
display: 'block',
}
```
## 斷點 breakpoint
為了在不同大小的裝置上呈現最好的排版,網頁在縮放時會根據斷點去變化元件布局。
一般常見斷點的選擇有以下:
1. 在600/900/1200/1800設置斷點,基本上能符合大部分人的裝置
2. bootstrap的斷點是320/480/768/1024
3. 只需設計桌面版和手機版兩種,其他的響應規則與工程師溝通好就好,例如圖片大小或間隔要依照比例放大縮小或是設置最大寬度。
### 從小螢幕開始,斷點最佳化
在不參考一般斷點的情況下,響應式設計會先從**小尺寸**的螢幕開始發想設計。
首先設計好小螢幕的排版後,將螢幕尺寸慢慢拉大,直到畫面中的空白過大或是排版設計不好看,這時就是設置斷點的時候了,設計師可以重新思考網頁元件的布局,或是增加網頁需要的訊息和功能。
這麼做的好處是可以優化斷點的設置,讓斷點個數最小化。
>**不一定要幾個裝置就幾個斷點,因為裝置的尺寸只會越來越多,而是因應自己的設計在什麼大小需要改變才能有更好的排版方式去設定斷點。**
## 響應式設計要訣
### 訂定區塊重要性
將網頁上的內容分成不同區塊,並依重要性排序,接著從最小介面開始設計,依序安排到介面上,也就是說**最小介面的內容都是最核心的元素**。
當介面放大有更多空間時,再將次要的區塊安排上去,而內容發生改變時,設計師也要思考內容在不同介面上實際的呈現,並調整成最佳的布局方式,例如:從多欄位的寬視窗轉變至單欄位的窄視窗是 RWD 典型的特徵。
![](https://i.imgur.com/u44XTgQ.jpg)
>**當空間有限時,必須減少非至關重要的內容,專注於真正重要的元素和功能。**
### 網站優化 - 圖片品質vs.網頁下載速度
設計師利用高畫質的圖片吸引使用者的目光時,網頁也需要花費更多時間去下載。設計師必須在精美的視覺呈現和網頁速率中取得平衡。
>**積極的移除不必要的內容,優化保留下來的元素。**
### 善用icons
在空間有限的介面中,適當的使用icons能取代冗長的文字。
**icons通常SVG檔案格式上傳**,SVG(可縮放向量圖形)檔案的優點是圖案在縮放時都不會失真,檔案大小也不因圖像大小改變。
### 留意字體大小
注意字體的設計在各個尺寸的裝置上,都能維持想營造的整體感覺。例如:細體字在字型夠大時能清楚閱讀,但字型縮小時可能不夠清晰,降低網頁的易讀性,因此要確認所有文字在最小尺寸的裝置上,仍可以清楚的閱讀。
### 考慮輸入方式
電腦和手機或平板最大的差異在於點擊的方式,手機使用者用手指點擊可能無法像用滑鼠和鍵盤一樣方便,因此在按鈕或表格的設計上要注意使用者是否能方便、有效的點擊和輸入,**注意不同裝置的使用者操作方式的差異**。
## 表格 Table
將大螢幕的表格轉換到小螢幕上呈現時,可以用**破壞原本表格排版**和**不使用Table實作Table**的方向思考。
以下提供四種[Table在RWD的解決方案](https://www.ctkpro.com/blog/fine-table-in-rwd/):
1. 擠壓(Squish):
將每個欄位的寬度縮短至符合裝置寬度
2. 滾動(Scroll):
不改變表格寬度大小,讓使用者以左右滾動方式查看表格
3. 摺疊橫列(Collapse Rows):
破壞原本表格排版,刪除表頭,改以類似 list 的方式分別呈現每一筆資料
4. 摺疊直行(Collapse Columns)
*Collapse Example*
![](https://i.imgur.com/8PWYHhD.png)
# Material-UI 實作 RWD 用法
###### tags: @mui v5.0.6
常用於 RWD布局的 components有:
- [Grid](https://mui.com/zh/components/grid/)
- [Container](https://mui.com/zh/components/container/)
- [Breakpoint](https://mui.com/zh/customization/breakpoints/#main-content)
- [useMediaQuery](https://mui.com/zh/components/use-media-query/)
### RWD 實作步驟
1. 設定viewport,瀏覽網頁時瀏覽器顯示畫面內容的區域。(可見***響應式元標記*** )
2. 決定RWD設計模式。(可參考[五種常用的響應式設計模式](https://developers.google.com/web/fundamentals/design-and-ux/responsive/patterns?hl=zh-tw))
4. 套用 CSS Media Query。(可見***Media Query***)
5. 使用相對單位設定寬高、大小。
`width: 50%`、`width: 100vh`、`height: 80vh`、`font-size: 2em`, etc.
## 響應式元標記(meta tag)
Material-UI 是先在移動裝置上開發的,採用了先為移動裝置編寫程式碼,然後根據需要使用 CSS media queries(CSS媒體查詢)擴展組件的策略。 如要確保所有裝置的正確渲染和觸摸縮放,請將響應式可視區域(viewport)的元標記加到`<head>`元素中。
```html=
<meta name="viewport" content="initial-scale=1, width=device-width" />
```
`<meta>`tag可以讓瀏覽器知道如何控制網頁的尺寸和縮放,`width=device-width`讓網頁能依設備獨立像素(DIP)去適應螢幕的寬度。
## 斷點 Breakpoint
### 預設斷點
- `xs`: 0px
- `sm`: 600px
- `md`: 900px
- `lg`: 1200px
- `xl`: 1536px
### 自訂斷點
在`theme`中設定自訂斷點
- `theme.breakpoint.value`: `key`為螢幕的名字,可以任何方式命名;`value`是斷點開始的最小寬度。
```javascript=
const theme = createTheme({
breakpoint:{
value:{
mobile: 0,
tablet: 600,
laptop: 1024,
desktop: 1200,
},
unit: 'px',
breakpoint: 5, //0.05px
},
})
```
## Media Queries
Media Queries代表網頁會先詢問(Query)媒體(Media)的屬性,若媒體條件符合為true,就會套用樣式。
### CSS Media Queries
Demo Code :
```javascript=
const styles = (theme) => ({
root: {
padding: theme.spacing(1),
[theme.breakpoints.down('md')]: {
backgroundColor: theme.palette.secondary.main,
},
[theme.breakpoints.up('md')]: {
backgroundColor: theme.palette.primary.main,
},
[theme.breakpoints.up('lg')]: {
backgroundColor: green[500],
},
},
});
```
提供四個API方式
- `key`(string | number): 可以是breakpoint key ('sm','md','mobile'),或螢幕大小(px)
- `media query`: 一個媒體查詢字符串
`theme.breadpoints.up(key) => media query`: 當前螢幕寬度大於(包含)`key`給出的螢幕尺寸
```css=
/*match[md, ∞)
[900px, ∞)*/
[theme.breakpoints.up('md')]:{
backgroundColor: red,
},
```
`theme.breadpoints.down(key) => media query`: 當前螢幕寬度小於(包含)`key`給出的螢幕尺寸
```css=
/*match[0, md)
[900px, ∞)*/
[theme.breakpoints.down('md')]:{
backgroundColor: red,
},
```
`theme.breadpoints.only(key) => media query`: 當前螢幕寬度符合`key`給出的螢幕尺寸
```css=
/*match[md, md+1)
[md, lg)
[900px, 1200px)*/
[theme.breakpoints.only('md')]:{
backgroundColor: red,
},
```
`theme.breadpoints.between(start,end) => media query`: 當前螢幕寬度大於`start`給出的螢幕尺寸且小於`end`給出的螢幕尺寸
```css=
/* match[sm, md)
[600px, 900px)*/
[theme.breakpoints.between('sm','md')]:{
backgroundColor: red,
},
```
### JavaScript Media Queries
透過 Media queries hook監聽使用者正在使用的螢幕大小,根據查詢結果是否符合來渲染物件。
`useMediaQuery(query,[options]) = matches`
- `query`(string | function): 傳入media query,或是`theme`的callback function
1. 傳入媒體查詢的字符串(media query)作為參數
```javascript=
import * as React from 'react';
import useMediaQuery from '@mui/material/useMediaQuery';
export default function SimpleMediaQuery() {
const matches = useMediaQuery('(min-width:600px)');
//matches = bool
return <span>{`(min-width:600px) matches: ${matches}`}</span>;
}
```
2. 傳入 Material-UI的斷點輔助功能
```javascript=
import { useTheme } from '@material-ui/core/styles';
import useMediaQuery from '@material-ui/core/useMediaQuery';
function MyComponent() {
const theme = useTheme();
const matches = useMediaQuery(theme.breakpoints.up('sm'));
//matches = bool
return <span>{`theme.breakpoints.up('sm') matches: ${matches}`}</span>;
}
```
3. 傳入`theme`的callback function
```javascript=
import useMediaQuery from '@material-ui/core/useMediaQuery';
function MyComponent() {
const matches = useMediaQuery((theme) => theme.breakpoints.up('sm'));
return <span>{`theme.breakpoints.up('sm') matches: ${matches}`}</span>;
}
```
- `options`(object): [optional]
1. `options.defaultMatches`(bool): 當`window.matchMedia`不可用時,第一次mount回傳的的預設值。預設值是`false`
2. `options.matchMedia`(func)
3. `options.noSsr`(bool): 預設值是`false`。如果是需要渲染服務端的話就設為`true`。
4. `options.ssrMatchMedia`(func)
# Verification RWD實作規劃
用 useMediaQuery回傳的 matches值判斷是否顯示mobile的介面
```javascript=
import useMediaQuery from '@material-ui/core/useMediaQuery';
import { useTheme } from '@material-ui/core/styles';
function VerificationPage(){
const theme = useTheme()
const matches = useMediaQuery(theme.breakpoint.down('md'))
return(
{matches && <VerificationMobile />}
)
}
```
![](https://i.imgur.com/4jjs9c1.png)
```javascript=
<List className={classes.paper}>
<ListItem>
<ListItemAvatar>
<Avatar className={classes.verifyPass}>
<img src={CheckIcon} alt="verifyPassIcon" height="20" />
</Avatar>
</ListItemAvatar>
<ListItemText primary={fileName} secondary=`${timestamp}•${proofName}` />
<ListItemSecondaryAction>
<IconButton edge="end" aria-label="expand-more">
<MoreHorizIcon />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
</List>
```
![](https://i.imgur.com/ZYuSWBR.png)
# RWD網頁範例精選
- [RWD JP](https://responsive-jp.com/)
- [Media Queri](https://mediaqueri.es/)
# Reference
- https://medium.com/@king40105/%E8%A3%BD%E4%BD%9Crwd%E7%B6%B2%E9%A0%81%E6%99%82%E8%A6%81%E6%B3%A8%E6%84%8F%E7%9A%84%E4%BA%8B-330e78700b10
- https://web.dev/responsive-web-design-basics/#breakpoints
- https://medium.com/uiux-cafe/%E9%9F%BF%E6%87%89%E5%BC%8F%E7%B6%B2%E7%AB%99-rwd-%E8%A8%AD%E8%A8%88%E6%8C%87%E5%8D%97-%E7%B2%BE%E9%81%B8%E6%94%B6%E9%8C%84-70ba84fab05
- https://mui.com/zh/customization/breakpoints/
- https://tw.alphacamp.co/blog/rwd-responsive-web-design-introduction
- https://developers.google.com/web/fundamentals/design-and-ux/responsive/patterns?hl=zh-tw