《响应式Web设计实践》学习笔记

来源:互联网 发布:手机淘宝天猫客服 编辑:程序博客网 时间:2024/06/05 18:01
第1章 无处不在的Web
1.4  成为响应式的
Ethan Marcotte利用三种已有工具:媒介查询(media queries)、流动布局(fluid grids)和自适应图片(scalable images)创建了一个在不同分辨率屏幕下都能漂亮地显示的站点。
设备无关:所有的东西(组件、布局等)都能与不同类型的设备和平台相兼容。
“未来友好宣言”,http://futurefriend.ly
激光般专注:我们需要专注于那些对客户和业务来说,最最重要的事。
以数据为中心:以下面这些方式来定义数据:多样(灵活)的访问和通知途径、通过标准来协作、侧重于长期的完整性、包含有意义的且永久的内容引用、支持读写操作。
通用内容:机构良好的内容现在已经成为了网站里必需的一部分。
识别未知的船:一个高级且足够准确的设备种类数据库能够帮助我们简化适应设备差异的过程。
领导你的舰队:当我们通过设备集合来管理单独设备上的体验时,单个设备便可以以自己最擅长的方式来处理交互了。
渐进增强:先从一个基本的体验开始,然后使用流动布局和媒介查询这些技术来为功能更多、屏幕更大的设备增强使用体验。
第2章 流动布局
2.1.2  流动布局
在流动布局中,度量的单位不再是像素,而是变成了百分比。
2.1.3  弹性布局
通常情况下,在弹性布局中会以em来作为单位。1em相当于当前字体的大小。
大量研究表明,理想的阅读文本的行宽介于45到70个字符之间,利用弹性布局,你可以将容器的宽度设定为55em。
2.2  字体大小
2.2.1  像素
使用像素作为字体大小的单位,是与Web的灵活性原则背道而驰的做法。
2.2.2  em
2.2.3 百分比
2.2.4  rem
rem与em的区别在于:rem的大小与根元素-HTML元素-有关。
但移动平台还不支持rem
span {
font-size: 16px;
font-size: 1rem;  /* 支持rem的浏览器将会使用rem声明,因为它是在后面声明的,而不支持rem的浏览器将会使用第一条声明,并忽略rem声明 */
}
2.2.6  从像素转换
body {
font-size: 16px;
}
h1 {
font-size: 16px;
}
span {
font-size: 12px;
}
从px转换为em: 目标 / 上下文环境 = 结果
body {
font-size: 100%l;  /* 大部分浏览器默认字体为16px */
}
h1 {
font-size: 1.5em;  /*24px / 16px */
}
span {
font-size: .5em; /* 12px / 24px, 上下文环境为h1 24px */
}
2.3  网格布局
网格使信息的展示变得有序、新颖、和谐。
网格使得用户能够预测该从哪里获得信息,这在信息交流过程中很有帮助。
在与原始总体设想相一致的前提下,网格使添加新的内容更为容易。
网格能在设计单一解决方案时促进合作,而不必对总体设想的解决方案妥协。
2.3.1  从内容出发
2.3.2  设置网格 
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;  /* 通过使用box-sizing: border-box, 你可以让浏览器将padding的值算在已经定义好的元素宽度内部 */
#container {
width: 95%;
padding: .625em 1.0548523% 1.5em;  /* 10px / 16px, 10px / 948px, 24px / 16px,顶部和底部的padding值是由font-size的大小决定的,所以使用em。 */
aside img,
.main img,
.slats img {
width: 100%;  /* 让图片填满整个边栏 */
max-width: 100%; /* 不让图片的大小超过它的容器元素 */
}
表2.1  与表格相关的display值
相应元素 相应元素
table TABLE table-column COL
table-row TR table-column-group COLGROUP
table-row-group TBODYtable-cellTD, TH
table-header-group THEADtable-captionCAPTION
table-footer-group TFOOT
.main {
display: table-cell;
}
aside {
display: table-cell;
width: 300px;
}
<!—[if (lt IE 8) & (!IEMobile)]>
<link rel=”stylesheet” href=”/css/ie.css” media=”all”>
<!—[endif]-->  /* 条件注释,IE8之前版本的IE(出去Windows Phone 7) 都会加载ie.css */
第3章 媒体查询
iPhone的布局视口为980px, Opera Mobile为850px, Android WebKit为800px。
3.1.2  视口标签和属性
<meta name=”viewport” content=”directive,directive” />
<meta name=”viewport” content=”width=device-width” />  // 将视口宽度设置为设备屏幕的宽度
<meta name=”viewport” content=”height=device-height” />  // 将视口高度设置为设备屏幕高度
<meta name=”viewport” content=”user-scalable=yes” />  // 允许用户在页面上进行缩放
<meta name=”viewport” content=”initial-scale=1, width=device-width” />  // 设置页面初始化时的缩放层级
@viewport {
width: device-width;
}  // 在CSS中将视口设置为设备宽度
3.2  媒介查询结构
一般形式:
@media [not|only] type [and] (expr) {
rules
}
3.3  内嵌样式与外部样式
@media screen and (min-width: 1300px) {
a {
text-decoration: underline;
}
} // 内嵌样式,当屏幕大于等于1300px时,链接有下划线
<link href=”style.css” media=”only screen and (min-width: 1300px)” /> //  外部样式
3.4  媒介查询顺序
3.4.1  从桌面端向下设计
/* base styles */
@media all and (max-width: 768px) {

}
@media all and (max-width: 320px) {

}
3.4.2  从移动端向上设计
/* base styles, for the small-screen experience, go here */
@media all and (min-width: 320px) {

}
@media all and (min-width: 768px) {

}
例如:
@media all and (min-width: 320px) {
aside {
display: table-cell;
width: 300px;
}
}
3.5  创建核心体验
把所有与布局相关的css都移到样式表的底部,并注释掉它们。
3.6  确定断点
3.6.1  追随内容
@media all and (min-width: 600px) { /* 当屏幕大于等于600px时,使slats中li并排排列 */
.slats li {
float: left;
margin-right: 2.5316%; /* 24px / 948px */
width: 31.6455696%; /* 300px / 948px */
}
.slats li:last-child {
margin-right: 0;
}
}
@media all and (min-width: 860px) { 当屏幕大于860px时,让aside浮动,使其成为两行 */
aside {
display: block;
margin-bottom: 1em;
padding: 0 1%;
width: auto;
}
aside section {
float: left;
margin-right: 2%;
width: 28%;
}
.article-tags {
clear: both; /* 清除左右两边浮动 */
}
.ad {
text-align: center;
padding-top: 2.5em;
}
}
@media all and (min-width: 860px) { /* 让导航栏排成一行 */

nav[role=”navigation”] li {
float: left;
border-top: 0;
}
nav[role=”navigation”] a {
float: left;
}
footer[role=”contentinfo”] .top {
float: right;
}
}
@media all and (min-width: 940px) { /* 当浏览器被拉伸到940px时,使aside不再浮动,且放到右侧 */
.main {
display: table-cell;
padding-right: 2.5316456%; /* 24px / 948px */
}
aside {
display: table-cell;
width: 300px;
}
aside img {
max-width: 100%;
}
aside section {
float: none;
width: 100%;
}
}
@media all and (min-width: 1300px) { /* 大屏幕时使用多列布局 */
.main section {
-moz-column-count: 2; /* Firefox */
-webkit-column-count: 2; /* Safari, Chrome */
column-count: 2; /* 2列布局 */
-moz-column-gap: 1.5em; /* Firefox */
-webkit-column-gap: 1.5em; /* Safari, Chrome */
column-gap: 1.5em; /* 间隔24px */
-moz-column-rule: 1px dotted #ccc; /* Firefox */
-webkit-column-rule: 1px dotted #ccc; /* Safari, Chrome */
column-rule: 1px dotted #ccc; /* 浅灰色点状线分隔 */
}
}
3.6.3  使用em为媒介查询增加灵活性
@media all and (min-width: 37.5em) { /* 600px / 16px = 37.5em */

}
@media all and (min-width: 53.75em) { /* 860px /16px = 53.75em */

}
3.7  导航栏
 <a href=”#nav” class=”nav-collapse” id=”nav-collapse”>Menu</a>
<ul class=”nav” id=”nav”>
#nav-collapse {
display: none;
color: #fff;
text-align: right;
width: 100%;
padding: .625em 0 .625em 0;
}
#nav-collapse.active {
display: block;
}
window.onload = function() {
var collapse = document.getElementById(‘nav-collapse’);
var nav = document.getElementById(‘nav’);
// toggle class utility function
function classToggle( element, tclass) { // 检查element是否有类名tclass,如果有就删除,如果没有就添加
var classes = element.className,
pattern = new RegExp( tclass );
var hasClass = pattern.test( classes );
//toggle the class
classes = hasClass ? classes.replace( pattern, ‘’ ) : 
classes + ‘ ‘ + tclass;
element.className = classes.trim();
};
classToggle(nav, ‘hide’);
classToggle(collapse, ‘active’);
collapse.onclick = function() {
classToggle(nav, ‘hide’);
return false;
}
}
使用JavaScript来检查导航条目有没有浮动,并基于此来运行代码。
var Utils = {
classToggle : function( element, tclass ) {

}
}
window.onload = function() {
var nav = document.getElementById(‘nav’);
var navItem = nav.getElementsByTagName( ‘li’ );
// is it floated?
var floated = navItem[0].currentStyle ? navItem[0].currentStyle[‘float’] : 
document.defaultView.getComputedStyle(navItem[0], null).
getPropertyValue(‘float’); // style只能获取到元素的内联样式,内部样式和外部样式则不能获取;currentStyle可以获取内部样式和外部样式,但只适用IE;getComputedStyle同currentStyle,适用于FF, opera, safari, chrome
if( floated != ‘left’ ) {
var collapse = document.getElementById( ‘nav-collapse’ );
Utils.classToggle(nav, ‘hide’ );
Utils.classToggle(collapse, ‘active’ );
collapse.onclick = function() {
Utils.classToggle(nav, ‘hide’ );
return false;
}
}
}
3.8  对IE的支持
IE 9 之前的版本IE不支持媒介查询
<!- - [if (lt IE 9) & (! IEMobile)]>
<link rel=”stylesheet” href=”/css/ie.css” media=”all”>
<![endif]- ->
第4章 响应式多媒体
4.2  有选择地为手机提供图片
<ul class=”slats”>
<li data-src=”images/ball.jpg” class=”group”> <!- - data-是自定义属性,用于JS - ->
<a href=”#”>
<h3>Kicker connects on record 13 field goals</h3>
</a>
</li>
<li data-src=”images/goal_post.jpg” class=”group”>
<a href=”#”>
<h3>Your favorite team loses to that team no one likes</h3>
</a>
</li>
<li data-src=”images/ball_field.jpg” class=”group”>
<a href=”#”>
<h3>The Scarecrows Win 42-0</h3>
</a>
</li>
</ul>
4.2.1 JavaScript
q : function(query) {  // 选取元素的函数
if(document.querySelectorAll) {
var res = document.querySelectorAll(query);
}
else { //IE7不支持querySelectorAll
var d = document,
a = d.styleSheets[0] || d.createStyleSheet();
a.addRule(query,’f:b’);
for(var l=d.all, b=0, c=[], f=l.length; b < f; b++) {
l[b].currentStylef && c.push(l[b]);
a.removeRule(0);
var res = c;
}
}
return res;
}
// load in the images
var lazy = Utils.q(‘[data-src]’);
for (var I = 0; i < lazy.legth; i++) {
var source = lazy[i].getAttribute(‘data-src’);
// create the image
var img = new Image();
img.src = source;
// insert it inside of the link
lazy[i].insertBefore(img, lazy[i].firstChild);
};
4.2.2  matchMedia介绍
matchMedia()会返回一个MediaQueryList对象,该对象有两个属性:matches和media,matches属性的值是true或false,media属性的值就是传递的参数。
if ( window.matchMedia(“(min-width: 37.5em)”).matches) {
//load in the images
var lazy = Utils.q(‘[data-src]’);
for ( var i = 0; i < lazy.length; i++) {
var source = lazy[i].getAttribute(‘data-src’);
//create the image
var img = new Image();
img.src = source;
// insert it inside of the link
lazy[i].insertBefore(img, lazy[i].firstChild);
};
}
4.3  响应式图片策略
据说世界上其实只有7个故事,另外其余的故事只不过是以不同的方式来讲述的罢了。
4.3.1  和浏览器比赛
4.3.2  默许浏览器的行为
4.3.3 找服务器帮忙
4.4  响应式图片的实现方法
4.4.1  Sencha.io Src
4.4.2  自适应图片
响应式图片的未来如何?
Jason Grigsby在开头处便一语中的:为了提高性能,浏览器希望在知道页面的布局前,就尽可能快地加载网页;但另一方面开发者们却要依靠他们关于页面布局的知识,来确定要下载哪张图片。
4.5  背景图片
@media all and (min-width: 53.75em) { // 屏幕宽度大于53.75em时加载背景图片
header[role=banner] .inner {
background: url(‘../images/football_bg.png’) bottom right no-repeat;
}
}
4.6  高分辨率屏幕
@media only screen and (-webkit-min-device-pixel-ratio: 2),  /* 基于WebKit的浏览器,使用-webkit-min-device-pixel-ratio查询像素比,基于非WebKit的浏览器,使用min-resolution查询
only screen and (min-resolution: 2dppx) {
header[role=”banner”] .inner {
background: url(‘../images/football_bg_highres.png’)
bottom right no-repeat;
}
}
SVG
4.7  其他固定宽度的内容
4.7.1  视频
video { /* 使用HTML5视频标签 */
max-width: 100%;
height: auto;
}
<div class=”div-wrapper”>
<iframe></iframe> <!—将视频放入iframe -->
</div>
.vid-wrapper {
width: 100%;
position: relative;
padding-bottom: 56.25%; /* 视频比例为16:9, 9/16 */
height: 0;
}
.vid-wrapper iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
<a id=”video” href=http://www.youtobe.com/watch?v=HwbE3bPvzr4>Video highlights</a> /* 小屏幕时显示连接 */
.video { /* video样式 */
display: block;
padding: .3em;
margin-bottom: 1em;
background: url(../images/video.png) 5px center no-repeat #e3e0d9;
padding-left: 35px;
border: 1px solid rgb(175, 175, 175);
color: #333;
}
getEmbed : function(url) {
var output = ‘’;
var youtubeUrl = url.match(/watch\?v=([a-zA-Z0-9\-_]+)/);
var vimeoUrl = url.match(/^http:\/\/(www\.)?vimeo\.com\/(clip\:)?(\d+.*$/);
if(youtubeUrl) {
output = ‘<div class=”vid-wrapper”><iframe src=http://www.youtube.com/embed/’ + youtubeUrl[1] +’?rel=0 frameborder=”0” allowfullscreen></iframe></div>’;
return output;
} else if(vimeoUrl) {
output = ‘<div class=”vid-wrapper”><iframe src=http://player.vimeo.com/video/’ + vimeoUrl[3] + ‘ frameborder=”0”></iframe></div>’;
return output;
}
}
// 在matchMedia(“(min-width:37.5em)”)中,大屏时将链接改为嵌入视频
var videoLink = document.getElementById(‘video’);
if(videoLink) {
var linkHref = videoLink.getAttribute(‘href’);
var result = Utils.getEmbed(linkHref);
var parent = videoLink.parentNode;
parent.innerHTML = result + parent.innerHTML;
parent.removeChild(document.getElementById(‘video’));
第5章 计划
第6章 设计流程 
第7章 响应式内容
科技会发展,标准会进化,但是内容-它们的目的、意义、结构、关系以及价值-需要被人们所理解的需求将不会改变。
<section class=”related”> <!—小屏时只显示一个基本链接 -->
<a href=”headlines.html” data-target=”related” id=”lazy”>View the latest headlines</a>
</section>
anchorInclude : function(elem) { // 将链接转换为嵌入内容
var url = elem.getAttribute(‘href’);
var target = document.getElementById(elem.getAttribute(‘data-target’));
reqwest(url, function(resp) { // 使用reqwest.js库
target.innerHTML = resp;
});
}
var lazyLink = document.getElementById(‘lazy’);
if(window.matchMedia(“(min-width: 37.5em)”).matches) {
Utils.anchorInclude(lazyLink); // 大屏时(大于600px)将链接转换为嵌入内容
} else {
lazyLink.onclick = function() { // 小屏时(小于600px)单击链接嵌入链接内容
Utils.anchorInclude(this);
return false;
}
}
第8章 RESS
抱怨工具的木匠不是好木匠。
RESS:响应式设计和服务器端组件
8.1  用户代理检测
设备检测库WURFL和DeviceAtlas
8.2  功能检测
return !!window.JSON; // 检测设备是否原生支持JSON
Modernizr
服务端Modernizr modernizr-server
var Utils = {
createCookie : function(name, value, days) {
if(days) {
var date = new Date();
date.setTime(date.getTime() + (dayd*24*60*60*1000));
var expires = “; expires =” + date.toGMTString();
}
else {
var expire = “”;
}
document.cookie = name + “=” + value + expires + “; path=/”;
},
readCookie : function(name) {
var nameEQ = name + “+”;
var ca = document.cookie.split(‘;’);
for(var i = 0; i < ca.length; i++) {
var c = ca[i];
while(c.charAt(0) == ‘ ‘) {
c = c.substring(1, c.length);
}
if(c.indexOf(nameEQ) == 0) {
return c.substring(nameEQ.length, c.length);
}
};
return null;
},
tests : {
getWidth : function() {
return  (window.innerWidth > 0) ? window.innerWidth : screen.width; // window.innerWidth获取浏览器宽度,但IE8不支持;screen.width获取屏幕宽度 
}
}
}
var features = {};
if(Utils.readCookie(‘features’)) { // 测试cookie是否存在
features = Utils.readCookie(‘features’);
features = JSON.parse(features);
} else { // 检测宽度,存储cookie
features[‘width’] = Utils.tests.getWidth();
Utils.createCookie(‘features’, JSON.stringify(features));
}
第9章 响应式体验
不断变化,即是未来。
 9.4.2  API
地理位置API
<div id=”results”></div>
<span id=”arrow”>&#8593;</span>
var results = document.getElementById(‘results’);
if(navigator.geolocation) { // 检测是否支持地理定位
navigator.geolocation.getCurrentPosition(function(pos) { 
alert(pos.coords.latitude); // 显示用户当前位置
alert(pos.coords.longitude);
results.innerHTML += “<p>Only “ + calculateDistance(pos.coords.latitude, pos.coords.longitude, lambeau.lat, lambeau.long)  + “ miles from hallowed Lambeau Field.</p>”; // 计算用户距离lambeau球场多远
var bearing = calculateBearing(pos.coords.latitude, pos.coords.longitude, lambeau.lat, lambeau.long); // 计算方位
var arrow = document.getElementById(‘arrow’); // 旋转指针
arrow.style.transform = ‘rotateZ(‘ + bearing + ‘deg)’;
arrow.style.msTransform = ‘rotateZ(‘ + bearing + ‘deg)’;
arrow.style.mozTransform = ‘rotateZ(‘ + bearing + ‘deg)’;
arrow.style.webkitTransform = ‘rotateZ(‘ + bearing + ‘deg)’;
}, function(error) {
alert(‘Whoops! Error code: ‘ + error.code);
});
} else {
alert(‘Bummer – looks like there is no geolocation support.’);
}
// 计算用户距离lambeau球场多远
var lambeau = {
‘lat’ : 44.5013805,
‘long’ : -88.062325
}
function calculateDistance(lat1, lon1, lat2, lon2) { // 计算经纬度之间的距离
var R = 3959; // miles
var dLat = (lat2 – lat1).toRad();
var dLon = (lon2 – lon1).toRad();
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 -  a));
var d = R * c;
return d;
}
Number.prototype.toRad = function() {
return this * Math.PI / 180;
}
function calculateBearing(lat1, lon1, lat2, lon2) {
return Math.atan2(
Math.sin(lon2 – lon1) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) – Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 – lon1)) * 180 / Math.PI;
}
媒介捕获API
用getUserMedia访问设备摄像头和麦克风
<meta name=”viewport” content=”width=device-width” />
<video id=”myVid” width=”300” height=”375” autoplay></video>
<input id=”camera” type=”button” disabled=”true” value=”Take Photo”></input>
<canvas id=”still” width=”300” height=”375”></canvas>
navigator.getUserMedia({video : true}, function(stream) {
var video = document.getElementById(“video”);
var video = document.getElementById(“still”);
var canvas = document.getElementById(“camera”);
video.src = stream;
button.disabled = false;
button.onclick = function(){
canvas.getContext(“2d”).drawImage(video, 0, 0);
};
}, function(err) {
alert(“there was an error “ + err);
});
设备API
Contacts API, Messaging API, Calendar API, Battery Status API, Vibration API, Sensor API, HTML Media Capture, Web Intents


----个人广告----
本人符江涛,17年6月硕士毕业,热爱编程,目前在找工作,熟悉领域:全栈开发,项目经验:母鸡行网站http://www.destpact.com,微信:jiangtao95zy,qq:1321332562
0 0
原创粉丝点击