响应式设计笔记

by Liu Yue/2017-02-21
HTML 4和CSS 2目前支持为不同的媒体类型设定专有的样式表。比如,一个页面在屏幕上显示时使用无衬线字体,而在打印时则使用衬线字体。screen和print是两种已定义的媒体类型。媒体查询让样式表有更强的针对性,扩展了媒体类型的功能。

下面的css是应用在宽度小于等于960px的屏幕上:

@media screen and (max-width: 960px) { 
    body { background-color: red; } 
此外,可以通过标签的media属性为样式表指定设备类型(如显示屏或打印机)。具体说来,就是在HTML页面的标签中插入一个如下面代码片段所示的link标签:

<link rel="stylesheet" type="text/css" media="screen" href="screen-styles.css"> 
媒体查询还能使我们根据设备的各种功能特性来设定相应的样式,而不仅仅只针对设备类型:

<link rel="stylesheet" media="screen and (orientation: portrait) and (min-width: 800px), projection" href="800wide-portrait-screen.css" /> 
这里有两点需要注意。第一,媒体查询之间使用逗号分隔。第二,你会注意到在projection之后,没有and,也没有任何特性/值的组合。没有后续表达式,意味着只要是projection就满足条件。本例中,样式会应用于所有的投影仪。

可以在CSS样式表中使用媒体查询。例如,将下面的代码插入样式表,在屏幕宽度小于等于400像素的设备上,h1元素的文字颜色就会变成绿色:

@media screen and (max-device-width: 400px) { 
    h1 { color: green } 
还可以使用CSS的@import指令在当前样式表中按条件引入其他样式表。例如下面的代码会给视口最大宽度为360像素的显示屏设备加载一个名为phone.css的样式表。

@import url("phone.css") screen and (max-width:360px); 
切记,使用CSS的@import方式会增加HTTP请求(这会影响加载速度),所以请谨慎使用该方法。

Viewport来帮忙
iOS上的Safari浏览器默认是在980像素宽的画布上渲染页面,然后将画布缩小到与视口大小匹配。虽然得放大页面才能看清楚,但页面内容没有被切掉。怎么阻止Safari或其他移动浏览器做这样的默认处理呢?

可以用viewport meta元素覆盖默认的画布缩放设置。只需要在HTML的标签中插入一个标签。标签中可以设置具体的宽度(如像素值)或者缩放比例如2.0(设备实际尺寸的两倍)。下面是一个将页面放大到设备实际尺寸两倍显示的meta标签的示例:

<meta name="viewport" content="initial-scale=2.0,width=device-width" /> 
在窄小的屏幕中,应该让设备用户首先看到主内容,而后再看到侧边栏。

媒体查询的不足
媒体查询尽其所能,根据设备特性应用了对应的样式。但问题是,例子中的媒体查询只覆盖了小范围的视口。针对各种视口的排列组合编写对应的CSS样式,无法兼容未来可能出现的设备;而一个完美的设计,往往能在一定程度上适应未来的发展。

因此,我们认识到,光靠媒体查询只能为我们提供自适应设计效果,不能真正实现响应式设计。

二、弹性布局
使用百分比布局创建流动的弹性界面,同时使用媒体查询来限制元素的变动范围。将这两者组合到一起构成了响应式设计的核心,基于此可以创造出真正完美的设计。

百分比尽可能精确,你可能认为在样式表中输入诸如.550724这样的数字很愚蠢。你可能也会疑惑,为什么不将这些小数四舍五入?但支持者们认为,这样做可以提供更加精确的结果。为浏览器提供更加精确的结果可以使其显示效果更加精准。

用em替换px
网页设计师使用em替代px主要是为了文字缩放。因为老版本的Internet Explorer无法缩放像素单位的文字。不过现代浏览器很久以前就支持缩放以像素为单位的文字了。那用em替换px还有什么必要性或优越性呢?

em的实际大小是相对于其上下文的字体大小而言的。如果我们给标签设置文字大小为100%,给其他文字都使用相对单位em,那这些文字都会受body上的初始声明的影响。

@media screen and (min-width: 1001px) and (max-width: 1080px) { 
    #navigation ul li a { font-size: 1.4em; } 
@media screen and (min-width: 805px) and (max-width: 1000px) { 
    #navigation ul li a { font-size: 1.25em; } 
@media screen and (min-width: 769px) and (max-width: 804px) { 
    #navigation ul li a { font-size: 1.1em; } 
根据视口宽度来改变文字大小,这是媒体查询和流动布局和谐共存的又一证据:媒体查询约束流动布局的变动范围,而流动布局则简化了从一组媒体查询样式过渡到另一组的改变过程。

弹性图片
在现代浏览器(包括IE 7+)中要实现图片随着流动布局相应缩放非常简单。只需在CSS中作如下声明:

img { max-width: 100%; } 
img,object,video,embed { max-width: 100%; } 
此外,也可以给弹性图片设置阈值,防止缩放过度:

img { 
    width: 28.9398281%; /* 698 ÷ 202 */ 
    max-width: 202px; 
CSS网格系统
人们对CSS网格系统/框架的看法褒贬不一,有人夸赞它,有人咒骂它。制作网站的时候,你必须要确保有一个系统化、结构合理的布局使得能够更快更轻松的组织网站的内容。网格系统为网页设计师们提供了一种快速构造网页内容布局的方法。借助这个工具,设计师可以根据预制结构进行布局,节省了大量的时间和精力。

下面是一些对响应式设计提供了不同程度支持的CSS框架: Semantic (http://semantic.gs); Skeleton (http://getskeleton.com); Less Framework (http://lessframework.com); 1140 CSS Grid (http://cssgrid.net); Columnal (http://www.columnal.com)。

上面的这些方法,一直使用的是HTML 4.01标签。响应式设计的“移动优先”思想要求它要用最简洁、最有效和最具语义的代码。还可使用HTML5+CSS3来做,这里就不展开了。可以使用Modernizr框架,向缺少HTML5或CSS3支持的浏览器页面中打补丁。

三、Modernizr
Modernizr是一个用于检测浏览器功能的开源JS库。除了能让IE支持HTML5新元素之外,它还能够基于一系列特性测试来有条件地加载更高级的腻子脚本(polyfill)、CSS文件以及额外的JavaScript文件。

腻子脚本(polyfill)这个词由Remy Sharp提出,意指使用腻子来补平老版本浏览器的缺陷。因此,腻子脚本具体指的是一段能给老版本浏览器带来新特性的JavaScript代码。

Modernizr的js文件执行之后,会在html标签上附加一系列class,它表示当前浏览器对HTML5或CSS3的特性的支持情况。

<html class="js no-flexbox canvas canvastext webgl no-touch geolocation postmessage no-websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients no-cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers applicationcache svg inlinesvg smil svgclippaths">
这样,就能做一定的降级,如:

body {
    background: url(background-top.png) top left no-repeat;
}
.multiplebgs body {
    background: url(background-top.png) top left no-repeat,
    url(background-bottom.png) bottom left repeat-x;
}
在下载的时候,将yepnop.js引入,Modernizr还能根据浏览器特性做到按需加载(根据浏览器特性来加载polyfill):

Modernizr.load({
    test: Modernizr.canvas,
    //yep:  '',
    nope: 'excanvas.js', 
    //both: '' 
});
上面代码就是当浏览器不支持canvas的话,就加在excanvas.js脚本,从而在低版本的IE中也能实现canvas。

也可以使用到我们上面提到的媒体查询来按需加载:

Modernizr.load({
    test:Modernizr.mq('only screen and (max-width:600px)'),
    yep:'a.js',
    nope:'b.js'
});