2014-03-13

Responsive Web Design

Responsive Web Design?

智慧型手機的興起讓瀏覽網頁的螢幕變小,但既有網頁多半是固定寬度,一開始手機瀏覽器都是將網頁縮小到可以放進那小小的螢幕裡,但是這種作法一點幫助也沒有,圖那麼小、文字那麼小,什麼都看不清楚,只能在那不斷的放大放大縮小縮小,頭都暈了,怎麼上網呢?

那為了手機另外做一個網站可以嗎?是不是只要有錢有時間就可以,其實不然,不只是建置的時間,還有維護的時間都要加倍,最大的問題是,給手機用的網頁寬度要設多少呢?桌機從七百多像素到將近一千像素都有(15吋到近30吋的螢幕),桌機小螢幕遇到大網頁挺多滑鼠拉一拉就好了,那手機呢?三吋、四吋、五吋到六吋的螢幕都有,甚至還有十幾吋的平板,這光是網頁寬度就訂不出來了,寬度訂小了,大螢幕很痛苦,訂的大了,小螢幕又沒滑鼠可以拉,這條路還走得下去嗎?

那有沒有可能一套網頁通吃呢?其實是有可能的,這就是 Responsive Web Design 的目的。

Responsive Web Design 組成

Responsive Web Design 由三種 CSS 技術組成:
  • Media Query
  • Fluid Layout
  • Flexible Images
從技術的名稱可以想像 Responsive Web Design 的內容,以 Media Query 決定使用不同的 Fluid Layout,並輔以不同的 Flexible Images

Media Query

Media Query 是 CSS 3 的新功能,直接來玩玩看。
<!DOCTYPE html>
<html>
<head>
<meta charset="BIG5">
<title>RWD</title>
<style type="text/css">
body {
  background-color: red;
}

@media screen and (max-width: 1200px) {
  body {
    background-color: orange;
  }
}

@media screen and (max-width: 960px) {
  body {
    background-color: yellow;
  }
}

@media screen and (max-width: 720px) {
  body {
    background-color: green;
  }
}

@media screen and (max-width: 600px) {
  body {
    background-color: blue;
  }
}

@media screen and (max-width: 480px) {
  body {
    background-color: indigo;
  }
}

@media screen and (max-width: 320px) {
  body {
    background-color: purple;
  }
}
</style>
</head>
<body>
</body>
</html>
可以得到以下的結果:
  • 寬度大於 1200 px,背景為紅色。
  • 寬度小於等於 1200 px,背景為橙色。
  • 寬度小於等於 960 px,背景為黃色。
  • 寬度小於等於 720 px,背景為綠色。
  • 寬度小於等於 600 px,背景為藍色。
  • 寬度小於等於 480 px,背景為靛色。
  • 寬度小於等於 320 px,背景為紫色。
目前瀏覽器都有一些快速改變瀏覽器大小的外掛可以用,例如 Chrome 可以用 Windows Resizer,真的不想裝外掛的話,可以用 jQuery 寫一隻簡單的 js 來用。

Media Type

前面用的語法可以拆成三部份:
  • @media:CSS 3 的 media query 語法,固定的。
  • screen:media type,有很多選項可以用,但一般只會用到 screen 與 print,挺多加一個 projection,詳情請見 CSS Media Types
  • (max-width: 320px):query 語法,用法如下。

Media Query 語法

可以用的語法如下,除了最後的 scan 和 grid,其他都可以加上 min- 或 max-:
  • width / height:Viewport 的寬度與高度,viewport 指的是瀏覽器顯示網頁內容的範圍,不是螢幕的大小。
  • device-width / device-height:螢幕的寬度與高度。
  • orientation:portrait 或 landscape。
  • aspect-ratio:Viewport 的寬高比,例如 16 比 9 的螢幕就是用 16/9。
  • device-aspect-ratio:螢幕的寬高比,餘同上。
  • color:不懂。
  • color-index:不懂。
  • monochrome:不懂。
  • resolution:不懂。
  • scan:不懂。
  • grid:不懂。

Fluid Layout

Fluid Layout 有很多名字,像是 Fluid Design、Elastic Layout、Rubber Layout、Liquid Design、Adaptive Layout、Cross-Device Design、Flexible Design,名字各異,目的都是一樣的。

網頁設計最早是用「比例」設計,比如說左邊欄寬度 20%,右邊內容欄寬度  80%,但是後來因為比例形成的網頁在不同大小的螢幕看起來不太一樣,慢慢的就轉成使用「固定寬度」的設計了,也就是不管是15吋螢幕或者22吋螢幕看到的網頁都是一樣的,缺點是15吋螢幕會有 scrollbar,而 22吋螢幕留白太多。

在 Responsive Web Design 的年代,比例設計又回來了!

Flexible Images

配合不同的 layout,顯示不同尺寸的圖片,或甚至在小螢幕省略某些圖片,簡單的作法是同一張圖進行頁面縮放,厲害的是後台直接餵給前台不同尺寸的圖片,前者是簡單做,但缺點是瀏覽器縮放圖片有時不漂亮,後者圖漂亮,但費工。

Top down or Bottom up?

到底要從最小的螢幕往上做呢?還是從最大的螢幕往下做?

從資料的重要性來看,就大螢幕而言,重要的資料或者說是主要的內容可以放在螢幕中間、左邊或右邊都沒問題,甚至上面還可以放一個大大的 header,也不會影響閱讀,但是就小螢幕而言就不是這麼一回事了,如果在手機上瀏覽網頁,每一頁都要先看過一串連結,才會到內文的話,使用者應該很快就逃走了。

因此在小螢幕上,最重要的資料要放在最前面,這常常是內文,然後才是相關連結,這和大螢幕的先連結再內文的作法南轅北轍,所以從這一點看來,應該要從小螢幕往上做。

RWD 第 0.5 版

v1.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="initial-scale=1.0,width=device-width" />
<title>RWD V.1</title>
<link rel="stylesheet" type="text/css" href="css/reset.css" />
<link rel="stylesheet" type="text/css" href="css/v1.css" />
</head>
<body>
  <div id="body">
    <div id="header">
      <div id="menu">
        <ul>
          <li><a href="javascript:; ">Menu 1</a></li>
          <li><a href="javascript:; ">Menu 2</a></li>
          <li><a href="javascript:; ">Menu 3</a></li>
          <li><a href="javascript:; ">Menu 4</a></li>
          <li><a href="javascript:; ">Menu 5</a></li>
        </ul>
      </div>
    </div>
    <div id="content">Content</div>
    <div id="submenu">Sub menu</div>
    <div id="footer">Footer</div>
  </div>
</body>
</html>
重點一:在 meta 裡設定 viewport,請各家瀏覽器不要自動縮放網頁。
重點二:使用 reset.css 將各家瀏覽器的預設值統一。
重點三:在 body 內另外加一個 div#body 來框住所有內容。
重點四:content 在 submenu 之前。

v1.css
body {
  background-color: #FFFFFF;
}

#body {
  margin: 0 auto;
  width: 960px;
}

#header {
  background-color: #468966;
  margin: 0 10px;
  padding: 10px;
  width: 920px; /* 920 + 10 * 2 + 10 * 2 = 960 */
}

#menu ul li {
  display: inline-block;
}

#content {
  background-color: #FFF0A5;
  float: right;
  margin: 0 10px 0 0;
  padding: 10px;
  width: 690px; /* 690 + 10 * 2 + 10 = 720 */
}

#submenu {
  background-color: #FFB03A;
  float: left;
  margin: 0 10px;
  padding: 10px;
  width: 200px; /* 200 + 10 * 2 + 10 * 2 = 240 */
}

#footer {
  background-color: #B64A26;
  clear: both;
  margin: 0 10px;
  padding: 10px;
  width: 920px; /* 920 + 10 * 2 + 10 * 2 = 960 */
}

@media screen and (max-width: 720px) {
  body {
    background-color: #666666;
  }
  #body {
    width: 720px;
  }
  #header {
    margin: 0 10px;
    padding: 10px;
    width: 680px; /* 680 + 10 * 2 + 10 * 2 = 720 */
  }
  #content {
    margin: 0 10px 0 0;
    padding: 10px;
    width: 530px; /* 530 + 10 * 2 + 10 = 560 */
  }
  #submenu {
    margin: 0 10px;
    padding: 10px;
    width: 120px; /* 120 + 10 * 2 + 10 * 2 = 160 */
  }
  #footer {
    margin: 0 10px;
    padding: 10px;
    width: 680px; /* 680 + 10 * 2 + 10 * 2 = 720 */
  }
}

@media screen and (max-width: 480px) {
  body {
    background-color: #000000;
  }
  #body {
    margin: 0 auto;
    width: 480px;
  }
  #header {
    margin: 0 5px;
    padding: 5px;
    width: 460px; /* 460 + 5 * 2 + 5 * 2 = 480 */
  }
  #content {
    margin: 0 5px;
    padding: 5px;
    width: 460px; /* 460 + 5 * 2 + 5 * 2 = 480 */
  }
  #submenu {
    margin: 0 5px;
    padding: 5px;
    width: 460px; /* 460 + 5 * 2 + 5 * 2 = 480 */
  }
  #footer {
    margin: 0 5px;
    padding: 5px;
    width: 460px; /* 460 + 5 * 2 + 5 * 2 = 480 */
  }
}
重點一:只求演練,所以先切成三種版型:960px、720px 與 480px。




第 0.5 版只套用 Responsive Web Design 的第一種技術,Media Query,所以有一個很大的問題,就是介於 960px 與 720px 之間,顯示的是有 scrollbar 的 960px 版型,720px 到 480px 之間也是一樣的問題,480px 以下也是。

這問題的元兇就是「固定寬度」,讓我們回到比例設計(Fluid Layout)吧。

RWD 第 0.9 版

v2.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="initial-scale=1.0,width=device-width" />
<title>RWD V.2</title>
<link rel="stylesheet" type="text/css" href="css/reset.css" />
<link rel="stylesheet" type="text/css" href="css/v2.css" />
</head>
<body>
  <div id="body">
    <div id="header">
      <div id="menu">
        <ul>
          <li><a href="javascript:; "><img class="menuIcon" src="img/1.png" />Menu 1</a></li>
          <li><a href="javascript:; "><img class="menuIcon" src="img/2.png" />Menu 2</a></li>
          <li><a href="javascript:; "><img class="menuIcon" src="img/3.png" />Menu 3</a></li>
          <li><a href="javascript:; "><img class="menuIcon" src="img/4.png" />Menu 4</a></li>
          <li><a href="javascript:; "><img class="menuIcon" src="img/5.png" />Menu 5</a></li>
        </ul>
      </div>
    </div>
    <div id="content">
      <div>Content</div>
      <img class="contentImg" src="img/1.jpg" />
    </div>
    <div id="submenu">Sub menu</div>
    <div id="footer">Footer</div>
  </div>
</body>
</html>
HTML 部份與 v1.html 大同小異,差別在於加了一些圖片來練習 Flexible Image。

v2.css
body {
  background-color: #FFFFFF;
}

img,object,video,embed {
  max-width: 100%; /* 隨著外層 block 物件縮放大小*/
}

#body {
  margin: 0 auto;
  width: 96%; /* 960px, 不要全滿比較好看 */
  font-size: 100%; /* font size reset */
  font-size: 16px;
  font-size: 1em;
  max-width: 1200px; /* 最大就是 1200px,超過就不再放大了 */
}

#header {
  background-color: #468966;
  margin: 0 1.041667%; /* 10 / 960 */
  padding: 1.041667%; /* 10 / 960 */
  width: 95.833333%; /* 920 / 960 */
}

#menu ul li {
  display: inline;
  /* 為了計算 #menu .menuIcon 的 width,只好從 inline-block 改成 inline */
  font-size: 1.5em; /* 24px / 16px */
}

#menu .menuIcon {
  width: 2.173913%; /* 20 / 920 */
}

#content {
  background-color: #FFF0A5;
  float: right;
  margin: 0 1.041667% 0 0; /* 10 / 960 */
  padding: 1.041667%; /* 10 / 960 */
  width: 71.875%; /* 690 / 960 */
}

#content .contentImg {
  width: 43.478261%; /* 300 / 690 */
  max-width: 300px; /* 有本事的話,可以從 Serve 依據不同的 viewport 餵給 web 不同大小的圖 */
}

#submenu {
  background-color: #FFB03A;
  float: left;
  margin: 0 1.041667%; /* 10 / 960 */
  padding: 1.041667%; /* 10 / 960 */
  width: 20.833333%; /* 200 / 960 */
  font-size: 1.25em; /* 20px / 16px */
}

#footer {
  background-color: #B64A26;
  clear: both;
  margin: 0 1.041667%; /* 10 / 960 */
  padding: 1.041667%; /* 10 / 960 */
  width: 95.833333%; /* 920 / 960 */
  font-size: 0.75em; /* 12px / 16px */
}

@media screen and (max-width: 720px) {
  body {
    background-color: #666666;
  }
  #body {
    width: 96%; /* 720px, 不要全滿比較好看 */
    font-size: 12px;
  }
  #header {
    margin: 0 1.388889%; /* 10 / 720 */
    padding: 1.388889%; /* 10 / 720 */
    width: 94.444444%; /* 680 / 720 */
  }
  #menu .menuIcon {
    width: 2.352941%; /* 16 / 680 */
  }
  #content {
    margin: 0 1.388889% 0 0; /* 10 / 720 */
    padding: 1.388889%; /* 10 / 720 */
    width: 73.611111%; /* 530 / 720 */
  }
  #content .contentImg {
    width: 37.735849%; /* 200 / 530 */
    max-width: 200px; /* 有本事的話,可以從 Serve 依據不同的 viewport 餵給 web 不同大小的圖 */
  }
  #submenu {
    margin: 0 1.388889%; /* 10 / 720 */
    padding: 1.388889%; /* 10 / 720 */
    width: 16.666667%; /* 120 / 720 */
  }
  #footer {
    margin: 0 1.388889%; /* 10 / 720 */
    padding: 1.388889%; /* 10 / 720 */
    width: 94.444444%; /* 680 / 720 */
  }
}

@media screen and (max-width: 480px) {
  body {
    background-color: #000000;
  }
  #body {
    width: 96%; /* 480px, 不要全滿比較好看 */
    font-size: 8px;
  }
  #header {
    margin: 0 1.041667%; /* 5 / 480 */
    padding: 1.041667%; /* 5 / 480 */
    width: 95.833333%; /* 460 / 480 */
  }
  #menu .menuIcon {
    width: 3.478261%; /* 16 / 460 */
  }
  #content {
    margin: 0 1.041667%; /* 5 / 480 */
    padding: 1.041667%; /* 5 / 480 */
    width: 95.833333%; /* 460 / 480 */
  }
  #content .contentImg {
    width: 21.739130%; /* 100 / 460 */
    max-width: 100px; /* 有本事的話,可以從 Serve 依據不同的 viewport 餵給 web 不同大小的圖 */
  }
  #submenu {
    margin: 0 1.041667%; /* 5 / 480 */
    padding: 1.041667%; /* 5 / 480 */
    width: 95.833333%; /* 460 / 480 */
  }
  #footer {
    margin: 0 1.041667%; /* 5 / 480 */
    padding: 1.041667%; /* 5 / 480 */
    width: 95.833333%; /* 460 / 480 */
  }
}
CSS 才是重點。

重點一:將 div#body 的寬度設為 96%,左右留一些空白,因為 body tag 設這種寬度沒作用,所以要另外加一個 div#body,比例是  Fluid Layout 的起點,從此不再出現 scrollbar。

重點二:在 div#body 將字型大小重設。

重點三:在 div#body 為 Fluid Layout 設下上限 max-width,讓網頁不會無限寬,有時候太寬也是挺醜的。

重點四:在 div#body 內的所有元件的 px 全部重算,計算公式如下:
原值 / 父值 = 新值 + %
以 header 的 width 為例,原值為 920px,父值為 div#body 的 960px,所以得到 95.833333,再加上百分比,就是 95.833333%。

有必要這麼多位小數嗎?四捨五入當然沒問題,但就怕有些地方,這邊多一點,那邊多一點,然後就破表了。

這裡要特別強調「父值不總是 960px」,如果今天 header 裡有另一個 div,假設寬度是 400 px,那這個 div 的寬度重算應為 400 / 920,這裡的 920 是 header 的寬度。

重點五:字型大小也要重算,公式同上,只是不是加上百分比,而是用 em。
原值 / 父值 = 新值 + em
em 是什麼?好像是一個 m 的大小吧。




相關筆記

Reset CSS
讓 IE8 認識 CSS Media Query 的 Respond.js
yepnope.js 讓瀏覽器只載入需要的檔案
More in yepnope 1.5.4
HTML5 與 CSS3 的偵測器 - Modernizr 2.7.1
---
---
---

7 則留言:

  1. Great post! I am see the programming coding and step by step execute the outputs.I am gather this coding more information. It's helpful for me my friend. Also great blog here with all of the valuable information you have.
    Selenium Training in Chennai

    回覆刪除

  2. i just go through your article it’s very interesting time just pass away by reading your article looking for more updates. Thank you for sharing.
    Best Devops Training Institute

    回覆刪除
  3. Well explanation with great coding knowledge. This blog gonna helpful to many. I am expecting these kind blogs in future too.
    AWS training in chennai | AWS training in annanagar | AWS training in omr | AWS training in porur | AWS training in tambaram | AWS training in velachery

    回覆刪除
  4. Very Nice Blog…Thanks for sharing this information with us. Here am sharing some information about training institute.
    devops online training in hyderabad

    回覆刪除
  5. Infycle Technologies offers the best Python training in Chennai for tech professionals and freshers with New year offers. In addition to the Python Training Course, Infycle also offers other technical courses such as Data Science, Oracle, Java, Power BI, Digital Marketing, Big Data, etc., which will be trained with complete practical classes. Dial 7504633633 to get more info and a free demo.

    回覆刪除
  6. Grab the Oracle Training in Chennai from Infycle Technologies the best software training and placement center in Chennai which is providing technical software courses such as Data Science, Artificial Intelligence, Cyber Security, Big Data, Java, Hadoop, Selenium, Android, and iOS Development, DevOps, etc with 100% hands-on practical training.

    回覆刪除