Web Design

Chapter 3   Responsive Web Design

∗ Web design

▸ In the early stage

✶ Users viewed the web pages using desktop or laptop computers
✶ The width of a web is fixed such that it looks the same for all sizes of screens
✶ There are blanks on the left and right side

▸ Recently

✶ A lot of users viewed the web pages using mobile devices (mobile phones and tablets)
✶ Displaying traditional web pages on mobile devices has many problems

▸ Solution: responsive web design

✶ The page adjusts its layout according to different viewport sizes
# Viewport: a region in the browser where information is displayed, excluding the browser menu, url field, toolbar, bookmarks, and tabs
# The size of the viewport is different from that of the screen
✶ Note: server-side has nothing to do with responsive web design the design does not affect the server-side scripting; hance can be changed any time

(1) Responsive web design

∗ Problems using mobile devices to view traditional web pages

▸ Uers need to zoom in/out to see information clearly

▸ If data extends too wide, users have to scroll left and right

Scrolling up and down on mobile devices is common and simple; however, scrolling left and right is very inconvinient

▸ Buttons or links may be too small to be correctly clicked

▸ Solution: adjusting the page layout according to the features of the device, e.g.:

✶ In a small viewport: move unimportant elements below more important ones
✶ In a worse case: hide some information, or turn that info. into a link
✶ Adjust the navigation buttons such that their sizes are suitable for finger clicking
✶ Scale the sizes of block elements such that the page is readable
✶ Adjust the page properly such that users don't need to scroll left and right

∗ The origin of the "responsive web"

▸ In 2010, Ethan Marcotte proposed this idea in his article titled "Responsive Web Design"

▸ "Responsive web design" integrates the following techniques:

✶ Flexible grid layouts
✶ Flexible images
✶ Media and media queries

▸ Other names: fluid design, elastic layout, rubber layout, liquid design, adaptive layout, cross-device design, and flexible design

(2) Example of reponsive web design

dConstruct 2011

▸ The viewport width is greater than 1350px

1350

▸ Viewport width less than 960px: image grids change

960

▸ Viewport width less than 720px: the links become small icons such that users may correctly click them; in addition, the dark green region moves from right to top

720

▸ Viewport width less than 480px: image grids change again

480

▸ Viewport width less than 320px: image sizes change

320

(3) Media query

▸ One of CSS3's modules, it is used to query the media typoes in order to adjust CSS styles

▸ Media features: viewport width, screen aspect ratio, landscape/portrait orientation, ...

∗ Example: change the background according to media query results

bgChange.html

<!doctype html>
<html>
<head>
<title>Browser background changer</title>
<meta charset="utf-8">
<link rel="stylesheet" href="css/bgChange.css">
</head>
<body>
</body>
</html>

bgChange.css

body {
  background-color: gray;
}

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

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

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

▸ The background color changes as the viewport width changes

@media screen: the page is shown in a screen (other options: all, speech, print)
max-width: maximum width

▸ CSS3 determins it styles according to the device's capability or features

✶ If the bowser features match the condition, apply the appropriate style; otherwise, do not apply it
✶ E.g.: load different style sheets according the various conditions
<link rel="stylesheet" media="screen and (orientation: portrait)" href="portrait-screen.css">
# There are two questions in the above: (1) is it a screen? (2) is the orientation portrait? If both answers are yes, load portrait-screen.css
✶ May addd logical operation not
<link rel="stylesheet" media="not screen and (orientation: portrait)" href="portrait-screen.css">
✶ May chain multiple conditions
<link rel="stylesheet" media="screen and (orientation: portrait) and (min-width: 800px)" href="800wide-portrait-screen.css">

∗ Media features

▸ Features commonly queried: viewport width (width) and screen width (device-width)

▸ Features:

width: viewport width
height: viewport height
device-width: screen width
device-height: screen height
orientation: screen orientation
aspect-ratio: viewport aspect ratio (e.g.: aspect-ratio: 16/9)
device-aspect-ratio: screen aspect ratio
color: number of bits per color component (e.g., min-color: 16 )
color-index: number of entries in the color lookup table
monochrome: bits per pixel in the monochrome frame buffer
resolution: pixel density (e.g., min-resolution: 300dpi)
scan: scanning process (progressive or interlace), e.g., 720p HDTV scan: progressive, 1080i HD TV scan: interlace
grid: types of the device, grid or bitmap

▸ May add minmax in front of the above features, except scan and grid, e.g., <link rel="stylesheet" media="screen and (min-width:200px) and (max-width:360px)" href="phone.css">

(4) Example: responsive navigation

▸ Adjust the arrangement of navigation buttons according to the viewport width (Original article):

✶ 1 row 3 rows, 2 columns 3 rows, 2 colunms with the pull-down button 6 rows, 1 column with the pull-down button
nav3
nav4
nav6
nav7

∗ Create the HTML file

nav.html

<!doctype html>
<html>
<head>
<title>Responsive navigation</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="css/nav.css">
</head>
<body>

<nav>
  <a id="pull" href="#"><img src="img/nav-icon.png"></a>
  <ul>
    <li><a href="#">Main page</a></li>
    <li><a href="#">How</a></li>
    <li><a href="#">Icons</a></li>
    <li><a href="#">Design</a></li>
    <li><a href="#">Web 2.0</a></li>
    <li><a href="#">Tools</a></li>
  </ul>
</nav>

<h3>Viewport</h3>
<p>width: <span id="width"></span></p>
<p>height: <span id="height"></span></p>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="js/screenSize.js"></script>
<script src="js/nav.js"></script>
</body>
</html>

▸ Add <meta name="viewport" content=...> in <head> to scale the page for various viewport widths

✶ May add multiple settings in content=..., e.g., the page for the 320px viewport: <meta name="viewport" content="width=320">
✶ Common settings: content="width=device-width, initial-scale=1, maximum-scale=1"
# The viewport width equals the screen width: width=device-width
# Initially, the scale of the page is the original scale: initial-scale=1
# Preventing users from zooming: maximum-scale=1

▸ There are <ul> and <li> buttons in the <nav> block and <a id="pull" ... > is the pull-down button with the image nav-icon.png nav-icon

<h3>Viewport</h3>: display the viewport size

▸ Finally, add JavaScripts before </body>

screenSize.js: show the viewport size
nav.js: menu toggling

∗ Script to display the viewport size

▸ Create the js sub-directory and create file screenSize.js in it for displaying the viewport size:

$(document).ready(function() {

  var $window = $(window);
  
  showViewportSize();
  $window.resize(function() {
    showViewportSize();
  });

  function showViewportSize() {
    $('#width').text($window.width());
    $('#height').text($window.height());
  }

});
nav

∗ CSS:

nav.css

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
  background-color: lightgray;
}

nav ul {
  margin: 0;
  padding: 0;
  overflow: auto;    /* Prevent from collpase */
  background-color: #485463;
}

nav li {
  list-style: none;
  width: 90px;
  float: left;
}

▸ Set the styles for body and nav:

box-sizing: all box sizes include borders
body: no margin or padding, background color
nav ul: no margin or padding, overflow to prevent from collaps, background color
nav li: no list style, fixed width, float left such that <li> blocks flow from left to right

▸ Result:

nav2

▸ Set the link styles

...

nav li {
  ...
}

nav a {
  display: block;
  color: white;
  font-weight: bold;
  text-decoration: none;
  padding: 0.8em 0;
  width: 100%;
  text-align: center;
  border-right: 2px solid #576979; 
}

nav li:last-child a {
  border-right: none;
}

nav a:hover {
  background-color: #8c99a4;
}

a#pull {
  display: none;
}
nav a: displayed as a block, white texts, boldface, no decoration, top and bottom paddings, 100% width, center align, right border, with hover effect
✶ Hide a#pull

▸ Result:

nav3

∗ Design responsive navigation using media queries and JavaScripts

▸ Create viewport thresholds: minimum width of 6 button is 540px (6×90); hence, this is the first threshold

...

a#pull {
  display: none;
}

@media screen and (max-width: 540px) {
  nav li {
    width: 50%;
  }
  
  nav a {
    border-bottom: 1px solid #576979;
    border-right: 1px solid #576979;
    text-align: left;
    text-indent: 30px;
  }
}
nav li 50% width: two buttons in a row
nav a: right and bottom borders, left align, indentation

▸ Result:

nav4

▸ The second threshold is set to be480px

...

@media screen and (max-width: 540px) {
  ...
}

@media screen and (max-width: 480px) {
  nav ul {
    display: none;
  }

  a#pull {
    display: block;
    background-color: #283744;
  }
}
✶ Hide nav ul
✶ Show a#pull (display: block;) and set the background color

▸ Result:

nav5

▸ Write jQuery scripts:

nav.js
$(document).ready(function() {

  var $menu = $('nav ul');
  
  $(document).on('click', '#pull', function() {
    $menu.slideToggle();
    return false;
  });

});

▸ Result:

nav6

▸ The third threshold is set to be 360px

...

@media screen and (max-width: 480px) {
  ...
}

@media screen and (max-width : 360px) {
  nav li {
    width: 100%;
  }
}
✶ 100% button width: one button in a row

▸ Result:

nav7

(5) Example: "And the winner isn't ..."

∗ Create the following page

Reference

theWinnerIsNot

∗ Layout related elements:

▸ Wrapper, header, navigation, sidebar, content, footer

structure

∗ HTML:

oscar3-1.html

<!doctype html>
<html>
<head>
<title>And the winner isn't ...</title>
<meta charset="utf-8">
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/oscar3-1.css">
</head>
<body>

<div id="wrapper">

<header>
  <p>And the winner isn't ...</p>
  <nav>
    <ul>
      <li><a href="#">WHY?</a></li>
      <li><a href="#">ABOUT</a></li>
      <li><a href="#">OFFLINE</a></li>
      <li><a href="#">REDEMPTION</a></li>
      <li><a href="#">VIDEOS/CLIPS</a></li>
      <li><a href="#">QUIZ</a></li>
      <div style="clear: both;"></div>
    </ul>
  </nav>
</header>

<aside>
  <p>UNSUNG HEROS ...</p>
  <p>OVERHYPED NONSENSE ...</p>
</aside>

<div id="content">
  <p>EVERY YEAR WHEN I WATCH THE OSCARS I'M ANNOYED ...</p>
  <p>that films like King Kong, Moulin Rouge and Munich get the statue
    whilst the real cinematic heroes lose out. Not very Hollywood is it?</p>
  <p>We’re here to put things right.</p>
  <p>These should have won <span>&raquo;</span></p>
</div>  <!-- content -->

<footer>
  <p>NOTE: OUR OPINION IS ABSOLUTELY CORRECT. YOU ARE WRONG, EVEN IF
    YOU THINK YOU ARE RIGHT. THAT’S A FACT. DEAL WITH IT.</p>
</footer>

</div>  <!-- wrapper -->

</body>
</html>

∗ CSS:

oscar3-1.css

* {
  box-sizing: border-box;
  margin: 0;
}

body {
  padding: 0;
}

/* Wrapper */
div#wrapper {
  width: 960px;
  margin: 0 auto;
  background-color: #ddddff;
}

/* Header */
header {
  padding: 20px;
  background-color: #779307;
}

/* Navigation */
nav {
  padding: 20px 0;
}

nav li {
  list-style: none;
  float: left;
}

nav li a {
  display: block;
  color: black;
  padding: 10px 20px;
  text-decoration: none;
}

/* Aside */
aside {
  float: left;
  width: 260px;
  margin-top: 50px;
  padding: 20px;
  background-color: #fe9c00;
}

/* Content */
div#content {
  float: left;
  width: 700px;
  margin-top: 50px;
  padding: 20px;  
  background-color: #dedede;
}

/* Footer */
footer {
  clear: both;
  margin-top: 20px;
  padding: 20px;
  background-color: #996600;
}

▸ Layout and navigation settings (Color every block for identification)

✶ All elements: box-sizing: border-box; margin: 0;
body: no padding
#wrapper: width 960px, align center
header: padding
nav: padding, display <li> as navigation link
aside: float left, width 240px, top margin, padding
#content: float left, width 720px, top margin, padding
footer: clear both, top margin, padding

▸ Result:

theWinnerIsNotStructure

∗ Images should be efficient

▸ The flags on the top and bottom page should use repeated elements (as below), and add padding and double horizon borders to header and footer

buntingFW buntingFWinvert

▸ Exercise: save oscar3-1.html and oscar3-1.css as oscar3-2.html and oscar3-2.css, respectively, and modify as follows:

oscar3-2.html
...
<link rel="stylesheet" href="css/oscar3-2.css">
...
oscar3-2.css
/* Header */
header {
  padding: 20px;
  padding: 60px 20px 20px 20px;
  border-bottom: 4px double #bfbfbf;
  background-image: url("../img/buntingFW.png");
  background-repeat: repeat-x;
  background-color: #779307;
}

/* Footer */
footer {
  ...
  padding: 20px;
  padding: 20px 20px 60px 20px;
  border-top: 4px double #bfbfbf;
  background-image: url("../img/buntingFWinvert.png");
  background-repeat: repeat-x;
  background-position: 0 bottom;
  background-color: #996600;
}
✶ Result:
theWinnerIsNotStructure2

∗ Setting font types and image styles

▸ Exercise: save oscar3-2.html and oscar3-2.css as oscar3-3.html and oscar3-3.css, and modify as follows:

oscar3-3.html:
<link rel="stylesheet" href="css/oscar3-3.css">
✶ Set the styles and links of "The winner isn't ...":
<p id="logo"><a href="/">And the winner <span>isn't ... </span></a></p>
oscar3-3.css:
/* Header */
header {
  ...
}

/* Logo */
p#logo {
  font-size: 3em;
}

p#logo a {
  text-decoration: none;
}

p#logo span {
  color: lightgray;
}

/* Navigation */
...

▸ Set styles for the side bar:

✶ In the HTML: add the following elements and poster images
<aside>
  <h1>UNSUNG HEROS ...</h1>
  <a href="#"><img class="poster" src="img/midnightRun.jpg" alt="midnightRun"></a>
  <a href="#"><img class="poster" src="img/wyattEarp.jpg" alt="wyattEarp"></a>
  <br>
  <h1>OVERHYPED NONSENSE ...</h1>
  <a href="#"><img class="poster" src="img/moulinRouge.jpg" alt="moulinRouge"></a>
  <a href="#"><img class="poster" src="img/kingKong.jpg" alt="kingKong"></a>
</aside>
# Poster images:
midnightRun.jpg   wyattEarp.jpg   moulinRouge.jpg   kingKong.jpg
✶ CSS: 在 aside 之後加上字體及影像尺寸之設定
/* Aside */
aside {
  ...
}

aside h1 {
  font-size: 1.2em;
}

aside img.poster {
  width: 90px;
  height: 120px;
}

/* Content */
...

▸ Set the style of #content:

✶ Add the trophy image, let the text flow around it, and set font styles
<div id="conten"t>
  <img id="oscar" src="img/oscar.png" alt="Oscar statue">
  <h1>EVERY YEAR<span>WHEN I WATCH THE OSCARS I'M ANNOYED ...</span></h1>
  <p>that films like <b>King Kong</b>, <b>Moulin Rouge</b>, and <b>Munich</b>
  get the statue whilst the real cinematic heroes lose out. Not very
  Hollywood is it?</p>
  <p>We’re here to put things right.</p>
  <p><a href="#">These should have won <span>»</span></a></p>
  <div style="clear: both"></div>
</div>
# Oscar statue image
oscar
✶ CSS: set the styles of h1 tag and the image:
/* Content */
div#content {
  ...
}

div#content h1 {
  font-size: 3em;
}

div#content h1 span {
  display: block;
  color: #757474;
  font-size: 0.6em;
}

div#content img#oscar {
  float: left;
  margin-top: -50px;
  width: 200px;
}
✶ Result:
isnot

▸ When the viewport width is less than 960px, contents on the right will be truncated

(4) Dynamic layout

∗ Overwrite the default viewport settings

▸ iOS and Android browsers are based on Webkit, and they allow the <meta> tag (in <head>) to set the defaults, e.g.:

✶ Fixed or scaled width: viewport width equals screen width, and the page is scaled twice initially
<meta name="viewport" content="initial-scale=2.0, width=device-width">
✶ Users may scale the page, form 0.5 to 3 times
<meta name="viewport" content="width=device-width, maximum-scale=3, minimum-scale=0.5">
✶ Scaling not allowed:
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">

∗ Layout change using media queries

▸ Exercise: save oscar3-3.html and oscar3-3.css as oscar3-4.html and oscar3-4.css, respectively, and modify as follows

▸ HTML:

✶ Update the CSS link
<link rel="stylesheet" href="css/oscar3-4.css">
✶ Set a fixed page size and disallow scaling: add the following to <head>
<meta name="viewport" content="initial-scale=1.0, width=device-width, user-scalable=no">

▸ CSS: remove all the background colors

▸ Responsive design

✶ Idea: in a small viewport, more important information should appear first; hence, #content should come before aside
# HTML: swap #content and aside
...

<div id="content">
  ...
</div>

<aside>
  ...
</aside>

...
# In a larger viewport, aside would be on the right and #content on the left
Solution: flow #content to the right
/* Content */
div#content {
  float: right;
  ...
}
✶ Add one media query: at 800px, #wrapper width 800px, #content no flow and width 100%
/* Footer */
footer {
  ...
}

/* Responsive design */
/* At 800px */
@media screen and (max-width: 800px) {
  div#wrapper {
    width: 800px;
  }
  
  div#content {
    float: none;
    width: 100%;
  }
}
aside: set no flow, and the posters flow form left to right
# HTML: make two h1 blocks in order that the texts in aside align center; also add an id to the first h1 for setting left and right margins
...

<aside>
<h1 id="first">
<p>UNSUNG HEROS ...</p>
<a href="#"><img class="poster" src="img/midnightRun.jpg" alt="midnightRun"></a>
<a href="#"><img class="poster" src="img/wyattEarp.jpg" alt="wyattEarp"></a>
</h1>
<h1>
<p>OVERHYPED NONSENSE ...</p>
<a href="#"><img class="poster" src="img/moulinRouge.jpg" alt="moulinRouge"></a>
<a href="#"><img class="poster" src="img/kingKong.jpg" alt="kingKong"></a>
</h1>
</aside>
# CSS: aside width 100% and no flow, h1 inline-block, first h1 with right margin, enlarge poster sizes
/* Responsive design */
/* At 800px */
@media screen and (max-width: 800px) {
  ...

  div#content {
    ...
  }
  
  aside {
    float: none;
    width: 100%;
    text-align: center;
  }
  
  aside h1 {
    display: inline-block;
  }
  
  aside h1#first {
    margin-right: 50px;
  }
  
  aside img.poster {
    width: 120px;
    height: 180px;
  }
}
✶ Test: because the oscar statue image is too taller than content, it has reach out to the <aside> element. Solution: add clearance such that content contains the image
<div id=content>
  ...
  <p>These should have won <span>»</span></p>
  <div style="clear:both"></div>
</div> <!--content -->
✶ Result:
isnot2

∗ Does media query solve all the problems? No!

▸ Currently, the viewport thresholds are not enough; the viewport will be truncated if its width is lower than 800px. This also happens when the viewport width is within 800px ~ 960px

▸ The cause of the problem: when the viewport reaches a threshold, the page layou would change; however, when the viewport is between two threshold it stays still

▸ Solution: replace the fixed layout with a fluid layout