领略前端技术 阅读奇舞周刊

第21~24期（2013-09-23）

奇舞周刊（21~24期）

第21期

1. 理解作用域和上下文在JavaScript
再次深入重温下 Javascript 中的作用域和上下文基础概念。

2. 专门针对初学者的Node.js教程
Node.js的教程并不缺乏，但有大部分教程针对已有Node.js基础的开发者。以下教程是专门针对Node.js初学者，文中将通过实例分享，一步步教你如何开始Node.js之旅。英文地址

3. 使用 CSS 和 DataURI 来添加杂色滤镜效果
用 CSS + DataURI 来实现给 HTML 元素添加杂色效果，可以在不增加 HTTP 请求的情况下，实现不错的效果。英文地址

4. 3D Shading with Box-Shadows
CSS 3的魅力不在于其本身，而是它能激发前端更多的创造力！

5. URL锚点HTML定位技术机制、应用与问题
鑫旭在文中深入探究了锚点的原理和使用，给出了一个非常漂亮的slider的例子。

6. 浏览器开发工具的秘密
devtoolsecrets.com的全站翻译版。用好开发工具往往能事半功倍，推荐大家都看看~

第22期

1. JavaScript与有限状态机
有限状态机（Finite-state machine）是一个非常有用的模型，可以模拟世界上大部分事物。使用有限状态机可以使逻辑清晰，表达力强，有利于封装事件。

2. Semantic CSS With Intelligent Selectors--使用智能选择器语义化CSS
重构必读，虽然有点长，可以放着慢慢看。

3. CSS3的calc()使用
calc()对大家来说，或许很陌生，不太会相信calc()是css中的部分。因为看其外表像个函数，既然是函数为何又出现在CSS中呢？

4. Sass 的新特性调查
Sass 3.3 版本正在开发当中，本文对新版做了一些调查和猜想。英文地址请戳这里

5. HTML5 的 Web Storage
Web Storage 是 HTML5 API 提供的一个新的重要特性，以 Key-Value 的形式来进行数据持久存储。

6. HTML5 的 progress 元素详解
progress 标签定义运行中的进度。

7. 教你用 Bootstrap 建立响应式网站
使用 Bootstrap 很容易就可以建立响应式网站。

8. 前端工程师面试问题列表
常见的一些面试题，还是比较有意思的。

第23期

1. Starting to Write CSS
开始写CSS吧！~桥都马得！你可以试着这样写~ 中文版

2. CSS3单边阴影
阴影还能只有一边？~

3. Javascript in WSH
用javascript搞定windows shell~~

4. JavaScript 的性能优化：加载和执行
本文详细介绍了如何正确的加载和执行 JavaScript 代码，从而提高其在浏览器中的性能。

5. 【翻译】解读ECMAScript 6箭头函数
箭头函数是ECMAScript 6最受关注的更新内容之一。它引入一种屌爆了的“箭头”(=>) 这样对函数定义的新语法。原文

6. 【翻译】行高的相关计算——文档节选
原文

7. Bootstrap 3 网格系统简介
Bootstrap 3 Grid 入门，简单易学！中文地址

8. The iOS 7 Design Cheat Sheet
IOS开发必备常识

9. Google Chrome中的高性能网络(一)
系列二、 系列三

10. 当浏览器邂逅小数值
各浏览器对于计算后宽度和高度为含有小数的长度值时，其最终值会不一致?~

第24期

1. CSS属性选择器驱动的过滤搜索技术
使用CSS来做按条件搜索，很好玩的思路，而且速度比用JavaScript快！英语原文：Client-side full-text search in CSS

2. CSS3 3D Transformations: backface-visibility
使用CSS做3D翻转时处理不好‘背面’问题（就是附图中的问题）的小伙伴们，这篇文章可以一次性治愈

3. [原创]Flash新版本11.8上传文件时中文名显示乱码问题解决方案
针对最近 flashplayer升级导致上传的文件中文名显示乱码给出解决方案。

4. [译]为后代选择器和ID选择器而辩护
作者认为使用ID和后代选择器没有任何问题，只要你正确运用（表达语义、表达结构、不滥用）。英语原文：In Defense of Descendant Selectors and ID Elements

5. [译]使用HTML、CSS和JavaScript实现iOS7原生组件
本文记录了作者使用WebApp实现iOS7原生组件的方案及一些思考探究的过程。原文在这里：Cloning the UI of iOS 7 with HTML, CSS and JavaScript

6. [译] 自定义元素 – 在 HTML 中定义新元素
自定义元素为我们提供了一个工具，通过它我们可以扩展 HTML 的词汇，赋予它新的特性，并把不同的 web 平台连接在一起。结合其他新的基本平台，如 Shadow DOM 和模板，我们领略了 web 组件的宏伟蓝图。标记语言将再次变得很时髦！

7. HTML5 的 IndexedDB
Indexed Database (IndexedDB)，是一项强大的数据持久技术，是 HTML5 标准的一部分。

8. 字符编码的前世今生
本文跟随历史的足迹讲述了字符编码的演化过程，以及和前端相关的各种编码。

9. 针对长列表的AngularJS性能调优
AnglarJS在处理包含复杂数据结构的大型列表时，会出现运行速度慢的情况。该如何解决？本文给出了7条AngularJS性能调优的建议。英文原文最后给出的链接也很有参考价值。

10. 相似图片搜索的原理（二）
相似图片搜索的原理，这个深了哈。阮老师的作品。之前还有 第一篇。

11. 前端们需要了解的图像压缩技术
图像压缩是当前的热门话题。本文从起因、历史、技术等各方面带你探索不同的图像优化、压缩技术。

理解作用域和上下文在JavaScript

JavaScript’s implementation of scope and context is unique to the language because it is so flexible. Functions can be adopted for various contexts and scope can be encapsulated and preserved. These concepts lend to some of the most powerful design patterns JavaScript has to offer. However, this is also a tremendous source of confusion amongst developers, and for good reason. The following is a comprehensive explanation of scope and context, the difference between them, and how various design patterns make use of them.

Context vs. Scope

The first important thing to clear up is that context and scope are not the same. I have noticed many developers over the years often confuse the two terms, incorrectly describing one for the other. To be fair, the terminology has become quite muddled over the years.

Every function invocation has both a scope and a context associated with it. Fundamentally, scope is function-based while context is object-based. In other words, scope pertains to the variable access of a function when it is invoked and is unique to each invocation. Context is always the value of the this keyword which is a reference to the object that “owns” the currently executing code.

Variable Scope

A variable can be defined in either local or global scope, which establishes the variables’ accessibility from different scopes during runtime. Any defined global variable, meaning any variable declared outside of a function body will live throughout the browser session and can be accessed and altered in any scope. Local variables exist only within the function body of which they are defined and will have a different scope for every call of that function. There it is subject for value assignment, retrieval, and manipulation only within that call and is not accessible outside of that scope.

JavaScript presently does not support block scope which is the ability to define a variable to the scope of an if statement, switch statement, for loop, or while loop. This means the variable will not be accessible outside the opening and closing curly braces of the block. Currently any defined variables inside a block are accessible outside the block. However, this is soon to change, the let keyword has officially been added to the ES6 specification. It can be used alternatively to the var keyword and supports the declaration of block scope local variables.

What is “this” Context

Context is most often determined by how a function is invoked. When a function is called as a method of an object, this is set to the object the method is called on:

var object = {
a: 1,
b: 2,
add: function(){
alert(this.a + this.b);
}
};
object.add(); // 3

When called as an unbound function, this will default to the global context or window object in the browser. However, if the function is executed in strict mode, the context will default to undefined.

Execution Context and Scope Chain

JavaScript is a single threaded language, meaning only one thing can be done at a time in the browser. When the JavaScript interpreter initially executes code, it first enters into a global execution context by default. Each invocation of a function from this point on will result in the creation of a new execution context that is appended to the top of what is called a scope chain, somethings referred to as an execution or call stack. The browser will always execute the current execution context that is atop the scope chain. Once completed, it will be removed from the top of the stack and control will return to the execution context below in the current scope chain.

Name conflicts amongst variables between different execution contexts are resolved by climbing up the scope chain, moving locally to globally. This means that local variables with the same name as variables higher up the scope chain take precedence. For example:

function first(){
var a = 1;
second();
function second(){
third();
function third(){
var a = 3;
fourth();
function fourth(){
// do something
}
}
}
}
first();

Running the preceeding code will result in the nested functions being executed all the way down to the fourth function. At this point the scope chain would be, from top to bottom, fourth, third, second, first, global. The fourth function would have access to global variables and any variables defined with the first, second, and third functions as well as the functions themselves. You may also notice a naming conflict between the a variable defined in the first function and the a variable defined in the third function. Here the value of a will be 3 because the execution context from which it was defined is higher up the scope chain and therefore takes priority.

The global execution context will remain at the bottom of the scope chain for the duration of runtime. This is because you cannot return or exit from the global execution context, attempting to do so will result in a syntax error. This is why global variables are always available to every execution context.

The Variable/Activation Object

An execution context can be divided into a creation and execution phase. In the creation phase, the interpreter will first create a variable object that is composed of all the variables, function declarations, and arguments defined inside the function. From there the scope chain is initialized next, and the value of this is determined last. Then in the execution phase, code is interpreted and executed.

When the execution context is initially created for the global code, the global object is used as the variable object. This is precisely why variables and functions defined globally become properties of the global object. Likewise, any properties added to the window object will become global variables, capable of being referenced without a dot notation:

var a = 'foo';
this.b = 'bar';
window.c = 'test';
alert(window.a) // foo
alert(b) // bar;
alert(this.c) // test
alert(this.document === document); //true
alert(this === window); // true

The behaviour is similar to local variables defined in function code as they become properties of a variable object. The difference is that the execution context for function code will create what is called an activation object which is merely an extension of the variable object and for all intents and purposes the same. The activation object is an internal mechanism not accessible to code.

To put it simply, each time you attempt to access a variable within a function’s execution context, the look-up process will always begin with its own activation object. If the variable is not found in the activation object, the search continues into the scope chain. It will climb up the scope chain examining the activation object of every execution context looking for a match to the variable name.

Closures

A closure is formed when a nested function is made accessible outside of the function in which it was defined, so that it may be executed after the outer function has returned. It maintains access to the local variables, arguments, and inner function declarations of its outer function. Encapsulation allows us to hide and preserve the execution context from outside scopes while exposing a public interface and thus is subject to further manipulation. A simple example of this looks like the following:

function foo(){
var local = 'private variable';
return function bar(){
return local;
}
}
var getLocalVariable = foo();
getLocalVariable() // private variable

One of the most popular types of closures is what is widely known as the module pattern; it allows you to emulate public, private, and privileged members:

var Module = (function(){
var privateProperty = 'foo';

function privateMethod(args){
//do something
}
return {

publicProperty: "",

publicMethod: function(args){
//do something
},

privilegedMethod: function(args){
privateMethod(args);
}
}
})();

The module acts as if it were a singleton, executed as soon as the compiler interprets it, hence the opening and closing parenthesis at the end of the function. The only available members outside of the execution context of the closure are your public methods and properties located in the return object (Module.publicMethod for example). However, all private properties and methods will live throughout the life of the application as the execution context is preserved, meaning variables are subject to further interaction via the public methods.

Another type of closure is what is called an immediately-invoked function expression (IIFE) which is nothing more than a self-invoked anonymous function executed in the context of the window:

(function(window){

var a = 'foo', b = 'bar';

function private(){
// do something
}

function Module(){
// do something
}
window.Module.public = function(){
// do something
};

})(this);

This expression is most useful when attempting to preserve the global namespace as any variables declared within the function body will be local to the closure but will still live throughout runtime. This is a popular means of encapsulating source code for applications and frameworks, typically exposing a single global interface in which to interact with.

Call and Apply

These two simple methods inherent to all functions allow you to execute any function in any desired context. The call function requires the arguments to be listed explicitly while the apply function allows you to provide the arguments as an array:

function user(first, last, age){
// do something
}
user.call(window, 'John', 'Doe', 30);
user.apply(window, ['John', 'Doe', 30]);

The result of both calls is exactly the same, the user function is invoked in the context of the window and provided the same three arguments.

ECMAScript 5 (ES5) introduced the Function.prototype.bind method that is used for manipulating context. It returns a new function which is permanently bound to the first argument of bind regardless of how the function is being used. It works by using a closure that is responsible for redirecting the call in the appropriate context. See the following polyfill for unsupported browsers:

if(!('bind' in Function.prototype)){
Function.prototype.bind = function(){
var fn = this, context = arguments[0], args = Array.prototype.slice.call(arguments, 1);
return function(){
return fn.apply(context, args);
}
}
}

It is commonly used where context is commonly lost; object-orientation and event handling. This is necessary because the addEventListener method of a node will always execute the callback in the context of the node the event handler is bound to, which is the way it should be. However if your employing advanced object-oriented techniques and require your callback to be a method of an instance, you will be required to manually adjust the context, this is where bind comes in handy:

function MyClass(){
this.element = document.createElement('div');
this.element.addEventListener('click', this.onClick.bind(this), false);
}
MyClass.prototype.onClick = function(e){
// do something
};

While reviewing the source of the bind function, you may have also noticed what appears to be a relatively simple line of code involving a method of an Array:

Array.prototype.slice.call(arguments, 1);

What is interesting to note here is that the arguments object is not actually an array at all, however it is often described as an array-like object much like a nodelist (anything returned by document.getElementsByTagName()). They contain a length property and indexed values but they are still not arrays, and subsequently don’t support any of the native methods of arrays such as slice and push. However, because of their similar behaviour, the methods of Array can be adopted or hijacked, if you will, and executed in the context of an array-like object as is the case above.

This technique of adopting another object’s methods also applies to object-orientation when emulating classical based inheritance in JavaScript:

MyClass.prototype.init = function(){
// call the superclass init method in the context of the "MyClass" instance
MySuperClass.prototype.init.apply(this, arguments);
}

By invoking the method of the superclass (MySuperClass) in the context of an instance of a subclass (MyClass), we can mimic this powerful design pattern.

Conclusion

It is important to understand these concepts before you begin to approach advanced design patterns, as scope and context play a significant and fundamental role in modern JavaScript. Whether were talking about closures, object-orientation and inheritance, or various native implementations, context and scope play a significant role in all of them. If your goal is to master the JavaScript language and better understand all it encompasses than scope and context should be one of your starting points.

原文链接：http://ryanmorr.com/understanding-scope-and-context-in-javascript/ （本内容由互联网资料整理而成）

专门针对初学者的Node.js教程

Node.js的教程并不缺乏，但有大部分教程针对已有Node.js基础的开发者。“我已下载了Node.js，可我如何开始呢？”以下教程是专门针对Node.js初学者，文中将通过实例分享，一步步教你如何开始Node.js之旅。

什么是Node.js?

很多初学者并没有真正地理解Node.js到底是什么。nodejs.org网站中的描述也没有多大帮助。

首先要清楚Node不是一个Web服务器，这十分重要。它本身并不能做任何事情。它无法像Apache那样工作。如果你希望它成为一个HTTP服务器，你必须借助它内置库自己编写。Node.js只是计算机上执行代码的另一种方式，它是一个简单的JavaScript Runtime.

安装Node.js

Node.js的安装十分容易。只需在这里下载满足你需要的安装程序即可。

已安装好Node.js，下一步做什么？

安装结束后，你可以输入一个新命令“node”。使用该“node”命令有两种不同的方法。第一种不带任何参数，将打开一个交互式Shell“>”（REPL： read-eval-print-loop），你可以在这里执行JavaScript代码。

$ node

> console.log('Hello World');

Hello World

undefined

上面案例中，我在Shell中键入了“console.log('Hello World')”，并敲回车。Node便开始执行该代码，并显示刚才记录的信息，同时打印出“undefined”。这是因为每条命令都会返回一个值，而console.log没有任何返回，故输出“undefined”。

Node命令的另一种用法是执行一个JavaScript文件。这是我们平时最常用的方法。

hello.js

<b>console.log('Hello World');</b>

<b>$ node hello.js

Hello World</b>

该案例中，我将“console.log('Hello World');”命令存入一个文件中，并将该文件作为node命令的参数。Node运行文件中JavaScript代码，并输出“Hello World”。

案例一：文件的输入与输出

Node.js包含一组强大的库（模块），可以帮助我们做很多事。第一个案例中，我将打开一个Log文件，并对它进行解析。

example_log.txt

<b>2013-08-09T13:50:33.166Z A 2

2013-08-09T13:51:33.166Z B 1

2013-08-09T13:52:33.166Z C 6

2013-08-09T13:53:33.166Z B 8

2013-08-09T13:54:33.166Z B 5</b>

该Log数据什么意思并不重要，基本可以确定每条信息都包含一条数据、一个字母和一个值。我希望将每个字母后面的值进行累加。

我们要做的第一件事是读出文件的内容。

my_parser.js

<b>

// Load the fs (filesystem) module

var fs = require('fs');

// Read the contents of the file into memory.

fs.readFile('example_log.txt', function (err, logData) {

// If an error occurred, throwing it will

// display the exception and end our app.

if (err) throw err;

// logData is a Buffer, convert to string.

var text = logData.toString();

});</b>

通过内置的文件（fs）模块，我们可以很容易进行文件的输入/输出操作。fs模块有一个readFile方法，该方法以文件路径、回调函数为参数。该回调函数在完成文件读取后调用。文件数据读取后存储在Buffer类型中，为基本的字节数组。我们可以通过toString（）方法将它转化为字符串。

现在我们对它进行解析。

my_parser.js

<b>

// Load the fs (filesystem) module.

var fs = require('fs');

// Read the contents of the file into memory.

fs.readFile('example_log.txt', function (err, logData) {

// If an error occurred, throwing it will

// display the exception and kill our app.

if (err) throw err;

// logData is a Buffer, convert to string.

var text = logData.toString();

var results = {};

// Break up the file into lines.

var lines = text.split('\n');

lines.forEach(function(line) {

var parts = line.split(' ');

var letter = parts[1];

var count = parseInt(parts[2]);

if(!results[letter]) {

results[letter] = 0;

results[letter] += parseInt(count);

});

console.log(results);

// { A: 2, B: 14, C: 6 }

});</b>

现在，当你将该文件作为node命令的参数时，执行该命令将打印出如下结果，执行完毕后退出。

$ node my_parser.js

{ A: 2, B: 14, C: 6 }

我大部时候将Node.js作为脚本使用，正如上面所展示的那样。它更易于使用，是脚本程序有力的替代者。

异步回调

正如在上例中看到的那样，Node.js典型的模式是使用异步回调。基本上，你告诉Node.js要做的事，它执行完后便会调用你的函数（回调函数）。这是因为Node是单线程的。在你等待回调函数执行过程中，Node可继续执行其他事务，不必被阻塞直到该请求完毕。

这对于Web服务器尤其重要。在现代Web应用访问数据库的过程中特别普遍。当你等待数据库返回结果的过程中，Node可以处理更多请求。与每次连接仅处理一个线程相比，它使你以很小的开销来处理成千上万个并行连接。

案例二：HTTP服务器

Node内建有一个模块，利用它可以很容易创建基本的HTTP服务器。请看下面案例。

my_web_server.js

<b>var http = require('http');

http.createServer(function (req, res) {

res.writeHead(200, {'Content-Type': 'text/plain'});

res.end('Hello World\n');

}).listen(8080);

console.log('Server running on port 8080.');</b>

在上面，我说是的基本HTTP服务器。该例中所创建的并不是一个功能全面的HTTP服务器，它并不能处理任何HTML文件、图片。事实上，无论你请求什么，它都将返回“Hello World”。你运行该代码，并在浏览器中输入“http://localhost:8080”，你将看见该文本。

$ node my_web_server.js

现在你可能已经注意到一些不一样的东西。你的Node.js应用并没有退出。这是因为你创建了一个服务器，你的Node.js应用将继续运行，并响应请求，直到你关闭它。

如果你希望它成为一个全功能的Web服务器，你必须检查所收到的请求，读取合适的文件，并返回所请求的内容。值得高兴的是，有人已经帮你做了这个艰难的工作。

案例三：Express框架

Express为一个框架，可使创建网站的过程十分简单。你首先需要安装它。除了node命令，你还需要访问“npm”命令。利用该工具，你可以访问社区所创建的庞大模块集。其中之一就是Express。

$ cd /my/app/location

$ npm install express

当你安装了一个模块，它将出现在应用程序所在目录的“node_modules”文件夹中。现在我们可以利用Express来创建一个基本的静态文件服务器。

my_static_file_server.js

<b>var express = require('express'),

app = express();

app.use(express.static(__dirname + '/public'));

app.listen(8080);</b>

$ node my_static_file_server.js

现在你已创建了一个强大的静态文件服务器。你可以通过浏览器请求访问你放在public文件夹中任何文件，并进行展示，包括HTML、图片等任何东西。比如，把一个名为“my_image.png”的图片放在public文件夹中，你可以在浏览器中输入“http://localhost:8080/my_image.png”来访问该图片。当然，Express还有很多特性，你可以在以后的开发中继续探索。

NPM

上面我们已经接触到了npm，但我仍想强调一下在Node.js开发过程中该工具的重要性。它有成千上万个模块可帮我们解决遇到的大部分典型问题。在重新发明轮子之前，记得检查一下npm中是否有相应功能。

上一例中，我们手动安装了Express。如果你的程序包含很多“依赖”（Dependency），那再利用该方法安装它们就不合适了。为此npm提供了一个package.json文件。

package.json

<b>{

"name" : "MyStaticServer",

"version" : "0.0.1",

"dependencies" : {

"express" : "3.3.x"

}</b>

package.json文件包含了应用程序的基本信息。其中“dependencies”部分描述了你想安装模块的名称和版本。该案例，接受Express 3.3的任何版本。你可以在该部分列出你想要的所有依赖。

代替之前一个个安装每个依赖，现在我们可以运行一个命令，即可将它们全部安装完成。

$ npm install

运行该命令，npm将在当下文件夹中查找“package.json”文件。一旦找到，即可安装所列出的所有依赖。

代码的组织

在大部分应用程序中，你的代码往往被分割到几个文件中。现在让我们把最开始案例中的Log分析脚本分离出来。这样该程序将更易于测试与维护。

parser.js

<b>

// Parser constructor.

var Parser = function() {

// Parses the specified text.

Parser.prototype.parse = function(text) {

var results = {};

// Break up the file into lines.

var lines = text.split('\n');

lines.forEach(function(line) {

var parts = line.split(' ');

var letter = parts[1];

var count = parseInt(parts[2]);

if(!results[letter]) {

results[letter] = 0;

results[letter] += parseInt(count);

});

return results;

// Export the Parser constructor from this module.

module.exports = Parser;</b>

在此创建了一个新文件，来存放Log分析脚本。这仅仅是一种标准JavaScript，还有很多方法可用来封装该代码。我选择重新定义一个JavaScript对象，这样更容易进行单元测试。

该程序中最重要的部分是“module.exports = Parser;”这一行代码。它告诉Node从该文件中要输出的内容。在该例中，我输出了构造函数，用户可以用Parser对象来创建实例。你可以输出任何你想要的。

现在我们看一下，如何导入该文件，来使用Parser对象。

my_parser.js

<b>

// Require my new parser.js file.

var Parser = require('./parser');

// Load the fs (filesystem) module.

var fs = require('fs');

// Read the contents of the file into memory.

fs.readFile('example_log.txt', function (err, logData) {

// If an error occurred, throwing it will

// display the exception and kill our app.

if (err) throw err;

// logData is a Buffer, convert to string.

var text = logData.toString();

// Create an instance of the Parser object.

var parser = new Parser();

// Call the parse function.

console.log(parser.parse(text));

// { A: 2, B: 14, C: 6 }

});</b>

如模块一样，文件被引入其中，你需要输入路径，而非名称。

希望该教程可以帮助到你。Node.js是一个强大、灵活的技术，可以帮助解决各种各样的问题。它已经超出了我们的想像。

原文链接：An absolute beginner's guide to Node.js

原文链接：http://www.html5cn.org/article-5464-1.html （本内容由互联网资料整理而成）

使用 CSS 和 DataURI 来添加杂色滤镜效果

本文由罗罗磊磊根据James Brocklehurst的《CSS Noise》所译，整个译文带有我们自己的理解与思想，如果译得不好或不对之处还请同行朋友指点。如需转载此译文，需注明英文出处：http://www.mightymeta.co.uk/css-noise/，以及作者相关信息

作者：James Brocklehurst

译者：罗罗磊磊

前几天在codewall上看到一篇“CSS Background Noise”的文章，用css+DataURI来实现给html元素添加杂色效果，可以在不增加http请求的情况下，实现不错的杂色效果。自己跟着实践了一下，在这里也就按照原文的步骤，自己翻译加整理实践，分享给大家。

首先放Demo ，图文无关，仅仅是演示而已，css源码请参考 CSS Code SNIPPET .

如何使用它？

最简单的方法就是把上面的CSS代码复制到你的css中，然后给你要加杂色的html元素加上 class=”noise”就好。

原理

长话短说，看了源码大家应该就能get到，我们首先使用photoshop生成一个50px * 50px的有杂色的半透明png图，然后通过转换工具将这个png图片转化为dateURI，然后在css中，设置一个.noise类，在其中的background-image属性中使用dataURI。

对于如何实现不同的元素滤镜效果，我们使用到了 :before伪选择器和 opacity透明度属性，同时，通过设置 .noise的 z-index;堆叠顺序顺序，.noise杂色在覆盖所有的背景颜色和图片的同时，不会覆盖住元素的内容。

最关键的是，上面涉及到的所有属性都是CSS2.1而不是CSS3，所以浏览器兼容性方面不存在太大的问题，哪怕某些浏览器不支持，最多就是不显示noise杂色而已。

为什么使用它？

在网页设计中使用一定数量的杂色以显现设计质感越来越常见 （英文作者写这篇文章的时候是2011年，现在是 flat 扁平化大行其道）。一般来说，我们可以通过使用img图片来实现效果，可是这也意味着我们必须使用 photoshop ，并且修改起来挺不方便，对于前端优化来说，也额外增加了HTTP请求。

说完了上面的，那使用css+dataURI来实现添加杂色质感的优点就显而易见了：纯css+html，小文件（往往5k不到），还能较好地控制和修改。

自己动手，丰衣足食

你可以直接使用我的dataURI来作为杂色模板，当然，你也能自己做一个，在 photoshop 里根据自己的需求和喜好调整透明度，杂色值等等。

一.创建杂色模板图片

1.photoshop

创建一个50px*50px的画布（根据作者实践，发现其他大于50px的图片都会导致最终URI过大导致优势不那么明显）。

2.创建一个新的图层，使用50%灰色填充（编辑 > 填充）。

3.应用杂色滤镜（滤镜 > 杂色 > 添加杂色），数量区间5~6%为佳。

4.增加杂色对比度，可以通过添加一个图层模板，调整亮度对比度.

5.降低杂色层的透明度（可以通过把已经有的两个图层加入一个新组，然后降低组的透明度值）

7.保存输出为PNG-24格式，对于图片格式的相关知识，建议大家可以阅读一下一淘的《PNG的秘密—— 一淘前端分享会》。

二.优化png图片

最终我们生成的png文件大概有8kb的大小，对于前端工程师来说，节省每一kb文件大小都是有意义的，我使用的是 mac 上的 ImageOptim 这个软件，通过优化压缩，最后我们获得了一个4kb大小的文件。

三.将图片转换成Data URI

在这里，我们使用了一个在线的转换服务“dopiaza.org”,上传文件，转换。

四.比较一下data URI和原图像的大小

这时候，别高兴得太早，再确认一下，看看生成出来的data URI的字符大小有多少，在这里推荐使用“bytesizematters”在线查看文本大小，如果字符大小比原来的png图片大小还大，那优化就得不偿失。经过比较，我们发现dataURI进一步压缩到了2.05kb。

浏览器支持

Internet Explorer 8+, FireFox 3.5+, Chrome 1+, Safari 4+, Opera 9+

其他

实际上也可以通过同样的原理，实现其他常用的纹理效果：如纸张、石头、布料等等效果，大家也可以实践一下，看看效果如何。

译者手语：整个翻译依照原文线路进行，并在翻译过程略加了个人对技术的理解。如果翻译有不对之处，还烦请同行朋友指点。谢谢！

关于罗罗磊磊

前端小菜，广州暨南大学14届本科生，喜欢折腾各种技术，爱生活，爱骑行，互联网GEEK，间隔年践行者，坚持优质原创内容，致力于传播美好的思想，分享有价值的信息。独立博客，新浪微博 ，欢迎与同学一起共勉。

如需转载烦请注明出处：

英文原文：http://www.mightymeta.co.uk/css-noise/

中文译文：http://www.w3cplus.com/css/css-noise.html

原文链接：http://www.w3cplus.com/css/css-noise.html （本内容由互联网资料整理而成）

3D Shading with Box-Shadows

A tutorial about a technique that uses box shadows for creating a realistic shading effect on simple objects.

View demo Download source

When working with 3D transformed elements, you might notice that they don’t have any shading and appear to be very flat. In real life, objects block light and have shadows. Surfaces can be matte, reflective, and everything in between. Indeed, we can do better.

If you need to cast light onto complicated geometry, there are options available such as Photon, but they’re very processor intensive. In this article, I’ll show you a solution that can be applied to objects that only have a few faces. Our example will be a 3D movie gallery with glossy posters and, when the posters are rotated, the sides will contain matte information cards with meta data about the film.

The Markup

Our page is going to have a few different parts. First, we need a simple wrapper to center everything on the page. Next, we’ll create an unordered list that will contain all of our 3D posters. We’ll add the class “stage” to the ul and “scene” to each li. In our CSS, the stage element will act as a container for the scene elements, which will be their own 3D environment with the perspective property applied.

<div class="wrapper">
<ul class="stage">
<li class="scene"></li>
<li class="scene"></li>
<li class="scene"></li>
</ul>
</div>

For each li, we need to add quite a bit of markup. This will contain our movie poster as well as all the metadata about each movie. In a more robust movie library, this could be done dynamically with some backend code. We’ll keep things simple for the purposes of this example.

<li class="scene">
<div class="movie">
<div class="poster"></div>
<div class="info">
<header>
<h1>It's a Wonderful Life</h1>
<span class="year">1946</span>
<span class="rating">PG</span>
<span class="duration">130 minutes</span>
</header>
<p>
In Bedford Falls, New York on Christmas Eve, George Bailey is deeply troubled. Prayers for his well-being from friends and family reach Heaven. Clarence Odbody, Angel Second Class, is assigned to visit Earth to save George, thereby earning his wings. Franklin and Joseph, the head angels, review George's life with Clarence.
</p>
</div>
</div>
</li>

Our library will contain two more movies in addition to this one. The metadata is a bit lengthy and there are also a few image assets you’ll need, but everything is included in the code download. Let’s get to styling.

The CSS

Note that the CSS will not contain any vendor prefixes, but you will find them in the files.

First, let’s get some of the basics out of the way. We need to center our wrapper and then remove the default list styling from the stage class.

.wrapper {
margin: 0 auto 100px auto;
max-width: 960px;
}

.stage {
list-style: none;
padding: 0;
}

Next, we want to style the scene class with an explicit width and height (the same as our posters). If you’d like to provide additional detail needed for high resolution displays then you could use images that are twice as large.

The margin between each scene will provide sufficient spacing so that they don’t overlap each other. Then we’ll float all of the list items to the left so that they line up next to one another in a nice gallery. This is similar to how most top-level website navigation is created.

Finally, we’ll add the perspective property. This will allow us to create a 3D scene in the nested elements, and the value of 1000px will give the objects a decent amount of depth. A lower value would be a bit too dramatic, but you can experiment with this and see what works best for you.

.scene {
width: 260px;
height: 400px;
margin: 30px;
float: left;
perspective: 1000px;
}

Similar .scene, we also need to set an explicit width and height on .movie. This will help each poster look correct when it’s being transformed. Next, we’ll set the transform-style to preserve-3d so that we can transform elements in 3D space. Finally, we’ll translate it along the Z plane by -130 pixels. This will give the posters a little bit more room to move around and really pop towards the viewer.

.movie {
width: 260px;
height: 400px;
transform-style: preserve-3d;
transform: translateZ(-130px);
transition: transform 350ms;
}

Here’s where the movement happens. We’ll apply a transition to the .movie class. The transition timing is set to a rapid 350ms, but if you’d like a more dramatic effect, you could slow it down.

Then we’ll transform each .movie on :hover. This will rotate the 3D poster along the Y axis and then move it towards the screen along the Z plane. You could rotate the poster by a full 90 degrees, but I prefer to leave it slightly offset to maintain the 3D effect while hovered.

.movie:hover {
transform: rotateY(-78deg) translateZ(20px);
}

Observant coders will notice that, while we have translated the scene, we never actually rotated any elements that would give semblance of geometry and build an object. Let’s create each 3D poster now. Each .poster and .info card needs to be positioned absolutely, otherwise they’ll push one another out of the way. We don’t want that, because we’re going to position them using transforms. Next, we need to set an explicit dimensions on both of the classes so that each of the two sides is exactly the same.

.movie .poster,
.movie .info {
position: absolute;
width: 260px;
height: 400px;
background-color: #fff;
backface-visibility: hidden;
}

With the geometry of our posters ready, we can transform them into place. The .poster just needs to be moved 130px along the Z plane (because remember, we moved the .movie back by this amount). The background size has been set to cover so that when we apply our poster backgrounds, they’ll fill the geometry. They should anyway since they’re sized correctly, so this is really just a precautionary measure.

The .info needs to be translated by the same amount as the .poster, but it also needs to be rotated. We want to form a square box, so we’ll rotate it 90 degrees. I’ve added some styling after the transformation, but this is mostly just for aesthetic reasons.

.movie .poster  {
transform: translateZ(130px);
background-size: cover;
background-repeat: no-repeat;
}

.movie .info {
transform: rotateY(90deg) translateZ(130px);
border: 1px solid #B8B5B5;
font-size: 0.75em;
}

We’ll use the pseudo-element ::after to create another face that will have a subtle box shadow beneath the movie box:

.movie::after {
content: '';
width: 260px;
height: 260px;
position: absolute;
bottom: 0;
box-shadow: 0 30px 50px rgba(0,0,0,0.3);
transform-origin: 100% 100%;
transform: rotateX(90deg) translateY(130px);
transition: box-shadow 350ms;
}

.movie:hover::after {
box-shadow: 20px -5px 50px rgba(0,0,0,0.3);
}

Further down in the CSS, we style the metadata contained inside the .info class. None of this is particularly relevant to this demo, as it’s mostly just formatting some text and imagery. The real magic happens later on.

.info header {
color: #FFF;
padding: 7px 10px;
font-weight: bold;
height: 195px;
background-size: contain;
background-repeat: no-repeat;
text-shadow: 0px 1px 1px rgba(0,0,0,1);
}

.info header h1 {
margin: 0 0 2px;
font-size: 1.4em;
}

.info header .rating {
border: 1px solid #FFF;
padding: 0px 3px;
}

.info p {
padding: 1.2em 1.4em;
margin: 2px 0 0;
font-weight: 700;
color: #666;
line-height: 1.4em;
border-top: 10px solid #555;
}

Here’s where we create our pseudo-lighting using the box-shadow property. For the .poster class, we add an inset box shadow with an X and Y offset of 0px. The blur radius will be set to 40px and the shadow is set to rgba(255,255,255,0) (which is white “shadow” set to 100% transparency). Remember, there’s a transition applied to all the children of .movie, so if we set a starting state for the shadow, we can then animate it using a :hover state.

If we :hover over the .movie, it will reset the values of the box-shadow for the .poster and animate them with a transition. In this new state, the poster is still inset, but this time it has an X offset of 300px and an opacity of 0.8 for the white color. This will effectively move the box-shadow over top the poster with some fuzziness along the edge. The transparency will help to gel the shadow with the poster image, which will make the poster look like it has a glossy finish.

.movie .poster,
.movie .info,
.movie .info header {
transition: box-shadow 350ms;
}

.movie .poster {
box-shadow: inset 0px 0px 40px rgba(255,255,255,0);
}

.movie:hover .poster {
box-shadow: inset 300px 0px 40px rgba(255,255,255,0.8);
}

Just like for the poster, we also want to apply a shadow to the other side of the box. For the .info panel, we want a dark shadow to disappear as the element is rotating forward and then reappear when the paper texture recedes back into the gap between each 3D poster. On our page, with the glossy poster on the left and the shadow on the right, it will make it appear as though there’s a light source coming from the left side of the page.

.movie .info,
.movie .info header {
box-shadow: inset -300px 0px 40px rgba(0,0,0,0.5);
}

.movie:hover .info,
.movie:hover .info header {
box-shadow: inset 0px 0px 40px rgba(0,0,0,0);
}

Last but not least, we need to add the poster images and still preview images to each movie. I’ve done this using the :nth-child pseudo class, but again, this would probably be done elsewhere in a dynamic website.

.scene:nth-child(1) .movie .poster {
background-image: url(../img/poster01.jpg);
}

.scene:nth-child(2) .poster {
background-image: url(../img/poster02.jpg);
}

.scene:nth-child(3) .poster {
background-image: url(../img/poster03.jpg);
}

.scene:nth-child(1) .info header {
background-image: url(../img/still01.jpg);
}

.scene:nth-child(2) .info header {
background-image: url(../img/still02.jpg);
}

.scene:nth-child(3) .info header {
background-image: url(../img/still03.jpg);
}

You’ll notice that we’ve used Modernizr in the demo to detect support for 3D transforms and provide a simple fallback for browsers that don’t support it.

That’s it! As I suggested in the intro, this technique can be applied to simple geometry. Some of you may be wondering why I didn’t use a gradient to create a more controlled shadow over top the poster images. At the time of this article, transitions cannot be applied to gradients, so while this might work for static geometry, the illusion would be broken as soon as the element is animated.

If you have any questions, comments, or improvements on this technique, I’d love to hear about them in the comments!

View demo Download source

原文链接：http://tympanus.net/codrops/2013/08/27/3d-shading-with-box-shadows/ （本内容由互联网资料整理而成）

URL锚点HTML定位技术机制、应用与问题

unknown

原文链接：http://www.zhangxinxu.com/wordpress/2013/08/url-anchor-html-%E9%94%9A%E7%82…%88%B6-%E5%BA%94%E7%94%A8-%E9%97%AE%E9%A2%98/comment-page-1/#comment-39173 （本内容由互联网资料整理而成）

浏览器开发工具的秘密

源网站：Secrets of the Browser Developer Tools
译者：涂鸦码农

目录

常规

找到开发工具

快捷方式：

- “F12”（Windows）

- “Cmd”⌘ +”Option” +”I”（Mac）

- 右键选择”Inspect Element 检查元素”

- Safari 需要在 首选项 > 高级 > 显示开发菜单，启用开发工具

- Firebug 是 Firefox 扩展，需要在此安装

用最新的开发版

开发工具会不断完善，在开发版可以体验。 Chrome Canary 是 Chrome 实验版，Canary 和 Chrome 可以同时安装。 你可以通过 chrome://flags 进一步加强你的 Chrome 开发工具 ，启用”1.Enable Developer Tools experiments （启用开发工具实验）“。不要忘了点击页面底部的”现在重启**”按钮。

Firefox Aurora 提供 Firefox 最新特性预览。不幸的是，Aurora 不能和 Firefox 同时打开。

Webkit Nightly 是 Safari 测试版，因此有些不稳定。Webkit Nightly 可以和 Safari 同时运行。

Opera Next 是 Opera 最新改良版，会提供一些新的功能和特性。

现在浏览器的发布周期为12周，浏览器自动更新，变化是增量的。

移动开发工具位置

有时候不想让我们的工具在屏幕底部，大部分的开发工具提供了配置选项。

Chrome 开发工具，左下角图标允许改变停靠设置。快速点击它，会在底部和右侧切换。长按可以选择停靠选项（独立窗口打开），你也可以点击并拖拽移动开发工具。

Firefox 和 Safari 开发工具，停靠选项在右上角临近关闭按钮的位置，可以新窗口打开。

要改变停靠位置，可点击左上角小虫子，选择 Firebug 界面位置（上/下/左/右）。Firebug 右上角可以快速选择：最小化，新窗口，关闭。

开发工具调试响应式设计

当调试移动站点的时候，停靠在右侧可充分利用空间，并且可以快速调整浏览器视口和开发工具的宽度，调试不同网页宽度。

在 Chrome 开发工具左下角，点击按钮可切换下侧或右侧停靠位置。

在 Chrome 开发工具右下角，点击并选择”General“标签，你可以改变工具的外观，停靠右侧时可以垂直显示面板。

学习快捷键

Chrome 的快捷键列在设置菜单里，点击右下”齿轮“图标，可以看到”Shortcuts“标签。

IE 的快捷键是在线的.aspx) 。

Opera 的快捷键也在设置按钮里。

Console 控制台

Log, Info, Debug, Warn, Error

不必用 alert 时，console.log() 是个极其有用的输出调试工具；

console.log() 是 printf 风格，因此你可以这么做：console.log("%s is %d years old.", "Bob", 42)。

可以用 console.info() 输出提示信息；console.debug() 输出调试信息；console.warn() 输出警示信息；console.error() 输出错误信息。

你还可以用 %c 模式，把第二个变量作为样式格式参数。例如：console.log("%cThis is green text on a yellow background.", "color:green; background-color:yellow");

Firebug 只不过显示的图标不同，消息的背景色是一致的。

根据 MDN 的消息，他们不赞成使用 console.debug() ，因此没有图标标识，赞成用 console.log() 代替。

Chrome 和 Safari（nightly）用 info 时不显示图标，用 debug 时显示蓝图标；用 warn 时显示黄图标；用 error 时显示红图标。

你可以输出多个值，用逗号隔开即可，方便在同一行输出对象和数组，例如：console.log('Kings: ', kings);

输出数据表格

console.table() 可以用来输出数组或者对象列表，以一种合适的表格形式显示。

例如：console.table([[10, true, "blue"],[5, false]]) 将输出以下格式：

如果元素的数量不匹配，表格将显示 undefined 表示没有数据。

自定义列名，属性名必须在对象中指定元素。自定义（index）的值，可以给每个属性命名。

第二个可选的变量允许你明确指定哪一列要输出。

console.table({“London”:{population:8173194, country:”UK”, elevation:”24m”},”New York”:{population:8336697, country:”USA”, elevation:”10m”}},[“population”, “country”])

结果如下：

Assert

console.assert() 用于测试表达式的真假。

它有两个参数：表达式和显示信息。如果表达式是 FALSE 时，信息将会显示。

例如：console.assert(!true, 'This is not true'); 输出“‘This is not true”。console.assert(true, 'This is not true'); 什么也不输出。

使用控制台定时器

使用 console.time(label)，定时器在控制台启动。字符串 label 是必须的，我们想停止它时，有个定时器引用。调用 console.timeEnd(label) 定时器停止，控制台输出定时器执行的毫秒数（通过 label 识别）。

持久控制台

有时页面加载时，你需要保留控制台信息。有时在点击或离开页面时，我们需要这个作为参考或者用来查看日志。

在 Chrome 里，右键点击控制台，显示菜单里有”Preserve Log upon Navigation“，选择它将保存你的控制台内容。

Firefox 默认会保存控制台信息。你可以点击右上角”清除“按钮清除控制台日志，或者打开/关闭工具。

在 Firebug 里，有个显著的按钮用来保持控制台内容，就在控制台的上部。

Opera 默认保存控制台内容，你可以右键选择”clear console“清除控制台日志或者重开工具。

重新运行命令

如果已经在 JavaScript 控制台输入过命令，你想重新运行它，简单点一下”上“箭头即可翻看原先的命令列表。

任意 Tab 打开控制台

在 Chrome ，尽管控制台有自己的 tab ，在任意 tab 按下”ESC“键即可打开控制台，因此不必切换 tab 了。

Safari 控制台在开发工具的底部，”ESC”键用来切换控制台日志的可见性。在命令行执行一个命令也将打开控制台日志。

在 Firefox ，快速切换到控制台：”Ctrl + Shift + K “（Windows），”Cmd ⌘ + Option ⌥ + K “（Mac）。

改变框架焦点

用命令行运行 JavaScript 非常实用，但是如果页面有 iframe ，你又不知道如何定位框架，就不好办了。

在 Firebug ，你可以用下面的命令聚焦框架： cd(window.frames[‘frameName’]);

Chrome 可以在控制台底部的下拉列表中改变框架。

Opera 在”Console 控制台”和”Documents 文档” 有个改变框架的下拉菜单。

你可以通过 document.getElementsByTagName("iframe"); 获得 iframe 列表。

引用当前和前一个元素

如果你的”Elements”标签选择了一个元素，你可以用 $0 调用它。输入 $0.innerHTML 试试看。

在 Firebug 和 Opera，你可以用 $1 选择前一个元素。

在 Chrome 和 Safari，你可以通过 $1 - $4 选择更靠前的元素。

在 Firebug ，你可以通过 $n(2) - $n(5) 选择更靠前的元素。

最终求值表达式

如果你需要先前表达式的结果用于后面的求值，你可以使用便利 $_ ，最终表达式结果自动展示给你。

Firebug 1.12 开始支持。

检查

通过面包屑导航 DOM

当你检查 DOM 树的节点时，节点的 DOM 路径面包屑列表显示在开发工具里。

Chrome 和 Opera，显示在 DOM 检查器的底部。

Firebug，Firefox 和 Safari，显示在 DOM 检查器的顶部。

你可以直接点击节点，或者按箭头键导航面包屑。按左箭头是父节点，按右箭头是第一个子项。上下箭头导航到下一个或前一个子节点。没有更多子节点，上下箭头导航回到 DOM 树。

在 Firefox ，你可以右击面包屑看兄弟节点列表，可以快速导航到兄弟节点。

在 Safari，你可以左击面包屑看兄弟节点。

搜索 DOM 节点

在 Firefox ，你可以在”检查器”面板搜索特别的节点。面包屑右边有个小的搜索框有同样作用。

聚焦时搜索框变大。

输入一个匹配的选择器， DOM 树将自动高亮它。

在 Chrome ，你可以按 Ctrl-F 打开对话框，CSS 选择器如期工作。

检查字体

Firefox 有个字体检查器，可以查看当前元素使用的字体。

你可以修改默认的”Abc”文字，在字体列表底部有个按钮，可以显示页面所有字体。

浏览你的响应式网站

在响应式设计时代，最重要的是如何在任意尺寸的设备查看我们的网站。尽管我们可以调整浏览器大小，开发工具里还是有一些其它的工具可用。

在 Chrome 开发工具的”设置“面板（工具右下角点击齿轮），在”Overrides“标签，你会发现”Device Metrics 设备指标“选项，你可以指定宽度和高度，以及字体缩放尺寸。你可以把开发工具停靠在右侧，然后调整页面大小测试。

Firefox 开发工具内置一个’响应式设计模式‘工具，此工具在开发工具的右上角。它包含一些预设的尺寸，你可以添加需要的尺寸。Firefox 也提供旋转的选项，你可以测试 landscape 和 portrait 模式。

3D 视图

Firefox 开发工具可以 3D 视图查看你的网站，可以方便地查看元素嵌套关系，点击开发工具右上角立方体图标可以启动它。

编辑

改变 CSS 值

如果有个元素需要修改 margin，padding，width 或者 height，可以使用方向键增加/减少尺寸。简单使用上下方向键增加/减少1个单位。

“Shift” + 上下方向键，可以增加/减少10个单位；”Alt” + 上下方向键，可以增加/减少0.1个单位。

“Shift” + Page-Up / Page-Down，可以增加/减少100个单位。

当你矫正尺寸时，这些快捷键非常实用。

改变 :active， :hover， :focus， :visited 状态样式

在开发工具里修改 CSS 非常爽，但是碰到 hover 之类的伪类就有点挠头了。恰好有解决方案。

Chrome 有个按钮是干这用的，在”Elements”标签右手边看到一个虚线框和光标在一起的图标，它可以切换其它状态。

Firebug 的 HTML 标签右侧，点击样式小箭头，可以选择想要的状态。Firebug 并没提供 :visited 状态选项。

Firefox 为你选择的 DOM 元素提供一个下拉菜单，右键选择”查看元素”可以看到它，Firefox 同样没提供 :visited 状态选项。

在 Opera，”样式”标签有个像列表的图标，Opera 提供了 :link 和 ::selection 选项。在新版 Opera ，位置跟 Chrome 一致了。

在 Safari，DOM 上右击一个元素，显示一个菜单，里面有”Force Psuedo-Classes”选项。

拖拽重排元素

在 Chrome 和 Safari 里，”Elements “标签下，可以拖拽重排元素顺序。简单点击拖动元素即可，目标位置会出现一条线。

使用 SASS Source Maps

使用 CSS 预处理器有许多优势，但是在浏览器开发工具中修改比较困难。例如，当你再次运行 SASS 时， 在开发工具中保存的编译后CSS 可能被覆盖，不太理想。SASS 3.3 以上（可以安装使用’sass gem install sass –pre’），为 SASS 文件创建映射很容易，你可以很容易的保存修改。

首先，为 SASS watch 命令增加 --sourcemap ，像这样：

1

sass --watch scss/devtoolsecrets.scss:css/devtoolsecrets.min.css --style compressed --sourcemap

然后在 SASS 文件底部添加映射文件的名字（sourceMappingURL）：

1

/*@ sourceMappingURL=devtoolsecrets.css.map */

然后，你需要启用”Experiments 实验“。地址栏输入 chrome://flags 启用”启用开发者工具实验”选项，点击页面底部”马上重启”按钮应用改变。在 Chrome 开发工具的右下角，点击齿轮按钮打开”设置“面板。

点击”General 常规“标签，激活”Enable Source Maps 启用 Source Maps “。点击”Experiments 实验”标签，检查”Support for SASS 支持 SASS “选项。

重启浏览器，你可以直接查看 SASS 文件的行号了。

调试

用 debugger; 调试

添加此行代码：debugger; 可以自动创建断点，当开发工具打开时运行，断点会自动创建。

尽管快速添加断点很方便，不用在开发工具一行一行找，小心不要把 debugger; 提交到线上环境。

条件断点

不必每次生效时，条件断点很有用。例如，你知道你的代码在最后一项有 bug，你可以用条件判断在最后一项时激活 debugger。条件满足，断点触发。

在 Chrome 中创建条件断点，先创建个正常的断点，然后右击断点选择”编辑断点“添加条件。

在 Firebug ，先创建常规断点，然后右击出现输入框，可以添加条件。

在 Firefox ，右击想创建断点的行，选择”增加条件断点“。

在 IE，先创建常规断点，然后右击断点，选择”条件…“。

在 Opera，先创建常规断点，然后右击断点，选择”添加条件“。

在 Safari，确保脚本和”调试器”面板都打开，创建一个断点，然后在”调试器”面板右击同样的断点，选择”编辑断点“。

DOM 断点

如果特定的 DOM 改变，你的页面会被破坏，或者你只想找出元素属性或子元素改变，哪些代码生效，Chrome 和 Firebug 均可以在 DOM 修改时设置断点，你可以找到代码问题的根源。简单点击你想监控的元素，右击选择”break on“选项。

XHR 断点

在 Chrome ，可以为 XmlHttpRequest 设置断点，你可以调试 AJAX 请求。到”Sources“标签选择”XHR 断点“，点击右侧加号图标，输入部分或所有你想添加断点的 URL 。一旦请求返回，断点将生效，你可以看到返回的数据，并可单步调试后续操作。

取消勾选可以关掉断点，右键选择”Delete Breakpoint 删除断点“删除断点。

在 Firebug ，到网络标签选择”在 XHR 时中断“按钮，或者右键选择”在 XHR 时中断“，你也可以随意选择中断条件。

检查断点的作用域

在 Chrome ，Javascript 在断点处暂停时，你可以查看当前作用域的所有变量和对象，既可以悬浮查看，也可以通过控制台查看。

Firebug 有同样的选项，但是需要在 DOM 菜单选择”show closures“。 如果断点设置恰当，这个强大的属性让你很容易查看闭包里的变量。

Firebug 有额外的功能，无需在断点停止，即可访问隐藏的闭包变量。看此例：

1
2
3
4
5
6
7
8

function Person(name) {
this.introduce = function() {
console.log("Hello, my name is %s", name);
}
}
// create an instance of Person: var someone = new Person("Arthur");
// we call a closure! someone.introduce();
// prints "Hello, my name is Arthur"

代码访问以下闭包变量： closure.%variable 以上例子，你将用这个表达式访问 name： someone.introduce.%name // ==> “Arthur” 注意你也可以改变值：

1

someone.introduce.%name = "Trillian"; someone.introduce(); // prints "Hello, my name is Trillian"

Firebug 中，需要 JavaScript 的地方，同样的语法都会生效，例如监控面板和条件断点。

监控值

在”脚本”标签的右上角，监控变量相当容易，只有输入变量名，”监控”将让它的值保持更新。

调试压缩后的 JavaScript

下断点让 JavaScript 调试更容易，但是如果代码已经放到生成环境，很可能已被压缩。如何调试最小化的代码呢？庆幸的是一些浏览器已经支持解压你的 JavaScript 。

在 Chrome 和 Safari ，选择”脚本”标签，找到相应的文件，然后点击”{}”图标（pretty print，在面板底部）。

在 IE ，点击工具图标选择下拉菜单，找到格式化 JavaScript 选项。

Opera 自动格式化压缩的 JavaScript 。

使用 JavaScript Source Maps

当我们部署代码到生产环境时，比较明智的是压缩代码减少加载时间。压缩去除了无用的字符（比如注释），空行和空格。可是压缩后很难调试，无法单步调试，代码不易读。JavaScript source maps 调试压缩后 JavaScript 文件非常有用，它提供一个映射关联到未压缩文件。

创建 JavaScript source maps ，下载 Google Closure Compiler ，它帮你生成 .map 文件。

运行带 Source Map 属性的 Closure Compiler ：

1

java -jar compiler.jar --js common.js --create_source_map ./common.js.map --source_map_format=V3 --js_output_file common.min.js

在压缩后的 JS 文件底部加上映射文件的名字： sourceMappingURL

1

//@ sourceMappingURL=common.js.map

在 Chrome 开发工具，”Settings 设置”菜单 -> “General 常规”标签，激活”Enable Source Maps 启用 Source Maps “。

现在，当你调试 JavaScript 时，可以用未压缩的版本查找问题所在。

模拟User Agent

有时伪装成不同的浏览器或设备用于调试，特别是某个网站用到了设备探测。

在 Chrome ，打开设置菜单（右下角齿轮图标），选择”Overrides”选项，找到 “User Agent”选项。你可以选择内置的选项，也可以选择”Other”自己添加。如果你选择移动或平板设备， Chrome 将调整浏览器尺寸 - 取消勾选”Device Metrics”，很容易关掉此功能。

在 Opera ，点击浏览器左下”面板”箭头（开发工具以上），选择 + ，然后选择”自定义”，到”按钮”标签选择”首选项”，然后拖住”识别为 Opera “下拉框，拖到浏览器工具栏。

模拟触控设备

Chrome 可以伪装成支持触控的设备，直接在浏览器模拟 touch 事件。在设置面板（Chrome 开发工具右下角齿轮图标），选择”Overrides”选项，选择”Emulate Touch Events 模拟触控事件”。

在 Chrome Canary ，用个圆形代替了光标，可以用于区分处于哪种模式。

覆盖地理位置

如果你的应用用到了 Geolocation ，模拟不同的位置会非常有用。在 Chrome ，”设置”菜单，选择”Overrides”标签，这里可以模拟不同的经度纬度，也可以模拟不可用的位置。

在 Google Maps Labs 启用了坐标提示，你就可以从 Google Maps 获得位置的经纬度。

重写设备方向

设备方向改变可以在 Chrome 中模拟。”Settings “-> “Overrides”，选择”Override Device Orientation”，在输入框输入新值。

Alpha 代表沿 z 轴 0-360 度。 Beta 代表沿 x 轴 -180 到 180 度 - 前到后运动 Gamma 代表沿 y 轴 -90 到 90 度 - 左到右运动

改变值将触发 deviceorientation 事件。

调试 Canvas 元素

Chrome 可以用开发工具调试 canvas 元素，可用于 2D 和 WebGL canvas 项目。

首先启用”Experiments”标签，地址栏输入 chrome://flags ，启用”Enable Developer Tools experiments”，按下”Relaunch Now”按钮应用改变。到设置面板，找到”Experiments”标签，选择”Canvas inspection”选项。

现在访问”Profile”标签，你可以看到”Capture Canvas Frame 捕获 Canvas 帧”选项。使用期间可能需要重载页面。按下”Start 开始”捕获 canvas 应用的单个帧。你也可以点击下面的框，切换到”Consecutive Frames 连续帧”，你可以捕获多帧。

每次访问 canvas Chrome 会创建日志，提供每次访问上下文的列表以及快照。你可以点击一个日志项重播那帧，看看哪些命令被调用，及它们在哪一行。

运行代码片段

如果你发现同样的代码需要重复的运行，Chrome Canary（Chrome 29 已有此功能） 提供了便捷的”Snippets 片段”区域，你可以保存代码。

在”Source”标签，”Sources”和”Content scripts”后面有个”Snippets “标签，右键点击空区域，点”New”创建新的片段，写入一些代码，无论何时再想运行它时，右键点击选择”Run 运行”即可。

Firefox 6 + 的代码片段速记器（开发工具右上角小本子图标）跟这很类似。

性能

禁用浏览器缓存

每个浏览器都可以禁用网页的缓存，确保资源每次都从服务器加载。

Chrome ，设置小齿轮里找，”General”-> “Disable cache”。

IE 菜单栏的”Cache 缓存”下面。

Opera，点击网络标签清除缓存，选择”网络选项”-> “禁用所有缓存”

Firebug，网络标签 -> 下拉菜单”禁用浏览器缓存”

在任何浏览器呼出清除缓存对话框，Ctrl + Shift + Delete（Windows），Shift + Cmd + Backspace（Mac）。

排序网络请求找到瓶颈

在网络标签按顺序显示每个请求的资源，点击每列的标题可以重新排序。

大部分的浏览器在网络标签共享公共字段，你可以通过文件名；域名；资源类型；HTTP 状态；方法和资源大小这些字段排序。

在 IE 中，文件名和域名字段合并了。

Chrome 更进一步，点击”Timeline”字段显示额外的排序选项：

- Start Time 默认选项，按每个请求开始时间排序

- Response Time 按网络请求获得响应的时间排序

- End Time 按请求完成时间排序

- Duration 按请求完成花费时间排序

- Latency 浏览器初始请求到接收响应的时间总和。以等待时间排序，可以看看哪个资源占用了大量时间等待响应。等待时间依赖于用户距服务器的距离，设置 Content Delivery Networks （CDN）可以改善此时间。合并 CSS 和 JavaScript 文件，图像拼接可以减少资源请求数，因此减少总延迟。

网络时间轴导出为 HAR 文件

HAR（HTTP 存档）文件可以用于各种性能分析技术和调试。测试提 bug 时可以附上 HAR 文件 - 开发人员可以在本地运行 HAR 数据查找问题原因。

我们可以用 Chrome 开发工具导出网络标签时间轴，右键点击网络输入，选择”Save as HAR with Content”。

Firebug 需要另安装插件 Net-export，此工具由 Firebug 开发主管和 HAR 格式创造者开发。

chromeHAR 是个在线工具，提供跟 Chrome 一样的时间轴界面，功能类似。

检查 DOMContentLoad 和 Load 事件

Chrome 和 Safari （以及 Firebug 网络面板）的网络时间轴显示网页加载有多快，用一条线标记 DOMContentLoaded 和 load 事件触发的时机。

- 当浏览器解析文档完毕（但是其他资源比如图像，样式表可能未下载完毕）DOMContentLoaded 触发，它用蓝线标识。

- 当所有初始资源（图像，样式表，JavaScript）加载完毕，load 事件触发一次，它用红线标识。

- 当两个事件同时触发，标识线是紫色的。

在 Safari ，标识线是虚线。

重发送 XHR 请求

如果希望重发送 XHR 请求，但不想刷新页面或重触发事件，可以右键点击资源，选择”Replay XHR”（Firebug 叫”Resend”）。

测量渲染性能和 FPS

Chrome 提供了帧率时间轴，可以逐帧调试网站。

要创建帧时间轴，首先打开 Chrome 开发工具，选择”Timeline”标签，底部黑色的圆形代表”record 记录”，按下开始时间轴记录，按第二次停止记录。记录的同时，你可以跟网页正常交互，帧模式会记录所有帧的行为。

时间轴图表每一条代表单帧动画，不同的颜色表示如下： 蓝色表示加载任务，黄色表示脚本任务，紫色表示渲染任务，绿色表示绘制任务，白色区域代表空闲时间。

时间轴图表下面是网页性能的瀑布图，帧显示在标题列，标题单元格还包含画这帧花费的毫秒数；相应的动作也记录在左侧。

你可以拖动两个灰色的鼠标滑块，改变你想检查的帧的数量。

悬停在时间轴的标题行显示帧的持续时间；FPS 数值；CPU 时间和与帧交互的合计时间。

悬停在左侧的记录上面，可以看到每个任务的持续时间；还有其它有用信息。如果有页面相关的部分，则会高亮，有些任务被分组了，点击瀑布图的箭头查看。

移动端

开发工具调试 IOS

把 IOS 设备连接到可用的 Mac，打开 Mac 和 IOS 设备的 Safari 。

找到 Safari 的”Develop 开发”菜单，第一个菜单分隔线的后面应该是你要连接的 IOS 设备的名字。在子菜单选择你想调试的页面。

Safari 的开发工具将以弹出窗口的式出现，你可以调试移动设备的站点了。

开发工具调试 Android

你可以用Mac 上的 Chrome Canary 开发工具调试安卓设备上的公共和本地网站，你可以在手机上访问 Chrome 开发工具的广泛的特性集。

首先，需要在安卓设备安装 Chrome BETA 。

然后，需要下载 ADB 插件扩展，安装到 Chrome Canary 上。从未在 Google Play 商店下载过的话，需要拖拽文件到扩展页 （chrome://extensions/）。

确保已经在 chrome://flags 里面打开”Enable Developer Tools experiments 启用开发工具实验”。

手机用 USB 线插到电脑上，在手机找到”设置”，选择”开发人员选项”，确保”USB 调试”选上。如果它已经选上，而你以前从未用过 USB 调试，取消选择，重选一次，确保它有此计算机的 MAC 地址。

现在到安卓上的 Chrome BETA ，点击菜单图标和”Settings 设置”，确保”Enable USB Web debugging 启用 USB Web 调试”启用。打开新标签。

在 Chrome Canary ，点击 ADB 插件图标，点击”Start ADB”，需要重启浏览器。

访问检查页（chrome://inspect ），找到设备（需要 Chrome Canary 28 +），找到要调试的标签。点击页面 URL 右侧的”Inspect 检查”链接。

弹出”Settings 设置”窗口，点击”Experiments 实验”标签，启用”Reverse Port Forwarding “，你需要关闭窗口重启开发工具，”Port Forwarding”标签出现之前，再点”Inspect 查看”链接。

在 Port Forwarding 标签，输入想转发的端口（例如 9000），地址，应该可以映射到本地的电脑了。现在，在移动设备输入 localhost:端口号（如 localhost:9000），本地的站点应该加载到移动设备上了，并且可以调试了。

扩展

覆盖地理位置

在 Firefox ，位置 API 可以像 Chrome 一样覆盖，需要 Geolocater 扩展 。

安装后到”Tools”工具菜单，”Geolocater”，”Manage 管理”，在这你可以通过浏览地图或搜索位置，直接添加”伪造的”地理位置。你可以覆盖先前预设的地理位置。可以到 html5demos for Geolocation 页试试。

原文链接：http://jinlong.github.io/blog/2013/08/29/devtoolsecrets/ （本内容由互联网资料整理而成）

JavaScript与有限状态机

有限状态机（Finite-state machine）是一个非常有用的模型，可以模拟世界上大部分事物。

简单说，它有三个特征：

* 状态总数（state）是有限的。
* 任一时刻，只处在一种状态之中。
* 某种条件下，会从一种状态转变（transition）到另一种状态。

它对JavaScript的意义在于，很多对象可以写成有限状态机。

举例来说，网页上有一个菜单元素。鼠标悬停的时候，菜单显示；鼠标移开的时候，菜单隐藏。如果使用有限状态机描述，就是这个菜单只有两种状态（显示和隐藏），鼠标会引发状态转变。

代码可以写成下面这样：

var menu = {

// 当前状态
currentState: 'hide',

// 绑定事件
initialize: function() {
var self = this;
self.on("hover", self.transition);
},

// 状态转换
transition: function(event){
switch(this.currentState) {
case "hide":
this.currentState = 'show';
doSomething();
break;
case "show":
this.currentState = 'hide';
doSomething();
break;
default:
console.log('Invalid State!');
break;
}
}

};

可以看到，有限状态机的写法，逻辑清晰，表达力强，有利于封装事件。一个对象的状态越多、发生的事件越多，就越适合采用有限状态机的写法。

另外，JavaScript语言是一种异步操作特别多的语言，常用的解决方法是指定回调函数，但这样会造成代码结构混乱、难以测试和除错等问题。有限状态机提供了更好的办法：把异步操作与对象的状态改变挂钩，当异步操作结束的时候，发生相应的状态改变，由此再触发其他操作。这要比回调函数、事件监听、发布/订阅等解决方案，在逻辑上更合理，更易于降低代码的复杂度。

下面介绍一个有限状态机的函数库Javascript Finite State Machine。这个库非常好懂，可以帮助我们加深理解，而且功能一点都不弱。

该库提供一个全局对象StateMachine，使用该对象的create方法，可以生成有限状态机的实例。

var fsm = StateMachine.create();

生成的时候，需要提供一个参数对象，用来描述实例的性质。比如，交通信号灯（红绿灯）可以这样描述：

var fsm = StateMachine.create({

initial: 'green',

events: [
{ name: 'warn',  from: 'green',  to: 'yellow' },
{ name: 'stop', from: 'yellow', to: 'red' },
{ name: 'ready',  from: 'red',    to: 'yellow' },
{ name: 'go', from: 'yellow', to: 'green' }
]

});

交通信号灯的初始状态（initial）为green，events属性是触发状态改变的各种事件，比如warn事件使得green状态变成yellow状态，stop事件使得yellow状态变成red状态等等。

生成实例以后，就可以随时查询当前状态。

* fsm.current ：返回当前状态。
* fsm.is(s) ：返回一个布尔值，表示状态s是否为当前状态。
* fsm.can(e) ：返回一个布尔值，表示事件e是否能在当前状态触发。
* fsm.cannot(e) ：返回一个布尔值，表示事件e是否不能在当前状态触发。

Javascript Finite State Machine允许为每个事件指定两个回调函数，以warn事件为例：

* onbeforewarn：在warn事件发生之前触发。
* onafterwarn（可简写成onwarn） ：在warn事件发生之后触发。

同时，它也允许为每个状态指定两个回调函数，以green状态为例：

* onleavegreen ：在离开green状态时触发。
* onentergreen（可简写成ongreen） ：在进入green状态时触发。

假定warn事件使得状态从green变为yellow，上面四类回调函数的发生顺序如下：onbeforewarn → onleavegreen → onenteryellow → onafterwarn。

除了为每个事件和状态单独指定回调函数，还可以为所有的事件和状态指定通用的回调函数。

* onbeforeevent ：任一事件发生之前触发。
* onleavestate ：离开任一状态时触发。
* onenterstate ：进入任一状态时触发。
* onafterevent ：任一事件结束后触发。

如果事件的回调函数里面有异步操作（比如与服务器进行Ajax通信），这时我们可能希望等到异步操作结束，再发生状态改变。这就要用到transition方法。

fsm.onwarn = function(){
light.fadeOut('slow', function() {
fsm.transition();
});
return StateMachine.ASYNC;
};

上面代码的回调函数里面，有一个异步操作（light.fadeOut）。如果不希望状态立即改变，就要让回调函数返回一个StateMachine.ASYNC对象，表示状态暂时不改变；等到异步操作结束，再调用transition方法，使得状态发生改变。

Javascript Finite State Machine还允许指定错误处理函数，当发生了当前状态不可能发生的事件时自动触发。

var fsm = StateMachine.create({
// ...
error: function(eventName, from, to, args, errorCode, errorMessage) {
return 'event ' + eventName + ': ' + errorMessage;
},
// ...
});

比如，当前状态是green，理论上这时只可能发生warn事件。要是这时发生了stop事件，就会触发上面的错误处理函数。

Javascript Finite State Machine的基本用法就是上面这些，更详细的介绍可以参见它的主页。

（完）

原文链接：http://www.ruanyifeng.com/blog/2013/09/finite-state_machine_for_javascript.html （本内容由互联网资料整理而成）

Semantic CSS With Intelligent Selectors--使用智能选择器语义化CSS

“Form ever follows function. This is the law.” So said the architect and “father of skyscrapers” Louis Sullivan. For architects not wishing to crush hundreds of innocent people under the weight of a colossal building, this rule of thumb is pretty good. In design, you should always lead with function, and allow form to emerge as a result. If you were to lead with form, making your skyscraper look pretty would be easier, but at the cost of producing something pretty dangerous.

So much for architects. What about front-end architects — or “not real architects,” as we are sometimes known? Do we abide by this law or do we flout it?

With the advent of object-oriented CSS (OOCSS), it has become increasingly fashionable to “decouple presentation semantics from document semantics.” By leveraging the undesignated meanings of classes, it is possible to manage one’s document and the appearance of one’s document as curiously separate concerns.

In this article, we will explore an alternative approach to styling Web documents, one that marries document semantics to visual design wherever possible. With the use of “intelligent” selectors, we’ll cover how to query the extant, functional nature of semantic HTML in such a way as to reward well-formed markup. If you code it right, you’ll get the design you were hoping for.

If you are like me and have trouble doing or thinking about more than one thing at a time, I hope that employing some of these ideas will make your workflow simpler and more transferable between projects. In addition, the final section will cover a more reactive strategy: We’ll make a CSS bookmarklet that contains intelligent attribute selectors to test for bad HTML and report errors using pseudo-content.

Intelligent Selectors

With the invention of style sheets came the possibility of physically separating document code from the code used to make the document presentable. This didn’t help us to write better, more standards-aware HTML any more than the advent of the remote control resulted in better television programming. It just made things more convenient. By being able to style multiple elements with a single selector (p for paragraphs, for instance), consistency and maintenance became significantly less daunting prospects.

The p selector is an example of an intelligent selector in its simplest form. The p selector is intelligent because it has innate knowledge of semantic classification. Without intervention by the author, it already knows how to identify paragraphs and when to style them as such — simple yet effective, especially when you think of all of the automatically generated paragraphs produced by WYSIWYG editors.

So, if that’s an intelligent selector, what’s an unintelligent one? Any selector that requires the author to intervene and alter the document simply to elicit a stylistic nuance is an unintelligent selector. The class is a classic unintelligent selector because it is not naturally occurring as part of semantic convention. You can name and organize classes sensibly, but only with deliberation; they aren’t smart enough to take care of themselves, and browsers aren’t smart enough to take care of them for you.

Unintelligent selectors are time-intensive because they require styling hooks to be duplicated case by case. If we didn’t have p tags, we’d have to use unintelligent selectors to manufacture paragraphs, perhaps using .paragraph in each case. One of the downsides of this is that the CSS isn’t portable — that is, you can’t apply it to an HTML document without first going through the document and adding the classes everywhere they are required.

Unintelligent selectors at times seem necessary, or at least easier, and few of us are willing to rely entirely on intelligent selectors. However, some unintelligent selectors can become “plain stupid” selectors by creating a mismatch between document structure and presentation. I’ll be talking about the alarming frequency with which the unintelligent .button selector quickly becomes plain stupid.

Vive la Différence

Intelligent selectors are not confined just to the basic elements offered to us in HTML’s specification. To build complex intelligent selectors, you can defer to combinations of context and functional attribution to differentiate basic elements. Some elements, such as <a>, have a multitude of functional differences to consider and exploit. Other elements, such as <p>, rarely differ in explicit function but assume slightly different roles according to context.

header p {
/* styles for prologic paragraphs */
}

footer p {
/* styles for epilogic paragraphs */
}

Simple descendent selectors like these are extremely powerful because they enable us to visually disclose different types of the same element without having to physically alter the underlying document. This is the whole reason why style sheets were invented: to facilitate physical separation without breaking the conceptual reciprocity that should exist between document and design.

Inevitably, some adherents of OOCSS treat the descendent selector with some suspicion, with the more zealous insisting on markup such as the example below, found in BEM’s “Definitions” documentation.

<ul class="menu">
<li class="menu__item">…</li>
<li class="menu__item">…</li>
</ul>

I won’t cover contextual selectors any further because, unless you have a predilection for the kind of overprescription outlined above, I’m sure you already use them every day. Instead, we’ll concentrate on differentiation by function, as described in attributes and by attribute selectors.

Hyperlink Attributes

Even those who advocate for conceptual separation between CSS and HTML are happy to concede that some attributes — most attributes besides classes and custom data attributes, in fact — have an important bearing on the internal functioning of the document. Without href, your link won’t link to anything. Without type, the browser won’t know what sort of input to render. Without title, your abbr could be referring to either the British National Party or Banco Nacional de Panama.

Some of these attributes may improve the semantic detail of your document, while others are needed to ensure the correct rendering and functioning of their subject elements. If they’re not there, they should be, and if they are there, why not make use of them? You can’t write CSS without writing HTML.

The rel Attribute

The rel attribute emerged as a standard for link relations, a method of describing some specific purpose of a link. Not all links, you see, are functionally alike. Thanks to WordPress’ championing, rel="prev" and rel="next" are two of the most widely adopted values, helping to describe the relationship between individual pages of paginated blog content. Semantically, an a tag with a rel attribute is still an a tag, but we are able to be more specific. Unlike with classes, this specificity is semantically consequential.

The rel attribute should be used where appropriate because it is vindicated by HTML’s functional specification and can therefore be adopted by various user agents to enhance the experience of users and the accuracy of search engines. How, then, do you go about styling such links? With simple attribute selectors, of course:

[rel="prev"] {
/* styling for "previous links" */
}

[rel="next"] {
/* styling for "next" links */
}

Attribute selectors like these are supported by all but the most archaic, clockwork browsers, so that’s no reason not to use them anywhere the attributes exist. In terms of specificity, they have the same weight as classes. No woe there either, then. However, I recall it being suggested that we should decouple document and presentation semantics. I don’t want to lose the rel attributes (Google has implemented them, for one thing), so I’d better put an attribute that means nothing on there as well and style the element via that.

<a href="/previous-article-snippet/" rel="prev" class="prev">previous page</a>

The first thing to note here is that the only part of the element above that does not contribute to the document’s semantics is the class. The class, in other words, is the only thing in the document that has nothing functionally to do with it. In practice, this means that the class is the only thing that breaks with the very law of separation that it was employed to honor: It has a physical presence in the document without contributing to the document’s structure.

OK, so much for abstraction, but what about maintenance? Accepting that we’ve used the class as our styling hook, let’s now examine what happens when some editing or refactoring has led us to remove some attributes. Suppose we’ve used some pseudo-content to place a left-pointing arrow before the [rel="prev"] link’s text:

.prev:before {
content: '\2190'; /* encoding for a left-pointing arrow ("←") */
}

Removing the class will remove the pseudo-content, which in turn will remove the arrow (obviously). But without the arrow, nothing remains to elucidate the link’s extant prev relationship. By the same token, removing the rel attribute will leave the arrow intact: The class will continue to manage presentation, all the time disguising the nonexistence of a stated relationship in the document. Only by applying the style directly, via the semantic attribute that elicits it, can you keep your code and yourself honest and accurate. Only if it’s really there, as a function of the document, should you see it.

Attribute Substrings

I can imagine what you’re thinking: “That’s cute, but how many instances are there really for semantic styling hooks like these on hyperlinks? I’m going to have to rely on classes at some point.” I dispute that. Consider this incomplete list of functionally disimilar hyperlinks, all using the a element as their base:

- links to external resources,

- links to secure pages,

- links to author pages,

- links to help pages,

- links to previous pages (see example above),

- links to next pages (see example above again),

- links to PDF resources,

- links to documents,

- links to ZIP folders,

- links to executables,

- links to internal page fragments,

- links that are really buttons (more on these later),

- links that are really buttons and are toggle-able,

- links that open mail clients,

- links that cue up telephone numbers on smartphones,

- links to the source view of pages,

- links that open new tabs and windows,

- links to JavaScript and JSON files,

- links to RSS feeds and XML files.

That’s a lot of functional diversity, all of which is understood by user agents of all sorts. Now consider that in order for all of these specific link types to function differently, they must have mutually differential attribution. That is, in order to function differently, they must be written differently; and if they’re written differently, they can be styled differently.

In preparing this article, I created a proof of concept, named Auticons. Auticons is an icon font and CSS set that styles links automatically. All of the selectors in the CSS file are attribute selectors that invoke styles on well-formed hyperlinks, without the intervention of classes.

In many cases, Auticons queries a subset of the href value in order to determine the function of the hyperlink. Styling elements according to the way their attribute values begin or end or according to what substring they contain throughout the value is possible. Below are some common examples.

The Secure Protocol

Every well-formed (i.e. absolute) URL begins with a URI scheme followed by a colon. The most common on the Web is http:, but mailto: (for SMTP) and tel: (which refers to telephone numbers) are also prevalent. If we know how the href value of the hyperlink is expected to begin, we can exploit this semantic convention as a styling hook. In the following example for secure pages, we use the ^= comparator, which means “begins with.”

a[href^="https:"] {
/* style properties exclusive to secure pages */
}

In Auticons, links to secure pages become adorned with a padlock icon according to a specific semantic pattern, identifiable within the href attribute. The advantages of this are as follows:

- Links to secure pages — and only secure pages — are able to resemble links to secure pages by way of the padlock icon.

- Links to secure pages that cease to be true links to secure pages will lose the https protocol and, with it, the resemblance.

- New secure pages will adopt the padlock icon and resemble links to secure pages automatically.

This selector becomes truly intelligent when applied to dynamic content. Because secure links exist as secure links even in the abstract, the attribute selector can anticipate their invocation: As soon as an editor publishes some content that contains a secure link, the link resembles a secure one to the user. No knowledge of class names or complex HTML editing is required, so even simple Markdown will create the style:

[Link to secure page](https://payment.example.com/)

Note that using the [href^="https:"] prefix is not infallible because not all HTTPS pages are truly secure. Nonetheless, it is only as fallible as the browser itself. Major browsers all render a padlock icon natively in the address bar when displaying HTTPS pages.

File Types

As promised, you can also style hyperlinks according to how their href value ends. In practice, this means you can use CSS to indicate what type of file the link refers to. Auticons supports .txt, .pdf, .doc, .exe and many others. Here is the .zip example, which determines what the href ends with, using $=:

[href$=".zip"]:before,
[href$=".gz"]:before {
content: '\E004'; /* unicode for the zip folder icon */
}

Combinations

You know how you can get all object-oriented and use a selection of multiple classes on elements to build up styles? Well, you can do that automatically with attribute selectors, too. Let’s compare:

/* The CSS for the class approach */

.new-window-icon:after {
content: '[new window icon]';
}

.twitter-icon:before {
content: '[twitter icon]';
}

/* The CSS for the attribute selector approach */

[target="_blank"]:after {
content: '[new window icon]';
}

[href*="twitter.com/"]:before {
content: '[twitter icon]';
}

(Note the *= comparator, which means “contains.” If the value string contains the substring twitter.com/, then the style will be honored.)

<!-- The HTML for the class approach -->

<a href="http://twitter.com/heydonworks" target="_blank" class="new-window-icon twitter-icon">@heydonworks</a>

<!-- The HTML for the attribute selector approach -->

<a href="http://twitter.com/heydonworks" target="_blank">@heydonworks</a>

Any content editor charged with adding a link to a Twitter page now needs to know only two things: the URL (they probably know the Twitter account already) and how to open links in new tabs (obtainable from a quick Google search).

Inheritance

Some unfinished business: What if we have a link that does not match any of our special attribute selectors? What if a hyperlink is just a plain old hyperlink? The selector is an easy one to remember, and performance fanatics will be pleased to hear that it couldn’t be any terser without existing at all.

Flippancy aside, let me assure you that inheritance within the cascade works with attribute selectors just as it does with classes. First, style your basic a — perhaps with a text-decoration: underline rule to keep things accessible; then, progressively enhance further down the style sheet, using the attribute selectors at your disposal. Browsers such as Internet Explorer (IE) 7 do not support pseudo-content at all. Thanks to inheritance, at least the links will still look like links.

a {
color: blue;
text-decoration: underline;
}

a[rel="external"]:after {
content: '[icon for external links]';
}

Actual Buttons Are Actual

In the following section, we’ll detail the construction of our CSS bookmarklet for reporting code errors. Before doing this, let’s look at how plain stupid selectors can creep into our workflow in the first place.

Adherents of OOCSS are keen on classes because they can be reused, as components. Hence, .button is preferable to #button. I can think of one better component selector for button styles, though. Its name is easy to remember, too.

The <button> element represents a button.

– W3C Wiki

Topcoat is an OOCSS BEM-based UI framework from Adobe. The CSS for Topcoat’s various button styles is more than 450 lines if you include the comment blocks. Each of these comment blocks suggests applying your button style in a manner similar to this introductory example:

<a class="topcoat-button">Button</a>

This example is not a button. No, sir. If it were a button, it would be marked up using <button>. In fact, in every single browser known to man, if it were marked up as a button and no author CSS was supplied, you could count on it looking like a button by default. It’s not, though; it’s marked up using <a>, which makes it a hyperlink — a hyperlink, in fact, that lacks an href, meaning it isn’t even a hyperlink. Technically, it’s just a placeholder for a hyperlink that you haven’t finished writing yet.

A dog in a shark costume does not a shark make. (Image: reader of the pack)

The examples in Topcoat’s CSS are only examples, but the premise that the class defines the element and not the HTML is deceptive. No amount of class name modification via “meaningful hyphenation” can make up for this invitation to turn your unintelligent selector into a plain stupid one and to just code stuff wrong.

See No Evil, Hear No Evil

“If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.”

A link that resembles a button and triggers button-like JavaScript events is, to many, a button. However, this only means that it has passed the first two stages of the “duck test.” For all users to be able to apply inductive reasoning and discern the button as such, it must also quack like one. Because it remains a link, it will be announced by screen readers as “link,” meaning that your allegorical skyscraper is not wheelchair-accessible. Avoiding this kind of unnecessary confusion for assistive technology users is not a pursuit of semantic perfection but a responsibility we should undertake for real benefit.

Nonetheless, some will insist on using a as the basis of their buttons. Hyperlinks are (slightly) easier to restyle consistently, after all. If a is the element of choice, then there is only one way to make it a close-to-true button in the accessibility layer. You guessed it: You must apply another meaningful attribute in the form of a WAI ARIA role. To ensure that a hyperlink element looks like a button for good reason, apply only the following attribute selector.

[role="button"] {
/* semantic CSS for modified elements that are announced as “button” in assistive technologies */
}

Quality Assurance With Attribute Selectors

“CSS gives so much power to the class attribute, that authors could conceivably design their own “document language” based on elements with almost no associated presentation (such as DIV and SPAN in HTML) and assigning style information through the “class” attribute. Authors should avoid this practice since the structural elements of a document language often have recognized and accepted meanings.”

– “Selectors,” CSS Level 2, W3C

The reason we have two elements — a and button — is to semantically demarcate two entirely different types of functional interaction. While the hyperlink denotes a means to go somewhere, the button is intended as the instigator of an event or action. One is about traversal, the other about transformation. One facilitates disengagement, the other engagement.

To make sure we don’t do anything too daft and get our links and buttons muddled up, we will now build a CSS bookmarklet that uses intelligent attribute selectors to test the validity and quality of the two respective elements.

Inspired partly by Eric Meyer’s post and taking a few cues from DiagnostiCSS, this style sheet will combine attribute selectors and the :not selector (or negation pseudo-class) to highlight problems in the HTML. Unlike these other two implementations, it will write an error to the screen using pseudo-content. Each error will be written in Comic Sans against a pink background.

By connecting function directly to form, we see that ugly markup results in ugly CSS. Consider this the revenge of an abused document, exacted on its designer. To try it out, drag revenge.css to your bookmarks, and click the bookmark to trigger it on any page that you fancy (Facebook is good):

REVENGE.CSS
Drag to your bookmarks bar.

Rule 1

“If it’s a hyperlink, it should have an href attribute.”

a:not([href]):after {
content: 'Do you mean for this to be a link or a button, because it does not link to anything!';
display: block !important;
background: pink !important;
padding: 0.5em !important;
font-family: 'comic sans ms', cursive !important;
color: #000 !important;
font-size: 16px !important;
}

Notes: In this example, we are testing not the attribute’s value, but whether the attribute exists in the first place — that is, whether [href] matches any element with an href attribute. This test is only appropriate on hyperlinks, hence the a prefix. The rule reads like, “For every a element that is not also an [href] element, append some pseudo-content with an error notice.”

Rule 2

“If it’s a hyperlink and has an href attribute, it should have a valid value.”

a[href=""]:after, a[href$="#"]:after, a[href^="javascript"]:after {
content: 'Do you mean for this link to be a button, because it does not go anywhere!';
/*... ugly styles ...*/
}

Notes: If the href is empty, ends in a # or is using JavaScript, it’s probably being used as a button without the correct button element. Note that I am using “starts with javascript.” Standard practice for voiding hrefs is to use javascript:void(0), but we can’t depend on that always being written in the same way (with or without a space after the colon, for example).

Rule 3

“If it uses a button class, it should be a button — at least in the accessibility layer.”

.button:not(button):not([role="button"]):not([type="button"]):not([type="submit"]):not([type="reset"]):after,
.btn:not(button):not([role="button"]):not([type="button"]):not([type="submit"]):not([type="reset"]):after,
a[class*="button"]:not([role="button"]):after {
content: 'If you are going to make it look like a button, make it a button, damn it!';
/*... ugly styles ...*/
}

Notes: In this example, we’re demonstrating how you can chain negation when testing for attributes. Each selector reads like this: “If the element has a class that says it’s a button but it’s not a button element and it doesn’t have the correct role to make it a button in the accessibility layer and it’s not an input being used as a button, then… well, you’re lying.” I’ve had to use [class*="button"] to catch the many Topcoat class variations (62 in total!) that fail to enforce actual buttons on hyperlinks. I’ve noticed that some authors use button-container and the like on parent elements, which is why the a qualifier is included to avoid false positives. You may recognize the .btn class from Twitter Bootstrap, which (if you’ve read the component’s documentation carefully) you’ll know is also unsure about whether links or buttons are buttons.

Rule 4

“If it is an a element with role="button", then it should link to somewhere when JavaScript is off.”

a[role="button"]:not([href*="/"]):not([href*="."]):not([href*="?"]):after {
content: 'Either use a link fallback, or just use a button element.';
/*... ugly styles ...*/
}

Notes: We can be fairly sure that hrefs that do not include one of /, . (usually to precede a file extension) or ? (to start a query string) are probably bogus. Getting links to act as buttons and return: false when JavaScript is on is fine — fine, that is, if they have a page to go to when JavaScript is off. In fact, it’s the only legitimate reason I can think of not to use <button> instead.

Rule 5

“You can’t disable a hyperlink.”

a.button[class*="disabled"]:after,
a.btn.disabled:after,
a[class*="button"][class*="disabled"]:after {
content: 'You cannot disable a hyperlink. Use a button element with type="disabled".';
/*... ugly styles ...*/
}

Notes: Even ancient user agents understand the disabled attribute, so use it with an appropriate element in a compliant way. You can concatenate attribute selectors just as you can concatenate classes: In the last of the three selectors, we’re saying, “If it’s a link that contains the substring button and the substring disabled, then print an error message.” Twitter Bootstrap uses the second form, .btn.disabled, in its style sheet, but not with the a prefix. We’ll only consider it an error if used on hyperlinks.

Rule 6

“Buttons in forms should have explicit types.”

form button:not([type]):after {
content: 'Is this a submit button, a reset button or what? Use type="submit", type="reset" or type="button"';
}

Notes: We need to determine whether buttons within forms have explicit types, because some browsers will treat any button in this context without a specified type as type="submit". We want to be absolutely sure that the form won’t submit if our button has a different purpose.

Rule 7

“Both hyperlinks and buttons should have some sort of content or an ARIA label.”

a:empty:not([aria-label]):not([aria-labelledby]):after,
button:empty:not([aria-label]):not([aria-labelledby]):after,
button:not([aria-label]):not([aria-labelledby]) img:only-child:not([alt]):after,
a:not([aria-label]):not([aria-labelledby]) img:only-child:not([alt]):after {
content: 'All buttons and links should have text content, an image with alt text or an ARIA label';
/*... ugly styles ...*/
}

Notes: Buttons and links that don’t include any kind of direction for their usage — in either textual or graphical form — are pretty bogus. These final two selectors are perhaps the most complex I’ve ever written. For the hyperlink version, the selector reads something like this: “If it is a hyperlink that does not have either an aria-label attribute or an aria-labelledby attribute and it contains only an image as content but this image does not have an alt attribute, then write the ugly error message.” Also, note the use of the :empty selector. Arguably, no element that is not self-closing should ever be left empty.

Ten points to the first person using revenge.css who can tell me where I’ve broken my own rule in this very article. Trust me, the error is definitely there.

Conclusion

The reason I use the kinds of selectors and patterns described above is not to try something different or to have something new to write about. Attribute selectors aren’t, by themselves, anything new anyway. IE 6 is the only browser that doesn’t support them. The reason I use them is because I simply do not have the time or mental capacity to “do” HTML and CSS in parallel. My brain just isn’t good enough for that. The reason I style my page headers with [role="banner"] and not .page-header is because that’s the only way I’ll know — upon seeing the intended visual effect — that I’ve put the navigable landmark in place. How else does one keep track? You can’t just leave it to testing, because then it’s usually too late.

There’s no such thing as semantic CSS. There’s only semantic HTML and its visible form. In this article I have tried to demonstrate that, by coupling the function and form of Web pages directly, you can create mechanisms for reward and punishment. On the one hand, you can set up selectors that invoke visual motifs only when the suitable markup is used. On the other hand, you can query the markup for bad patterns and erode the visual design as a commitment to the underlying ugly truth.

It’s true that not all the styling hooks in your arsenal will likely ever be uniformly semantic or intelligent. Classes are often desirable as polyfills for much needed elements or attributes that have yet to be standardized. That’s how .footer became <footer> and type="text" (with a bunch of JavaScript) became type="url". Other times, they are helpful for doing non-semantic layout scaffolding with grid frameworks and the like.

However, if you are committed to giving CSS its own completely separate logic, then you are bound to create unnecessary arguments between form and function. In this eventuality, only constant vigilance can protect against inaccessibility and invalidity. To make matters worse, trying to manufacture pseudo-semantics purely with classes makes it easy to fall into one of those interminable discussions over what makes a semantic class name. You’ll start spending less time using the remote to control the TV and more time just sitting there, contemplating the remote control held in your hand.

Life is too short.

(al) (ea)

原文链接：http://coding.smashingmagazine.com/2013/08/20/semantic-css-with-intelligent-selectors/ （本内容由互联网资料整理而成）

CSS3的calc()使用

calc()对大家来说，或许很陌生，不太会相信calc()是css中的部分。因为看其外表像个函数，既然是函数为何又出现在CSS中呢？这一点也让我百思不得其解，今天有一同事告诉我，说CSS3中有一个属性能实现自适应的布局，首先让我想到的是box-sizing，但跟我说还可以计算，这让我不得不想起calc()。因为早先在官网和一些blog上看到相关的介绍，但一直没有深入，也没有自己去测试过。今天花了一下午的时间彻底学习了一下calc()。于是就有了这篇blog，希望对大家有所帮助。

平时在制作页面的时候，总会碰到有的元素是100%的宽度。众所周知，如果元素宽度为100%时，其自身不带其他盒模型属性设置还好，要是有别的，那将导致盒子撑破。比如说，有一个边框，或者说有margin和padding，这些都会让你的盒子撑破。我们换句话来说，如果你的元素宽度是100%时，只要你在元素中添加了border,padding,margin任何一值，都将会把元素盒子撑破（标准模式下，除IE怪异模式）。这样一来就会相当的麻烦，平时我们碰到这样的现象时，也是相当的谨慎，有时甚至无法解决，只能通过改变结构来实现。就算你通过繁琐的方法实现了，但有于浏览器的兼容性而导致最终效果不一致。虽然前面介绍的CSS3属性中的box-sizing在一定程度上解决这样的问题，其实今天的calc()函数功能实现上面的效果来得更简单。

什么是calc()?

学习calc()之前，我们有必要先知道calc()是什么？只有知道了他是个什么东东？在实际运用中更好的使用他。

calc()从字面我们可以把他理解为一个函数function。其实calc是英文单词calculate(计算)的缩写，是css3的一个新增的功能，用来指定元素的长度。比如说，你可以使用calc()给元素的border、margin、pading、font-size和width等属性设置动态值。为何说是动态值呢?因为我们使用的表达式来得到的值。不过calc()最大的好处就是用在流体布局上，可以通过calc()计算得到元素的宽度。

calc()能做什么？

calc()能让你给元素的做计算，你可以给一个div元素，使用百分比、em、px和rem单位值计算出其宽度或者高度，比如说“width:calc(50% + 2em)”，这样一来你就不用考虑元素DIV的宽度值到底是多少，而把这个烦人的任务交由浏览器去计算。

calc()语法

calc()语法非常简单，就像我们小时候学加 （+）、减（-）、乘（*）、除（/）一样，使用数学表达式来表示：

.elm {
width: calc(expression);
}

其中"expression"是一个表达式，用来计算长度的表达式。

calc()的运算规则

calc()使用通用的数学运算规则，但是也提供更智能的功能：

1. 使用“+”、“-”、“*” 和 “/”四则运算；

2. 可以使用百分比、px、em、rem等单位；

3. 可以混合使用各种单位进行计算；

4. 表达式中有“+”和“-”时，其前后必须要有空格，如"widht: calc(12%+5em)"这种没有空格的写法是错误的；

5. 表达式中有“*”和“/”时，其前后可以没有空格，但建议留有空格。

浏览器的兼容性

浏览器对calc()的兼容性还算不错，在IE9+、FF4.0+、Chrome19+、Safari6+都得到较好支持，同样需要在其前面加上各浏览器厂商的识别符，不过可惜的是，移动端的浏览器还没仅有“firefox for android 14.0”支持，其他的全军覆没。

大家在实际使用时，同样需要添加浏览器的前缀

.elm {
/*Firefox*/
-moz-calc(expression);
/*chrome safari*/
-webkit-calc(expression);
/*Standard */
calc();
}

通过上面的了解，大家对calc()不在那么陌生，但对于实际的运用可能还是不太了解，那么大家就接下来跟我一起动手，通过实例来了解他吧。首先我们来看一个最常用的实例：

<div class="demo">
<div class="box"></div>
</div>

上面的结构很简单，就是一个div.demo的元素中包含了一个div.box的元素，接下来我们一步一步来看其中的变化。

第一步：添加普通样式：

.demo {
width: 300px;
background: #60f;
}
.box {
width: 100%;
background: #f60;
height: 50px;
}

此时的效果很简单，就是div.box完全遮盖了div.demo，如下图所示：

第二步，在div.box上添加border和padding

这一步很棘手的事情来了，在div.box上添加10px的内距padding，同时添加5px的border：

.demo {
width: 300px;
background: #60f;
}
.box {
width: 100%;
background: #f60;
height: 50px;
padding: 10px;
border: 5px solid green;
}

为了更好的说明问题，我在div.demo上添加了一个padding：3px 0;

.demo {
width: 300px;
background: #60f;
padding: 3px 0;
}
.box {
width: 100%;
background: #f60;
height: 50px;
padding: 10px;
border: 5px solid green;
}

这个时候大家不知道能否想到问题会发生在哪？其实很简单，这个时候div.box的宽度大于了其容器div.demo的总宽度，从而撑破容器伸出来了，如图所示：

第三步，calc()的运用

为了解决撑破容器的问题，以前我们只能去计算div.box的宽度，用容器宽度减去padding和border的值，但有时候，我们苦于不知道元素的总宽度，比如说是自适应的布局，只知道一个百分值，但其他的值又是px之类的值，这就是难点，死卡住了。随着CSS3的出现，其中利用box-sizing来改变元素的盒模型类型实使实现效果，但今天我们学习的calc()方法更是方便。

知道总宽度是100%，在这个基础上减去boder的宽度（5px * 2 = 10px）,在减去padding的宽度（10px * 2 = 20px），即"100% - (10px + 5px) * 2 = 30px" ，最终得到的值就是div.box的width值：

.demo {
width: 300px;
background: #60f;
padding: 3px 0;
}
.box {
background: #f60;
height: 50px;
padding: 10px;
border: 5px solid green;
width: 90%;/*写给不支持calc()的浏览器*/
width:-moz-calc(100% - (10px + 5px) * 2);
width:-webkit-calc(100% - (10px + 5px) * 2);
width: calc(100% - (10px + 5px) * 2);
}

这样一来，通过calc()计算后，div.box不在会超出其容器div.demo的宽度，如图所示：

上面是一个简单的实例，接下来我们一起来看一个自适应布局的例子：

上面的demo是一个非常简单而常见的布局效果，在这个布局中，我采用了自适应布局。整个布局包含了“头部”、“主内容”、“边栏”和“脚部”，并且“主内容”居左，“边栏”靠右，具体结构请看DEMO中的html部分。

接下来，我们主要看看css部分：

1、在body中设置一个内距，并附上一些基本的样式，大家可以根据自己需要进行不同的设置，此例代码如下：

body {
background: #E8EADD;
color: #3C323A;
padding: 20px;
}

2、设置主容器“wrapper”的样式

主容器的宽度是“100% - 20px * 2”,并且水平居中：

.wrapper {
width: 1024px; /* Fallback for browsers that don't support the calc() function */
width: -moz-calc(100% - 40px);
width: -webkit-calc(100% - 40px);
width: calc(100% - 40px);
margin: auto;
}

给不支持calc()的浏览器设置了一个固定宽度值“1024px”。

3、给header和footer设置样式

这个例子中的header和footer很简单，给他们添加了一个内距为20px，其他就是一些基本的样式设置，那么其对应的宽度应该是"100% - 20px * 2"：

#header {
background: #f60;
padding: 20px;
width: 984px;/*Fallback for browsers that don't support the calc() function*/
width: -moz-calc(100% - 40px);
width: -webkit-calc(100% - 40px);
width: calc(100% - 40px);
}
#footer {
clear:both;
background: #000;
padding: 20px;
color: #fff;
width: 984px;/* Fallback for browsers that don't support the calc() function */
width: -moz-calc(100% - 40px);
width: -webkit-calc(100% - 40px);
width: calc(100% - 40px);
}

4、给主内容设置样式

给主内容设置了一个8px的边框，20px的内距，并且向左浮动，同时设置了一个向右的外边距“20”px，关键之处，我们主内容占容器宽度的75%，这样一来，主内容的宽度应该是“75% - 8px * 2 - 20px * 2”:

#main {
border: 8px solid #B8C172;
float: left;
margin-bottom: 20px;
margin-right: 20px;
padding: 20px;
width: 704px; /* Fallback for browsers that don't support the calc() function */
width: -moz-calc(75% - 20px * 2 - 8px * 2);
width: -webkit-calc(75% - 20px * 2 - 8px * 2);
width: calc(75% - 20px * 2 - 8px * 2);
}

4、设置右边栏样式

给边栏设置了一个25%的宽度，其除了包含8px的边框，10px的内距外，还有主内容外距20px也要去掉，不然整个宽度与容器会相差20px,换句话说就会撑破容器掉下来。因此边栏的实际宽度应该是"25% - 10px * 2 - 8px * 2 -20px":

#accessory {
border: 8px solid #B8C172;
float: right;
padding: 10px;
width: 208px; /* Fallback for browsers that don't support the calc() function */
width: -moz-calc(25% - 10px * 2 - 8px * 2 - 20px);
width: -webkit-calc(25% - 10px * 2 - 8px * 2 - 20px);
width: calc(25% - 10px * 2 - 8px * 2 - 20px);
}

这样一来，大家就看到了上面demo展现的布局效果。经过此例的学习，大家是不是会觉得使用calc()用于自适应布局是超爽的呀。此时有很多同学肯定会感吧，苦逼的IE6-8不支持，不敢使用。

最后在给大家提供一个heihgt的实例：

时隔好久没有写blog，不知道大家对calc()整明白了没有，要是没有的话，继续动手写几个例子吧。如果您有更好的分享，记得告诉我们哟。

如需转载，烦请注明出处：http://www.w3cplus.com/css3/how-to-use-css3-calc-function.html

原文链接：http://www.w3cplus.com/css3/how-to-use-css3-calc-function.html （本内容由互联网资料整理而成）

Sass 的新特性调查

本文由大漠根据Hugo Giraudel的《Looking Into the Future of Sass》所译，整个译文带有我们自己的理解与思想，如果译得不好或不对之处还请同行朋友指点。如需转载此译文，需注明英文出处：http://davidwalsh.name/future-sass，以及作者相关信息

——作者：Hugo Giraudel

——译者：大漠

Sass是CSS的预处理器，这也是现在最常见讨论的一个话题。Sass最早是2007年由Hampton Catlin提出。Sass到现在已经走了很长的路了，到现在也是最常见的CSS预处理程序。

如果您还不知道他什么是Sass，我强烈推荐您阅读一下David Walsh写的这文章和Chris Coyier写的文章。

如果您不喜欢阅读英文文章，可以阅读W3cplus中有关于Sass的系列教程。

不管什么情况之下，我将假定您基本都了解Sass，你们当中有一些人甚至可是以Sass的铁杆粉丝！这些都不先考虑，如果有一篇博客将Sass的未来特性，那多好。

Sass3.3即将到来

这一段时间Nathan Weizenbaum和Chris Eppstein正致力于Sass3.3版本开发。截止今天，Sass3.3的alpha版本已经可以使用了（当然其中还有不足），但我相信官方版本将会很快公布（虽然没有具体发布日期）。

那什么是全新的Sass版本呢？里面有很多新东西，他们中的大多数并没有正式宣布做Sass3.3版本，所以我只有猜想：

从一个方面说明，如果你有机会参加2013年CSS峰会，你不要错过它。特别是Chris Eppstein将在峰会上谈论很多很棒的Sass3.3。

Sourcemaps

我认为Sass3.3版本最大的功能是具有Sourcemaps。其实Sourcemaps并不特定于Sass所有。它是一种与语言无关的方式映射到原始的生产代码之中，甚至是编译和压缩。这里有一篇相关的介绍。

在开发者工具中查看一个元素，如果你想编辑样式，比如说是style.css:1(你的样式文件中的第一行)。你是没有办法可以编辑CSS样式文件，但Sass文件可以。

这基本上是的Sass sourcemaps派上用场。而style.css:1刚好是component.scss:42编译出来的，这样不是更好吗？

你使用sourcemaps Sass工作流，可以分五个步骤：

- 你需要使用Chrome28+

- 确认你使用的是Sass3.3 Alpha(gem install sass --pre)

- 到chrome://flags中开启Developer Tools Experiments

- 打开开发者工具，并到General tab中选择Enable source maps

- 打开开发者工具，并到Experiments tab中选择Support for Sass

- 使用sass --watch --sourcemap编译你的样式文件

到此，你的浏览器就可以使用DevTools Sass roucemaps(.map文件)将你的产品代码映射到你的开发者代码中。你现在可以点击（文件名和样式）和访问你的Sass文件。

注：截至今天，如果你在使用Compass0.13版本，Sass3.3 Alpha还存在一些严重的问题。你不能使用compass watch，现在你要使用sass --compass --sourcemap --watch style.scss:style.css.更多信息可以点击这里查看。

有关于Sass sourcemap功能和开发者工具调试相关介绍，可以阅读《SASS调试》一文。

改善选择器&

你可能已经知道了参考选择器(&)。这是一个引用当前选择器用于嵌套规则，不能用于根级别嵌套（Sass抛出一个错误）。最简单的使用情况如下：

a {
color: tomato;

&:hover {
color: deepskyblue;
}
}

编译出来的CSS

a {
color: tomato;
}
a:hover {
color: deepskyblue;
}

这是最基本的。他们在这个参考选择器上取得了大量的改进，让我们看看其中的一对。

在选择器中使用&

修复了几个Bug，使用参考选择器在更复杂的选择器上，请参考下面的例子：

$base: ".module";
#{$base} {
&#{$base}-something {
/* ... */
}
}

在本例中，您为您的模块定义某种基本选择器，然后想应用样式到某个元素和派生选择器（.module和.module-something）。但按上面的代码写，编译代码时会报错：

error style.scss (Line 4: Invalid CSS after "    &#{$base}": expected "{", was "-something {""-something" may only be used at the beginning of a compound selector.)

在Sass下一个版本，我们将能够通过插值和参考选择器混合使用，参考资料。

$base: ".module";
#{$base} {
#{&}#{$base}-something {
/* ... */
}
}

当前，唯一的解决方法是从基本变量中删除.，并且显式的在选择器中使用：

$base: "module";
.#{$base} {
&.#{$base}-something {
/* ... */
}
}

转译出来的CSS：

.module.module-something {
/* ... */
}

这并不是怎么强大，因为在编码和在前嵌套选择器，迫使在编码中使用类名.。还是在等待新的&功能，对吗？

BEM-like语法

有一件事情我真的很期待，扩展选择器&能够运用在BEM语法上。如果你不是很熟悉BEM语法，我强烈建议你读一下这个帖子。

如果你想了解更多有关于BEM相关的知识，可以点击w3cplus发表的有关于BEM教程。

问题是在使用Sass的嵌套。让我们来看一个简单的例子：

.block {
/* Base stuff */
}

.block__child {
/* Sub-element of block */
}

.block--modifier {
/* Variation of block */
}

这是你想要的。对吗？不幸的是，你不能在嵌套中使用（没有任何嵌套）。如果我们能像下面这样使用：

.block {
/* Base stuff */
&__child {
/* Sub-element of block */
}
&--modifier {
/* Variation of block */
}
}

这将是可怕的。最好的语法，但截至今天，编译上面的代码仍然会报错：

error style.scss (Line 4: Invalid CSS after "    &": expected "{", was "__child {"
"__child" may only be used at the beginning of a compound selector.)

舍得庆幸的是，他们将提高参考选择器在这种语法上的某种程序上的使用（详细参考这里）。快速笔记，我们将不得不使用插入选择器：#{&}__child。这也没什么大不了的。

绑定父元素

这个例子是Ericam从Susy框架中提出的（参考这里）。他创建了一个mixin，使用参考选择器来制作了适合IE浏览器的@media规则：

@mixin respond-to($media, $ie-class:'ie') {
@media (#{$media}) { @content; }
// We need the parent selector here in order to mimic the @media bubbling.
.#{$ie-class} & { @content; }
}

想法很简单：他被称为mixin，给@media传递一个有效的值，在大括号中写上所有想要的样式。这些样式将显示在一个@media块中。此外，通过参考选择器为IE创建另一个样式块。

// This works already.
.container {
@include respond-to('min-width: 30em') {
color: red;
}
}

// This doesn't work.
@include respond-to('min-width: 30em') {
.container { color: red; }
}

从内部调用mixin选择器工作是很强大的。然而从根标签调用mixin，Sass会报错(基本规则是不能包含父选择器引用字符&)。这是因为&选择器不能用于根一极。

可以理解的。然而它应该可用。这将防止Sass在这种情况之下报错，比如这个例子。希望在新的版本之中能解决这个问题，详细讨论可以参考这里。

改善if()函数

你听过if()函数吗？这是一个众所周知的三元判断variable = condition ? true : false(javasctipr，PHP)。他像下面这样工作：

$a: 10;
$b: if($a > 5, blue, red); // blue

除了一个小问题，这个函数没有条件价值。把它简单，功能的工作原理是这样的：

- 检查条件

- 评估真的结果

- 评估错的结果

- 分配显示结果

当它应该是这样的工作的：

这看起来好像我很挑剔，但在这种情况下，一个结果不应该被显示。如下面的例子：

@function dosomething($argument) {
$second-item: if(
type-of($argument) == list,
nth($argument, 2),
$argument
);
@return $second-item;
}

// This works like a charm
dosomething( (item-1, item-2) );

// This throws an error
dosomething( only-item );

如果给定的参数是一个列表，那么函数返回列表中的第二个列表项；如果给定的参数不是一个列表，那么函数返回他的参数。不幸的是，这个函数，如果传的参数只是一个就会报错。

这个不应该失败。正常的行为会检查条件，在目前的情况下意识到这是错误的，所以会跳到第三点，甚至没有试图解析第二点。不幸的是if()解析了一切。

所以他们决定在内置解析器解决if()问题，详细请参考这里。

行进的操作列表

Sass提供了相当多的函数来操作列表。他们功能都是非常强大的，尤其是join()函数，可以将一个列表附加到另一个列表中。他们正在考虑通过+操作符来操作列表，详细请阅读这里。

$a: item-1, item-2, item-3;
$b: item-4, item-5, item-6;
/* Same as
* $c: join($a, $b);
*/
$c: $a + $b; // item-1, item-2, item-3, item-4, item-5, item-6

直到目前这只是一种想像，但尽管如此，我认为这是不错的。现在Crhis甚至还提出使用减号-来操作列表：

$a: item-1, item-2, item-3;
$b: item-3, item-4, item-1;
$c: $a - $b; // item-1, item-2, item-3, item-4

减号-操作符应该删除掉第一列中具有的第二列的列表项。这可能是一个强大的功能，当你想要删除你想要删除的。包括false和null值：

$a: item-1, false, item-2, null, item-3;
/* Same as
* $a: reject($a, false);
* $a: reject($a, null);
*/
$a: $a - (false, null); // item-1, item-2, item-3

即使这是可能的，但Nathan似乎对此不太感兴趣——需要以唯一的语言来实施，就像Ruby一样，但并不是每个人都是熟悉Ruby。

列表就要介绍完了，我听到一个nth()函数，可以用来获取列表的第n个列表项，他可以接受负值，从列表的末尾开始索引列表项，而不是初始值（请参考这里）。为了得到列表中的最后一个列表项，你可以这样操作：

$list: a b c d e;
$last-item: nth($list, length($list)); // Old way
$last-item: nth($list, -1); // New way

一个新函数list-separator()

这是一个很小的飞跃，但我人为做Sass列表成员之一是非常不错的。

他们计算增加一个list-separator()函数用来决定一个列表中列表项的分隔符号是空格还是逗号（详情请点这里）。使用相当简单：

$a: item-1, item-2, item-3;
$b: item-1 item-2 item-3;
list-separator($a) -> comma
list-separator($b) -> space

函数返回逗号或空格。因为每管委会值在Sass中都被视为一个列表，通过一个单元素值将返回空格。

支持Maps

我花了一些时间来了解这个，他们似乎想让Sass3.3支持map功能（详细请点这里）。maps就像一个关联数组。一个A元素在B元素中的列表：

map = {
A: B,
C: D
}

这就是一个map，类似于JSON语言。到今天为止，我还不确定在一两层列表中Map有什么好处。这里有一个模拟Sass列表嵌套的例子：

$map: (
A B,
C D
);

@each $pair in $map {
$first-item  : nth($pair, 1);
$second-item : nth($pair, 2);
}

它是非常棒的，也非常有意义。这也是我为什么不理解Sass要增加map语法。其实我们可以看到一个更好的原因：使语法结构更简单化。

在任何情况下，这是我能找到关于传入的语法：

$map: (
a: b,
c: d
);

@for $key, $value in $map {
/**
* $key is what we called $first-item
* $value is what we called $second-item
*/
}

到现在为止，我所了解的map就这些，其他的随后会有。有关于Sass的map功能信息可以点击这里。

改善@for循环

我们喜欢循环，他功能是强大的。对于某些任务，他可以减少很多所需的代码。Sass提供了三种不同类型的循环：

- @for：让一个变量i从m到n循环

- @while：当条件a为真时循环

- @each：从矩阵中遍历每个元素

这些功能都是非常强大的。然而@for循环有一个问题。你试过一个做递减的@for循环吗？如下面的例子：

@for $i from 5 through 1 {
/* Do something with $i */
}

别麻烦了，这将会输出什么。甚至不是一个Sass差错。目前，只有按下面的方法来解决这个东西：

@for $i from -5 through -1 {
/* Do something with abs($i) */
}

基本上，你把两个负值，使循环做递增，再者你可以使用abs($i)来代替$i，访问你想要的第一个值。

不管怎么说，他们打算在Sass3.3中修复这个bug（详细信息请点击这里）。Chris Eppstein还打算在循环中添加从1到另一个值做递增和递减。大致是这样的：

@for $i from 1 through 10 by 2 {
/* Do something with $i */
}

然而Nathan Weizenbaum似乎没有合理的@for循环语法来处理这个边缘性的事情，他可以很容易的复制出：

@for $i from 1 through 10 {
@if $i % 2 != 0 {
/* Do something with $i */
}
}

@at-root规则

好吧，我跟您说实话：这个对于我来说仍是一个谜。这个@at-root命令需要嵌套块并将其移到根一级。这功能是不错的，但是为什么呢？为什么你不能只是把它写在根一级呢？

我不能找到更多有关于@at-root规则（除了语法）更多的信息，这里有几个简单的使用例子：

/* Example 1 - Sass */
.foo {
@at-root .bar {
color: gray;
}
}

/* Example 1 - CSS */
.bar { color: gray; }

/* Example 2 - Sass */
.foo {
@at-root .bar &;; {
color: gray;
}
}

/* Example 2 - CSS */
.bar .foo { color: gray; }

/* Example 3 - Sass */
.foo {
@at-root {
.bar {
color: gray;
}
}
}

/* Example 3 - CSS */
.bar { color: gray; }

你知道吗？我不会在这个@at-root上花太多时间，对于他们将怎么实现这个特性，他们看起来很有自信，但是我没有看到太多用例。在这个问题上，这里有更多的讨论信息。

新的字符串操作函数

当我从Sass的代码分支中看到这些，我意识到他们打算增加一些字符串操作函数来缓解quote(string)和unquote(string)函数功能。参考文档请点击这里。从里面我发现五个新的字符串操作函数：

- str_length(string)：返回$string长度

- str_insert(string,insert,index)：从$string第$index插入字符$insert

- str_index(string,substring)：返回$substring在$string中第一个位置

- str_slice(string,start_at,end_at = nil)：返回从字符$string中第$start_at开始到$end_at结束的一个新字符串

- to_upper_case(string)：将字符$string变成大写

- to_lower_case(string)：将字符$string变成小写

新的@import功能

最后但并非最不重要的，他们计划重新整一个强大的@import功能。然而这并不是Sass3.3的功能，Chris打算在Sass4.0加入，除此之外，新版本也有一些新的功能：

- @import-once

- 导入常规的CSS文件

- 命名空间

- 当导入一个文件夹，会自动索引index.scss或者index.sass

- 从一个文件夹中导入所有文件（可能吗？）

请注意这只是猜测。从开始讨论@import开始我就搜集了这个列表。顺便说一下，在没有请教Nathan或者Chris我就已经摆脱了提议。

只导入一次

如果你熟悉PHP或者其他程序语言，你可能知道include_once命令（一个类似的语法）。这个想法是为了一次只导入一个文件，而且只有一次。

在当前状态下，如果你两次导入相同的文件，会编译出来两次导入的文件内容，这样太不好了。

一个解决方案是Seanofw提出的一个小函数，将一个文件当为参数传入，然后检查文件名，确保文件只被导入一次。

$imported-once-files: ();

@function import-once($name) {
@if index($imported-once-files, $name) {
@return false;
}
$imported-once-files: append($imported-once-files, $name);
@return true;
}

@if import-once("_SharedBaseStuff.scss") {
/* ...declare stuff that will only be imported once... */
}

值得庆幸的是，新的@import功能将比这个函数更简单（详细信息请点击这里）。

导入常规的CSS文件

当你在一个项目中将CSS样式导入到SCSS或SASS样式中，是件烦人的事情，因为在Sass样式表中直接导航CSS样式，会完全崩溃。所以在Sass样式中能导入常规的CSS样式是很有意义的。

我想导入Normalize.css文件是最好的一个例子。当你使用@import "normalize"是没办法匹配一个常规的.css文件。因此你需要先将css文件转译成scss或者sass文件，这样非常的麻烦。

在新的@import中应该可以直接实现，详细信息请参考这里。

导入默认号

这主要取决于你的结构，你可以在文件夹中管理你的文件。例如在一个helpers目录中放了一个mixin，每个文件夹只放一个文件。他提出了一个新的行为，通过index来导入一个文件夹。

你可以像下面这样操作：

/* Current way of doing */
@import "helpers/clearfix/index";

/* New way of doing */
@import "helpers/clearfix";

这绝对是一个主要特点， 不过我不明白为什么管理的是文件夹而不是直接文件，但我想应该也是可以的。详细信息请参考这里。

从一个文件夹中导入所有文件

同样一个想法，增加一个新的特性，通过导入一个文件夹直接导入这个文件夹中所有文件。这也被称为"Sass Globbing"，目前Chris Eppstein写了一个Sass的插件。（我想在Sass4.0会有这个功能）。

他将充许你像下面这样操作：

/* Import all files from folder helpers */
@import "library/helpers/*";

/* Import all folders from folder library */
@import "library/**/*";

但是请注意，文件被导入会是按字母顺序排列的，这可能会破坏你导入文件和你所需要的不一样。

命名空间

一个比较大的事情是，命名空间让CSS丢失。在Sass中一切都在一个全局范围。Kaelig提出一个讨论主题，建议遵循CSS的全局命名空间。

不管怎么样，他们正在考虑通过命名空间来控制@import（详细信息请参考这里）。这样你就可以有一个更好控制你的文件和你的项目的方法。

因为这是一个很大的特性，还处理讨论当中，没有决定语法如何使用。我猜可能会像下面这样使用：

@import "file";
@import "file-2" as "Module";

.element {
@extend file%placeholder;
@include Module.mixin();
}

这个只是我的想法，可以不把他当一回事。如果您想了解这个问题，请参考这里。

其他功能

大家先别急于离开哟，下面还有一些很有意思的东西。我在Sass代码分支中发现其他一些很酷的东西！

独特的ID

原来有一个unique-id()函数返回一个独特的随机标识符（运用于Sass的作用域）作为一个不带引号的字符串。基于我对Ruby代码的理解，它返加一个9个字符串长的字母数字。比如“u214ab34e”。

我还不太确定这种功能主要用途是什么，然而，这可能是一个方法，用来获得一个随机数，让我试试：

@function parse-unique-id($value) {
$letters: a b c d e f g h i j k l m n o p q r s t u v w x y z;
$value: unquote("");
@for $i from 1 through str-length($value) {
$letter: str-slice($value, $i, $i + 1);
@if index($letter, $letters) == false {
$value: str-insert($value, $letter, str-length($value) + 1);
}
}
@return $value;
}
$number: parse-unique-id(unique-id());

如果你想测试这段代码，他是无法编译的，即使是最新的版本，因为它依赖于输入功能。基本上，它会检查unique-id()每个字符的值。如果这是一个字母，它会删除它。

他会给你一个0~9999999随机数，任何你想要的。

存在的检查

我发现几个功能，我认为主要由内部传动装置或者Sass库（详细请参考这里）。基本上他们允许你测试是否一个变量、函数或者是否存在当前状态。

- variable_exists(named)

- global_variable_exists(named)

- function_exists(named)

- mixin_exists(named)

似乎也存在一个feature_exists(named)函数，该函数是为了检查当前Sass运行时是否存在一个功能。我想它将用于未来的版本，用来检查一个给定的特性是否存在与否。

总结

好吧，我想说的就是这些，请记住大部分的东西都来自于 Github的问题讨论。没有日期或保证任何版本/特性宣布。

如果你对Sass的一些新特性感兴趣，我推荐你阅读官方的有关信息。

非常感谢您的阅读，下回再见！

译者手语：整个翻译依照原文线路进行，并在翻译过程略加了个人对技术的理解。如果翻译有不对之处，还烦请同行朋友指点。谢谢！

如需转载烦请注明出处：

英文原文：http://davidwalsh.name/future-sass

中文译文：http://www.w3cplus.com/preprocessor/future-sass.html

原文链接：http://www.w3cplus.com/preprocessor/future-sass.html （本内容由互联网资料整理而成）

HTML5 的 Web Storage

One of the reasons that certain technocrats favor native applications is their ability to store data locally on the client. HTML5 made a breakthrough by allowing web applications to store data in the browser.

Although cookies are available to store data in the browsers, there are certain disadvantages to that – which were addressed with the invention of HTML5 Web Storage.

Disadvantages of Cookies

- The storage limit of cookies in web browsers is limited to about 4KB.

- Cookies are sent with every HTTP request, thereby slowing down the web application performance.

What is HTML5 Web Storage?

It is a simple client side database that allows the users to persist data in the form of key/value pairs.

It has a fairly simple API to retrieve/write data into the local storage. It can store up to 10MB of data per domain. Unlike cookies, the data stored are not included with every HTTP request.

IE7 and older versions do not support Web Storage. All the other browsers like Chrome, Opera, Firefox, Safari and IE8+ support Web Storage.

Types of Web Storage

Local storage: Stores data with no expiration date. The data will be available even when the browser/ browsing tab is closed or reopened.

Session storage: Stores data for one session. Data persisted will be cleared as soon as the user closes the browser.

In both the cases, please note that the web storage data will not be available between different browsers.

Example

Let us dive directly into an example to have a better understanding of HTML5 Web Storage.

We will create a simple user settings web page that will allow us to change the page’s background color and header font size.

</pre>
<section><form onsubmit="javascript:setSettings()"><label>Select your BG color: </label>
<input id="favcolor" type="color" value="#ffffff" />
<label>Select Font Size: </label>
<input id="fontwt" type="number" max="14" min="10" value="13" />
<input type="submit" value="Save" />
<input onclick="clearSettings()" type="reset" value="Clear" /></form></section>
<pre>

The setSettings function which is called from the onsubmit event of the form would allow us to save the user selected data into local storage.

Before we use HTML5 Web Storage to store data, we should check whether the browser supports HTML5 storage or not.

We could use the default API or Modernizr to check for the browser compatibility.

function setSettings() {
if ('localStorage' in window && window['localStorage'] !== null) {
//use localStorage object to store data
} else {
alert('Cannot store user preferences as your browser do not support local storage');
}
}

Modernizr is a JavaScript library that helps us to detect the browser support for HTML5 and CSS features. Download the latest version of Modernizr and include the library in the script element.

<script type="text/javascript" src="modernizr.min.js"></script>
if (Modernizr.localstorage) {
//use localStorage object to store data
} else {
alert('Cannot store user preferences as your browser do not support local storage');
}

The setItem(‘key’,’value’) allows us to write the data into the local storage.

QUOTA_EXCEEDED_ERR exception will be thrown if the storage limit exceeds 5MB. So it is always better to add try/catch blocks to the storage code while saving data.

function setSettings() {
if ('localStorage' in window && window['localStorage'] !== null) {
try {
var favcolor = document.getElementById('favcolor').value;
var fontwt = document.getElementById('fontwt').value;
localStorage.setItem('bgcolor', favcolor);
localStorage.fontweight = fontwt;
} catch (e) {
if (e == QUOTA_EXCEEDED_ERR) {
alert('Quota exceeded!');
}
}
} else {
alert('Cannot store user preferences as your browser do not support local storage');
}
}

We can check whether the data is stored in local storage by using the developer tools that comes with the browsers. For instance, in Chrome, right click on the browser and select Inspect Element. Select Resources tab and then click on the local storage item. We can see the user selected data stored in the form of key/value pairs.

The web page can be reloaded with the background and font size values set by the user. The getItem(‘Key’) helps in retrieving the data stored In the database.

function applySetting() {
if (localStorage.length != 0) {
document.body.style.backgroundColor = localStorage.getItem('bgcolor');
document.body.style.fontSize = localStorage.fontweight + 'px';
document.getElementById('favcolor').value = localStorage.bgcolor;
document.getElementById('fontwt').value = localStorage.fontweight;
} else {
document.body.style.backgroundColor = '#FFFFFF';
document.body.style.fontSize = '13px'
document.getElementById('favcolor').value = '#FFFFFF';
document.getElementById('fontwt').value = '13';
}
}

The length function retrieves the total number of values in the storage area.

The above function can be called during the onload event of the body tag as follows

<body onload="applySetting()">

The local storage area can be cleared by using the clear() function or removeItem(‘key’) function. In our example the function below is called on the click event of the clear button.

function clearSettings() {
localStorage.removeItem("bgcolor");
localStorage.removeItem("fontweight");
document.body.style.backgroundColor = '#FFFFFF';
document.body.style.fontSize = '13px'
document.getElementById('favcolor').value = '#FFFFFF';
document.getElementById('fontwt').value = '13';
}

Storage Events

When we set or remove data from the web storage, a storage event will be fired on the window object. We can add listeners to the event and handle the storage changes if required.

window.addEventListener('storage', storageEventHandler, false);
function storageEventHandler(event) {
applySetting();
}

The event object has the following attributes

- key – the property that has changed

- newValue – the newly set value

- oldValue –  previously stored  value

- url – the full url path from where the event originated

- storageArea –  localStorage or sessionStorage object

Remember that the event gets fired only on other windows (not on the window where the event is triggered) and the event does not get fired if there is no change in the data.

The same API methods are applicable for session storage as well except that the methods should be executed on the sessionStorage object.

Conclusion

So, now you can start using Web Storage to store user preferences, user info, session info etc.You can also try creating apps that can be used completely offline and the data stored during offline can be sent back to the server as a batch update when the user is online again.

Tagged as: HTML5 Dev Center

原文链接：http://www.sitepoint.com/html5-web-storage/ （本内容由互联网资料整理而成）

HTML5 的 progress 元素详解

Published August 28, 2013 by Chris Coyier

The following is a guest post by Pankaj Parashar. Pankaj wrote to me about some pretty cool styled progress elements he created. I asked if he'd be interested in fleshing out the idea into an article about styling them in general. Thankfully, he obliged with this great article about using them in HTML, styling them with CSS as best as you can cross-browser, and fallbacks.

Here is the basic markup for the progress element:

<progress></progress>

As per the standard defined by W3C, the progress element represents the completion progress of a task. A progress element must have both a start tag (i.e. <progress>) and an end tag (i.e. </progress>), even though it looks like a replaced element (like an input). This is good though, as it helps with fallback content as we'll cover later.

Apart from the global attributes, it can have two more attributes:

- max - Indicates how much task needs to be done before it can be considered as complete. If not specified the default value is 1.0.

- value - Indicates the current status of the progress bar. It must be greater than or equal to 0.0 and less than or equal to 1.0 or the value of the max attribute (if present).

States of progress bar

A progress bar can be in two states - indeterminate and determinate.

1. Indeterminate

Indeterminate state of the progress bar in Chrome 29 on Mac OS 10.8

Based on your combination of browser and operating system, the progress bar can look different. Zoltan "Du Lac" Hawryluk covers the cross browser behavior of progress element in great depth in his article on HTML5 progress bars (which is definitely worth reading). Wufoo has some screenshots of how it looks on other operating systems on their support page for progress.

It's pretty easy to target and style an indeterminate progress bar because we know that it doesn't contain the value attribute. We can make use of CSS negation clause :not() to style it:

progress:not([value]) {
/* Styling here */
}

2. Determinate

Throughout this article, we'll only focus on styling the determinate state of the progress bar. So let's change the state by adding the max and value attribute.

<progress max="100" value="80"></progress>

Without applying any CSS, the progress bar looks like this in Chrome 29 on Mac OS 10.8.

Determinate state of the progress bar in Chrome 29 on Mac OS 10.8

Note that only adding the max attribute doesn't change the state of the progress bar because the browser still doesn't know what value to represent.

This is pretty much all that we can do in HTML as rest of the work is done by CSS. At this stage let's not worry about the fallback techniques for supporting older browsers that don't understand the progress element.

Styling progress bars

We can target determinate progress bars using the progress[value] selector. Using progress only is fine as long as you know that you do not have any indeterminate progress bars in your markup. I tend to use the former because it provides clear distinction between the two states. Just like any other element we can add dimensions to our progress bar using width and height:

progress[value] {
width: 250px;
height: 20px;
}

This is where the fun part ends and things get complicated because each category of browsers provide separate pseudo classes to style the progress bar. To simplify things, we don't really care about which versions of each browser support the progress element, because our fallback technique will take care of the rest. We classify them as follows:

- WebKit/Blink Browsers

- Firefox

- Internet Explorer

WebKit/Blink (Chrome/Safari/Opera)

Google Chrome, Apple Safari and the latest version of Opera (16+) falls into this category. It is evident from the user agent stylesheet of webkit browsers, that they rely on -webkit-appearence: progress-bar to style the appearance of progress element.

User-agent stylesheet of webkit browsers

To reset the default styles, we simply set -webkit-appearence to none.

progress[value] {
/* Reset the default appearence */
-webkit-appearance: none;
appearance: none;

width: 250px;
height: 20px;
}

Progress bar appearance after reset

On further inspecting the progress element in Chrome Developer Tools, we can see how the spec is implemented.

Chrome Developer Tools Snapshot

WebKit/Blink provides two pseudo classes to style the progress element:

- -webkit-progress-bar is the pseudo class that can be used to style the progress element container. In this demo we'll change the background color, border-radius and then apply inset box shadow to the progress element container.

- -webkit-progress-value is the pseudo class to style the value inside the progress bar. The background-color of this element by default is green which can be verified by inspecting the user-agent stylesheet. For this demo we will create a candystrip effect using linear-gradient on background-image property.

First we'll style the -webkit-progress-bar (the container):

progress[value]::-webkit-progress-bar {
background-color: #eee;
border-radius: 2px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25) inset;
}

Styling progress bar container

Next we'll style the -webkit-progress-value (the bar) with multiple gradient backgrounds. One for striping, one for top to bottom shadowing, and one for left to right color variation. We'll use the -webkit- prefix for the gradients since we're using it for the progress bar itself anyway.

progress[value]::-webkit-progress-value {
background-image:
-webkit-linear-gradient(-45deg,
transparent 33%, rgba(0, 0, 0, .1) 33%,
rgba(0,0, 0, .1) 66%, transparent 66%),
-webkit-linear-gradient(top,
rgba(255, 255, 255, .25),
rgba(0, 0, 0, .25)),
-webkit-linear-gradient(left, #09c, #f44);

border-radius: 2px;
background-size: 35px 20px, 100% 100%, 100% 100%;
}

Styling progress bar value

Adding Animation

At the time of writing only WebKit/Blink browsers support animations on progress element. We'll animate the stripes on -webkit-progress-value by changing the background position.

@-webkit-keyframes animate-stripes {
100% { background-position: -100px 0px; }
}

@keyframes animate-stripes {
100% { background-position: -100px 0px; }
}

And use this animation on the -webkit-progress-value selector itself.

-webkit-animation: animate-stripes 5s linear infinite;
animation: animate-stripes 5s linear infinite;

Pseudo Elements

At the time of writing only WebKit/Blink browsers support pseudo elements ::before and ::after on progress bar. By simply looking at the progress bar, it is not possible to tell the actual value. We can solve this problem by displaying the actual value right at the tail-end of the progress bar using either ::before or ::after.

progress[value]::-webkit-progress-value::before {
content: '80%';
position: absolute;
right: 0;
top: -125%;
}

Pseudo elements in action

Interestingly, content: attr(value) doesn't work on progress bars. However, if you explicitly specify the text inside the content attribute, it works! I haven't been able to find out the reason behind this behavior. Since this works only on WebKit/Blink browsers, there is no good reason to embed content inside pseudo elements, at least for now.

Similarly, ::after is used to create nice little hinge effect at the end of the progress bar. These techniques are experimental and not really recommended to be used if you are aiming for cross-browser consistency.

progress[value]::-webkit-progress-value::after {
content: '';
width: 6px;
height: 6px;
position: absolute;
border-radius: 100%;
right: 7px;
top: 7px;
background-color: white;
}

2. Firefox

Similar to WebKit/Blink, Firefox also uses -moz-appearence: progressbar to paint the progress element.

Firebug screenshot

By using appearence: none we can get rid of the default bevel and emboss. This unfortunately leaves behind a faint border in Firefox which can be removed by using border: none. This also solves the border issue with Opera 12.

progress[value] {
/* Reset the default appearence */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;

/* Get rid of default border in Firefox. */
border: none;

/* Dimensions */
width: 250px;
height: 20px;
}

Faint border in Firefox and Opera

Firefox provides a single pseudo class (-moz-progress-bar) we can use to target the progress bar value. This means that we cannot style the background of the container in Firefox.

progress[value]::-moz-progress-bar {
background-image:
-moz-linear-gradient(
135deg,
transparent 33%,
rgba(0, 0, 0, 0.1) 33%,
rgba(0, 0, 0, 0.1) 66%,
transparent 66%
),
-moz-linear-gradient(
top,
rgba(255, 255, 255, 0.25),
rgba(0, 0, 0, 0.25)
),
-moz-linear-gradient(
left,
#09c,
#f44
);

border-radius: 2px;
background-size: 35px 20px, 100% 100%, 100% 100%;
}

Firefox doesn't support ::before or ::after pseudo classes on progress bar, nor does it allow CSS3 keyframe animation on progress bar, which gives us a slightly reduced experience.

3. Internet Explorer

Only IE 10+ natively supports progress bar, and only partially. It only allows changing the color of the progress bar value. IE implements value of the progress bar as the color attribute rather than the background-color.

progress[value]  {
/* Reset the default appearence */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;

/* Get rid of default border in Firefox. */
border: none;

/* Dimensions */
width: 250px;
height: 20px;

/* For IE10 */
color: blue;
}

What about browsers that don't support them?

The progress element is natively supported in: Firefox 16+, Opera 11+, Chrome, Safari 6+. IE10+ is partially supports them. If you want to support older browsers, you've got two options.

1. Lea Verou's HTML5 progress polyfill

Lea Verou's excellent polyfill adds almost full support for Firefox 3.5-5, Opera 10.5-10.63, IE9-10. This also adds partial support in IE8. It involves including progress-polyfill.js file in your HTML and adding CSS selectors that the script file uses. To know more about its usage, check out the CSS source code of the project page.

2. HTML fallback

This is my preferred (no-js) approach. It makes use of a common technique that is also used by audio and video elements.

<progress max="100" value="80">
<div class="progress-bar">
<span style="width: 80%;">Progress: 80%</span>
</div>
</progress>

Simulate the look and feel of progress bar using div and span inside the progress tag. Modern browsers will ignore the content inside the progress tag. Older browsers that cannot identify progress element will ignore the tag and render the markup inside it.

.progress-bar {
background-color: whiteSmoke;
border-radius: 2px;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.25) inset;

width: 250px;
height: 20px;

position: relative;
display: block;
}

.progress-bar > span {
background-color: blue;
border-radius: 2px;

display: block;
text-indent: -9999px;
}

It is fairly common to use both the techniques in conjunction and it is perfectly safe for production sites. Once you get hold of styling a single progress bar, then adding styles for multiple progress bars is merely an exercise which can be accomplished using classes.

See the Pen Skillset using HTML5 progress bars with CSS3 animations by Pankaj Parashar (@pankajparashar) on CodePen

The demo should run fine for all the browsers including Internet Explorer (up to IE 8). The progress bar color is blue in all the versions of Internet Explorer. Opera 11 and 12 doesn't permit changing the progress bar color. Hence, it shows the default green color. The demo uses additional markup to display some meta information about the progress bar and the percentage value.

For additional reading, check out the HTML5 Doctor article. It covers some similar ground but has some bits about a few additional attributes as well as how to update the bar with JavaScript if you need that.

原文链接：http://css-tricks.com/html5-element/ （本内容由互联网资料整理而成）

教你用 Bootstrap 建立响应式网站

Before we start, there are a few things that you should know. This is a sequel to my previous article, Twitter Bootstrap Tutorial – Handling Complex Designs, which showcased many basics about building websites using Twitter Bootstrap from scratch. I highly recommend you read the previous article before jumping into the responsive nature of Twitter BootStrap. I am very thankful to our readers who praised my previous article and encouraged me to write the sequel to it. I hope you take away some useful knowledge from this article, too!

While the Release Candidate 1 of Twitter Bootstrap 3 is already out, we will be using version 2.3.2, which was their last most stable framework version. You can download the required files from their official GitHub page.

What do you mean by the “Responsiveness” of a website?

The first thing that comes to our mind when we use the word “Responsive” in the context of websites is that it should be compatible with all kinds and sizes of devices. There is a constant demand in the industry to make every website responsive for better readability of the online contents in different environments.

With the help of CSS3 and definitely HTML5, this trend is increasing every day. But what if you are a developer and not a designer? BONK!

Well, you don’t have to worry any more. Since, I have already stated in my previous article that Twitter Bootstrap is a superhero in the field of CSS Frameworks. This is definitely true when it comes to building responsive websites.

Setting up

To enable the responsive nature of Twitter Bootstrap, there are a few extra things you should follow, apart from what we did in our previous article. To set the responsive environment, you have to place the correct meta tag inside the head of the webpage.

<meta name="viewport" content="width=device-width, initial-scale=1.0">

The above meta tag is quite self-explanatory in nature. We are setting the width of the page to the width of the device and initially scaling it to 1, i.e. default size.

Then we have to also use the correct CSS file from the BootStrap CSS files. Last time we had used only css/bootstrap.css but this time we will be using css/bootstrap-responsive.css also. So we are adding an extra responsive stylesheet to our webpage.

<link rel="stylesheet" href="css/bootstrap.css">
<link rel="stylesheet" href="css/bootstrap-responsive.css">

Now we’re all set to start building our first responsive website using Twitter Bootstrap. Before we proceed, have a look at our demo page. Make sure you resize the browser window to see how your demo page is responding to various sizes of the browser. Awesome, isn’t it?

Let’s Begin

I have divided the above responsive webpage into different categories and we will see how to build each one of them in detail.

1. The Responsive Navigation

2. Marketing Area

3. Contents Section

4. Right side bar

5. Footer

The above sections look pretty much the same as the ones we used in the previous non-responsive website. There are, in fact, minute but important changes in the markup to make it responsive. You will have to understand and use them very carefully.

The Responsive Navigation

Now, we’re going to build the navigation bar of the website. It will contain the website’s title and some right aligned menu link items. This is going to be fixed to the top of the website as you have seen in the demo page. So here’s the markup for this:

<div class=”navbar navbar-fixed top”>
</div>

navbar class, already known to us, is for showing the navigation section. An additional navbar-fixed-top makes it stick to the top of the webpage. Pretty clear!

Let’s move ahead and insert some more codes into it:

<div class=”navbar navbar-fixed top”>
<div class="navbar-inner">
<div class=”container”>
</div>
</div>
</div>

navbar-inner helps make BootStrap understand that you are going to place some stuff inside the navigation. container, as we have seen, is used to contain everything inside it as a wrapper.

Till now whatever we have added is just the basic structure of our navigation bar. Let’s see the real magical stuff that makes the navigation responsive.

<div class=”navbar navbar-fixed top”>
<div class="navbar-inner">
<div class=”container”>
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-th-list"></span></a>
<a href="#" class="brand">responsiveSite</a>
<div class="nav-collapse collapse">
<ul class="nav pull-right">
<li class="active"><a href="#">Home</a></li>
<li><a href="#">About Us</a></li>
<li><a href="#">Contact Us</a></li>
</ul>
</div>
</div>
</div>
</div>

The branding and menu items are self-explanatory. It should be clear that adding the class brand gives the title a clean look and is used for the website’s name. The nav items are wrapped inside an additional div with the classes nav-collapse collapse which are used to make the menu appear like a stack when viewing in smaller browsers.

Just above the branding, you might be seeing an additional link with classes btn btn-navbar that wraps a span icon-th-list. This link is visible only on the smaller screens with a list icon. Also see we have used data-toggle=collapse that BootStrap uses to hide/unhide the menu items in smaller windows. Data-target is used to identify which menus to hide/unhide.

Marketing Area

The marketing area is built in exactly the same as in non-responsive webpages. We will create a div with hero-unit class. Then place a container wrapper inside it and then add h1, p and link with btn btn-primary classes. The code should look like below:

<div class="hero-unit">
<div class="container">
<h1>Learn Geometry</h1>
<p class="lead">Oat cake chocolate cake sugar plum sesame snaps. Bonbon danish oat cake chupa chups tart muffin tootsie roll sweet roll sweet roll.</p>
<p><a href="#" class="btn btn-success btn-large">Get Started</a></p>
</div>
</div>

Adding a class lead to the paragraph elements will make them stand out as compared to other p elements. Also make sure the hero-unit div is completely outside the navigation div.

Content Section

We had understood the concept of row classed elements in the non-responsive webpages. Here we will use a similar but slightly modified version of the row elements. This time we will use row-fluid inside of row class. This will enable the row of elements to fit to the webpage and flow down as and when needed. So the initial markup goes like this:

<div class=”container”>
<div class=”row-fluid”>
//some code here
</div>
</div>

Now that we have our structure ready, let’s move and fill in some content. Before that we have to divide the whole area into two sections, one for the content and other for the right sidebar. To do that we will use classes like span* to divide the area.

We will use span8 and span4 for the content area and right sidebar. As stated in the previous article, Twitter Bootstrap is a 12-grid system. The sum of the amount of spans must total to 12. You can make as many divisions as you wish but the sum must total to 12. For example: span4, span4 and span4 (three columns) or span3, span7 and span2 (three unequal columns), etc.

So the final structure of our content area goes like this:

<div class=”container”>
<div class=”row-fluid”>
<div class=”span8”>
</div>
<div class=”span4”>
</div>
</div>
</div>

Here, span8 will be our content area and span4 will be our right sidebar. In the span8, we will add some random texts using p tags.

Tart tiramisu ice cream cotton candy pudding. Sweet topping chocolate bar tootsie roll cotton candy brownie oat cake gummi bears. Danish cookie pudding powder. Pastry cotton candy tart topping. Dessert sesame snaps oat cake bear claw toffee jelly.

Marshmallow soufflé wypas.

Apple pie applicake sweet roll marzipan. Marzipan bear claw pudding jujubes sweet. Halvah sweet roll tiramisu liquorice candy canes halvah. Oat cake chocolate cake sugar plum sesame snaps. Bonbon danish oat cake chupa chups tart muffin tootsie roll sweet roll sweet roll. Sweet tootsie roll dragée cookie bear claw sweet roll jelly-o tootsie roll sweet.

After all the p tags, we will again divide the span8 area into three equal columns to feature some sections of our website. We can nest as many row-fluid within a row-fluid, but the point to remember is the sum of span* divs should equal 12 else your design will break down.

Go ahead and place the following snippet just below all the above p tags but within span8:

<div class="row-fluid">
<div class="span4">
<h4>Our Clients</h4>
<p>Hello These are our clients. <a href="#">Click here</a>.</p>
<a href="#" class="btn btn-primary"><i class="icon-heart icon-white"></i> Our Clients</a>
</div>
<div class="span4">
<h4>Our Clients</h4>
<p>Hello These are our clients. <a href="#">Click here</a>.</p>
<a href="#" class="btn btn-primary"><i class="icon-music icon-white"></i> Our Clients</a>
</div>
<div class="span4">
<h4>Our Clients</h4>
<p>Hello These are our clients. <a href="#">Click here</a>.</p>
<a href="#" class="btn btn-primary"><i class="icon-file icon-white"></i> Our Clients</a>
</div>
</div>

The icons in the buttons used here are shown from the glyphicons-halflings from the img folder. Use elements with appropriate icon class from the Bootstrap documentation to show the icon.

Right Sidebar

The right sidebar or span4 in our case will contain vertical navigation list. This section also remains the same as that used in non-responsive BootStrap webpage. We will also add an additional well class along with span4 to get a grey wrapper around the whole of right sidebar. Our code goes like this:

<div class="span4 well">
<ul class="nav nav-list">
<li class="nav-header">Our Services</li>
<li class="active"><a href="#">Overview</a></li>
<li><a href="#">Web Designing</a></li>
<li><a href="#">Web Development</a></li>
<li><a href="#">Android Applications</a></li>
<li class="divider"></li>
<li class="nav-header">Our Services</li>
<li><a href="#">Overview</a></li>
<li><a href="#">Web Designing</a></li>
<li><a href="#">Web Development</a></li>
<li><a href="#">Android Applications</a></li>
<li class="divider"></li>
<li><a href="#">Help</a></li>
</ul>
</div>

Classes nav nav-list is used for vertical navigation list. A class divider is given to any li element to separate all the li elements present above and below with it with a horizontal thin line. nav-header is used to make the li element look like a sub section header.

Building the footer

Our footer here is going to be a simple container with three equal sized span* elements. As you can see in the demo page, the horizontal line above the footer is a
element.

So the code for footer goes here:

<div class="container">
<div class="row-fluid">
<div class="span4">
<p>&copy; 2013 <a href="#">Zetiz Labs</a></p>
</div>
<div class="span4 text-center">
<ul class="nav inline">
<li><a href="#">About Us</a></li>
<li><a href="#">Contact Us</a></li>
<li><a href="#">Privacy Policy</a></li>
</ul>
</div>
<div class="span4 text-right">
<p>Powered By Twitter BootStrap 2.3.2</p>
</div>
</div>
</div>

text-center, text-right and text-left are aligning classes. You can use them as and when required.

Conclusion

You might not have realized it, but we have actually come to the end of the article. Congratulations on building your first responsive website. Try resizing the windows or opening the demo page in various other devices, to see the actual responsive nature.

Well, there is actually no end to what you can do with BootStrap. You can even customize it completely to make it look more personal. Custom stylesheets can be added, like “customstyle.css” or any other named CSS file. Import all the BootStrap CSS files using @import in “customstyle.css” and then link this CSS file in your webpage only. One change that I made in my customstyle.css was to override the background image and color of the marketing area.

Hope you had fun reading this article. Thank you!

Subscribe to news and offers from SitePoint, and you'll receive a free copy of Build Your Own Website The Right Way Using HTML5 & CSS3.

原文链接：http://www.sitepoint.com/building-responsive-websites-using-twitter-bootstrap/ （本内容由互联网资料整理而成）

前端工程师面试问题列表

前言：@darcyclarke 在 GitHub 上分享了一个 repo，其中包括了不少前端面试问题，可用于检验潜在的候选人。绝不推荐在单个候选人身上用上所用的问题（那样会花费好几个小时滴）。从这个列表选择一些，应该能从候选人身上，检测出你所需要的技能。

请记住，下面的很多问题都是开放式的，无标准答案，并能引发有趣的讨论。相比直接的答案，相信你在面试前端工程师时，从讨论中你对候选人会了解的更多。

以下中文译文由@shawnqiang 完成。

问题贡献者

@bentruyman (http://bentruyman.com/), @roger_raymond (http://twitter.com/iansym), @ajpiano (http://ajpiano.com/), @paul_irish (http://paulirish.com/), @SlexAxton (http://alexsexton.com/), @boazsender (http://boazsender.com/), @miketaylr (http://miketaylr.com/), @vladikoff (http://vladfilippov.com/), @gf3 (http://gf3.ca/), @jon_neal (http://twitter.com/jon_neal), @wookiehangover (http://wookiehangover.com/) and @darcy_clarke (http://darcyclarke.me)

一般问题

★你用Twitter吗？ （在天朝最好问你用微博吗？）

→如果用，你都关注那些人？

★你用Github吗？

→如果用，你关注的项目有什么？

★你关注的博客有那些？

★你使用那些版本管理系统，比如Git，SVN等？

★你常用的开发环境是怎样的？比如操作系统，文本编辑器，浏览器，及其他工具等。

★你能描述一下你制作一个网页的工作流程吗？

★你能描述一下渐进增强和优雅降级之间的不同吗?

→如果提到了特性检测，可以加分。

★请解释一下什么是语义化的HTML？

★你更喜欢在哪个浏览器下进行开发？你使用那些开发人员工具？

★你如何对网站的文件和资源进行优化？期待的解决方案包括：

· 文件合并

· 文件最小化/文件压缩

· 使用CDN托管

· 缓存的使用

· 其他

★为什么利用多个域名来存储网站资源会更有效？

→浏览器一次可以从一个域名下做多少资源？

★请说出三种减低页面加载时间的方法。（加载时间指感知的时间或者实际加载时间）

★如果你接到了一个使用Tab来缩进代码的项目，但是你喜欢空格，你会怎么做？

· 建议这个项目使用像EditorConfig (http://editorconfig.org) 之类的规范

· 为了保持一致性，转换成项目原有的风格

· 直接使用VIM的retab命令

★请写一个简单的幻灯效果页面

→如果不使用JS来完成，可以加分。

★你都使用那些工作来测试代码的性能？

· 例如JSPerf (http://jsperf.com/)

· 例如Dromaeo (http://dromaeo.com/)

· 其它。

★如果今年你打算熟练掌握一项新技术，那会是什么？

★请谈一下你对网页标准和标准制定机构重要性的理解。

★什么是FOUC？你如何来避免FOUC？

HTML相关问题

★文档类型的作用是什么？你知道多少种文档类型？

★浏览器标准模式和怪异模式之间的区别是什么？

★使用XHTML的局限有那些？

→如果页面使用’application/xhtml+xml’会有什么问题吗？

★如果网页内容需要支持多语言，你会怎么做？

★在设计和开发多语言网站时，有哪些问题你必须要考虑？

★在HTML5的页面中可以使用XHTML的语法吗？

★在HTML5中如何使用XML？

★’data-’属性的作用是什么？

★如果把HTML5看作做一个开放平台，那它的构建模块有那些？

★请描述一下cookies、sessionStorage和localStorage的区别？

JS相关问题

★你使用过那些Javascript库？

★你是否研究过你所使用的JS库或者框架的源代码？

★什么是哈希表？

★’undefined’变量和’undeclared’变量分别指什么？

★闭包是什么，如何使用它，为什么要使用它？

→你喜欢的使用闭包的模式是什么？

★请举出一个匿名函数的典型用例？

★请解释什么是Javascript的模块模式，并举出实用实例。

·如果有提到无污染的命名空间，可以考虑加分。

·如果你的模块没有自己的命名空间会怎么样？

★你如何组织自己的代码？是使用模块模式，还是使用经典继承的方法？

★请指出Javascript宿主对象和内置对象的区别？

★指出下列代码的区别：

function Person(){} var person = Person() var person = new Person()

★’.call’和’.apply’的区别是什么？

★请解释’Funciton.prototype.bind’的作用？

★你如何优化自己的代码？

★你能解释一下JavaScript中的继承是如何工作的吗？

★在什么时候你会使用’document.write()’？

→大多数生成的广告代码依旧使用’document.write()’，虽然这种用法会让人很不爽。

★请指出浏览器特性检测，特性推断和浏览器UA字符串嗅探的区别？

★请尽可能详尽的解释AJAX的工作原理。

★请解释JSONP的工作原理，以及它为什么不是真正的AJAX。

★你使用过JavaScript的模板系统吗？

→如有使用过，请谈谈你都使用过那些类似库文件。比如Mustache.js、Handlebars等等。

★请解释变量声明提升。

★请描述一下事件冒泡机制。

★”attribute”和”property”的区别是什么？

★为什么扩展JavaScript内置对象是个坏做法？

★为什么扩展JavaScript内置对象是个好做法？

★请指出document load和document ready的区别。(这是个问题的问题）

★’==’和’===’有什么不同？

★你如何获取浏览器URL中查询字符串中的参数。

★请解释一下JavaScript的同源策略。

★请解释一下事件代理。

★请描述一下JavaScript的继承模式。

★如何实现下列代码：

[1,2,3,4,5].duplicator(); // [1,2,3,4,5,1,2,3,4,5]

★描述一种JavaScript memoization（避免重复运算）的策略。

★什么是三元条件语句？

★函数的参数元是什么？

★什么是”use strict”?使用它的好处和坏处分别是什么？

JS代码示例：

~~3.14

★问题：上面的语句的返回值是什么？ **答案：3

"i'm a lasagna hog".split("").reverse().join("");

★问题：上面的语句的返回值是什么？ **答案：”goh angasal a m’i”

( window.foo || ( window.foo = "bar" ) );

★问题：window.foo的值是什么？ **答案：”bar” 只有window.foo为假时的才是上面答案，否则就是它本身的值。

var foo = "Hello";
(function() { var bar = " World"; alert(foo + bar); })();
alert(foo + bar);

★问题：上面两个alert的结果是什么 答案: “Hello World” & ReferenceError: bar is not defined

var foo = [];
foo.push(1);
foo.push(2);

★问题：foo.length的值是什么？ **答案：’2′

var foo = {};
foo.bar = 'hello';

★问题：foo.length的值是什么？ **答案: undefined

jQuery相关问题

★解释”chaining”。

★解释”deferreds”。

★你知道那些针对jQuery的优化方法。

★请解释’.end()’的用途。

★你如何给一个事件处理函数命名空间，为什么要这样做？

★请说出你可以传递到jQuery方法的四种不同值。

→选择器（字符串），HTML（字符串），回调函数，HTML元素，对象，数组，元素数组，jQuery对象等。

★什么是效果队列？

★请指出’.get()’、’[]‘、’eq()’,的区别。

★请指出’.bing()’、’.live()’ 和 ‘.delegate()’的区别。

★请指出 ‘$’ 和 ‘$.fn’ 的区别？或者解释什么是 ‘$.fn’ 。

★请优化下列选择器：

$(".foo div#bar:eq(0)")

CSS相关问题

★描述css reset的作用和用途。

★描述下浮动和它的工作原理。

★清除浮动的方法有那些，分别适用于什么情形。

★解释css sprites，如何使用。

★你最喜欢的图片替换方法是什么，你如何选择使用。

★讨论CSS hacks，条件引用或者其他。

★如何为有功能限制的浏览器提供网页。

→你会使用那些技术和处理方法。

★何视觉隐藏网页内容，只让它们在屏幕阅读器中可用。

★你使用过网格系统吗？如果使用过，你最喜欢哪种？

★你使用过meidia queries（媒体查询）吗，或者移动网站相关的CSS布局。

★你熟悉SVG样式的书写吗？

★如何优化网页的打印样式。

★在书写高效CSS文件时会有哪些问题需要考虑。

★你使用CSS预处理器吗？(SASS,Compass,Stylus,LESS)

→如果使用，描述你的喜好。

★你是否接触过使用非标准字体的设计？

→字体服务，Google Webfonts, Typekit,等等。

★请解释浏览器是如何根据CSS选择器选择对应元素的。

可选的有趣问题

★你编写过的最酷的代码是什么？其中你最自豪的是什么？

★你知道HTML5的帮派标志吗？

★你是否正在或曾经在一艘船上。(不懂这个幽默）

★你使用的开发工具中，你最喜欢的部分是什么？

★你有什么业余项目吗？是那种类型的？

★解释cornify的重要性？(本题完全摸不到头脑）

★在一张纸上，垂直写下ABCDE，然后不用任何代码，将他们到序排列。

→静静地看他们是否将纸翻转。

★海盗还是忍者？

→如果是两者的合体，并有恰当理由，可以加分。如果是僵尸猴子海盗加忍者加两分。(译注，此题文化差异过大）

★如果没有在Web开发，你会做什么？

★卡门圣迭哥的隐藏处在哪里？

→提示：本题的答案永远是错的。

★你最爱的IE特性是什么？

★完句填空： Brendan Eich和Doug Crockford是JavaScript的________。

★讨论：jQuery是牛逼的库还是最牛逼的库。

—————————————–

伯乐在线注：也欢迎国内前端开发人员来给这个列表添砖加瓦。

(没有评分)

Loading ...

原文链接：http://blog.jobbole.com/29269/ （本内容由互联网资料整理而成）

Starting to Write CSS

Don't you feel that CSS is not the same anymore? Last few years became a hot topic and many smart people talked about it. CSS is not that little thing which front-end developer should do to make the page looks pretty. It's far more then that. We care about performance and we want to produce better web sites. In this article I want to share what I learned last few months and what exactly is my vision about CSS coding. As a programmer I'm really interested in the architectural part of the things. I feel that the writing of CSS should be changed and I dig a lot. I search for the good processes, the best principles and new workflows. This post is like conclusion of journey in the world of CSS. Many people say that writing CSS is not exactly programming. I'll disagree and will say that it's equally interesting and challenging.

CSS Preprocessors

Ok, let's face it. Writing pure CSS is not the funnies thing in the world. The preprocessors take something which looks like CSS, make some magic and produce valid CSS code. This adds one more layer between you and the final styles which are send to the browser. That's not so bad as it sounds like, because the preprocessors provide some really helpful features.

Concatenation

I think that one of the most valuable thing which came is the concatenation of your files. I'm sure, you know that when you use @import in your .css file you actually tell to the browser please, get that file too. And it does. It makes a new request which is kinda bad, because you may have a lot of files. Making additional requests decrease the performance of you application. If you use CSS preprocessors this problem is gone. They simply compile all your styles to one single .css file.

Extending

There are two main CSS preprocessors - LESS and SASS. They both support extending. Yes, it works a little bit different, but the idea is the same. You make a basic class (usually called mixin) with bunch of properties and later import these properties inside another selector. For example

// less
.bordered(@color: #000) {
border: dotted 2px @color;
}
.header { .bordered; }
.footer { .bordered(#BADA55); }

// compiles to
.header {
border: dotted 2px #000000;
}
.footer {
border: dotted 2px #bada55;
}

The problem here is that if you define a mixin without parameters I.e. if you have just

.bordered {
border: dotted 2px #000;
}

this goes to the final compiled CSS file, no matter if it is used or not. It's like that, because it is a valid selector. In SASS we have a little bit more flexibility. There are mixins, extends and placeholders (if you want to see the exact difference between them I strongly recommend checking this article). Let's get the following SASS and its compilation:

// sass
@mixin bordered($color: #000) {
border: dotted 2px $color;
}
.header { @include bordered; }
.footer { @include bordered(#BADA55); }

// compiles to
.header {
border: dotted 2px black;
}
.footer {
border: dotted 2px #bada55;
}

It looks almost the same. But if we go to the second use case and define a place holder:

// sass
%bordered {
border: dotted 2px #000;
}
.header {
@extend %bordered;
}
.footer {
@extend %bordered;
}

// compiles to
.header, .footer {
border: dotted 2px #000;
}

There are two good things happening. First, there is no .bordered class compiled. Second, SASS combines the selectors and it makes our CSS a little bit shorter.

Configuration

Both LESS and SASS support definition of variables. You can later access those variables and use them as values for your properties.

// sass
$brand-color: #009f0A;
...
h1 {
color: $brand-color;
}

That's a good feature, because you may store some important things like company colors or grid widths in one place. If you need to change something you don't need to go through all your code.

Another handy usage of the variables is interpolation. The following example demonstrates the idea:

// sass
@mixin border($side) {
border-#{$side}: solid 1px #000;
}
.header {
@include border("left");
}

// compiles to
.header {
border-left: solid 1px #000;
}

Against the preprocessors

- The preprocessor is a tool, i.e. it's one more thing which you have to add to your environment. You may want to integrate it into your application. This of course requires additional coding.

- If you don't want to mess your code with such a thing, then you will probably need a watcher. Another instrument which monitors your files and once something is updated fire compilation. If that's the case then you have to run the watcher every time when you start working on the project. Maybe you will optimize the process over the time, but it's still something that you should care about.

- Very often the developers look only their .less or .sass files. However the output is what it matters. You may have elegant and optimized SASS code, but this doesn't mean that you will end up with the same beautiful CSS code. You may have some really interesting specificity problems. So, check the compiled version regularly.

BEM

Ok, I found a new tool to play with. The preprocessors probably save a lot of time, but they can't write a good architecture alone. The first thing which I started thinking of is a naming convention. Let's get the following HTML markup:

<header class="site-header">
<div class="logo"></div>
<div class="navigation"></div>
</header>

A possible styling may look similar to

.site-header { ... }
.logo { ... }
.navigation { ... }

This will work of course, but it has a problem - reading the CSS you can't understand that, for example, the logo belongs to the header. You may have another little logo image used in the footer. The next logical step is to write a descendant selector.

.site-header .logo { ... }

However using such selectors is not very good idea, because it tights styles to specific tags hierarchy. What if I want to move the logo outside the header tag? I'll lose the styling. The other thing which you could do is to add site-header in the name of the logo's class:

.site-header-logo { ... }

That's good, self explanatory, but it doesn't work in all the cases. Later, during December I may want to use a Christmas version of the logo. So, I can't write

.site-header-logo-xmas { ... }

because my logic is to write the selector like that so it matches the nesting of the tags in the html.

BEM could be the answer of the situation. It means Block, Element, Modifier and creates some rules, which you could follow. Using BEM, our little example will be transformed to:

.site-header { ... } /* block */
.site-header__logo { ... } /* element */
.site-header__logo--xmas { ... } /* modifier */
.site-header__navigation { ... } /* element */

I.e. site-header is our block. The logo and the navigation are elements of that block and the xmas version of the logo is modifier. Maybe it looks simple, but it's really powerful. Once you start using it will find that it makes your architecture better. The arguments against BEM are mainly because of the syntax. Yes, maybe it looks a little bit ugly, but I'm ready to make a sacrifice in the name of the good system.

(good reading: here and here)

OOCSS

Once I found BEM I was able to name my classes correctly and I started thinking about composition. Maybe the first thing which I read was an article about Object oriented CSS. Object oriented programming sometimes is about adding abstractions and CSS language supports that. Using preprocessors or not, OOCSS is something that you should know about. As a coder I found this concept really close to my usual programming, in JavaScript for example. There are two main principles:

Separate structure and skin

Let's use the following example:

.header {
background: #BADA55;
color: #000;
width: 960px;
margin: 0 auto;
}
.footer {
background: #BADA55;
text-align: center;
color: #000;
padding-top: 20px;
}

There are few styles which are duplicated. We may extract them in another class like that:

.colors-skin {
background: #BADA55;
color: #000;
}
.header {
width: 960px;
margin: 0 auto;
}
.footer {
text-align: center;
padding-top: 20px;
}

So, we have an object colors-skin which we could extend. The html markup may look like that:

<div class="header colors-skin"> ... </div>
<div class="colors-skin"> ... </div>
<div class="footer colors-skin"> ... </div>

There are several benefits of that change:

- We have a class, which may be used several times.

- If we need a change we need to make it in only one place

- We removed duplication in our CSS file, which makes its file size lower

Separate container and content

The idea here is that every element should have the same styles applied no matter where it is put in. So, you should avoid the usage of selectors similar to the following

.header .social-widget {
width: 250px;
}

It's because if you move .social-widget outside the .header container the width will be different. In general, that's not a good practice. Especially for components which are used all over the page. This principle encourage modular CSS and I strongly recommend to take enough time trying it. Personally, for me, following the principle means producing better CSS.

The framework

If you open the OOCSS repository on GitHub you will see a framework. Yes, the framework uses object oriented CSS concept and yes, it has a bunch of cool ready-to-use components. From some time I don't like frameworks. If you think a bit you will see that the word framework has two parts frame and work. And indeed you work in a frame. You actually make a deal with that thing and you have to play by its rule. I prefer to use micro-frameworks or something which gives me only the base. Of course I don't mean to reinvent the wheel, but I'm always trying to find the balance. Very often, the ready-to-use solutions lead to messy and complex systems. My advice is to build things with only one an specific purpose. If you try to cover as many cases as possible you will end up with ... you know - a framework.

However, I strongly recommend checking the OOCSS framework. It's an unique piece of knowledge and maybe it will fit in your needs. The repository is hosted by Nicole Sullivan. She is a pioneer in OOCSS and if you have some free time I'll suggest to check here presentations/talks.

SMACSS

Another popular concept is SMACSS. SMACSS stands for scalable and modular architecture for CSS. Jonathan Snook introduces something like style guide for the CSS developers. The idea is to separate your application into the following categories:

- Base - basic default styles usually used for a simple selectors. Like clearfix for example.

- Layout - grids definition

- Module - a group of elements which combined form a module. Like for example header or sidebar.

- State - contains different states of elements. Definition of rules if particular object is hidden, pressed, expanded etc ...

- Theme - oriented more to the visual parts of the things. Similar like the state category.

I don't have experience using SMACSS, but it is quite popular and indeed promotes good ideas. The very good thing is that it is more like a concept then a framework. So, you are not tight to any strict rules, classes or components.

Atomic design

Knowing about OOCSS and SMACSS I searched for an appropriate metaphor and very soon I landed on this page. It's a presentation of the great concept Atomic Design. Its author is Brad Frost, which is a well known web developer working mainly in the responsive and mobile world.

The idea is really interesting. Following some chemistry terminology, we could say that the basic unit of the matter is the atom. Brad moves this to CSS saying that our pages are build by atoms. An atom could be

<label>Search the site</label>

<input type="text" placeholder="enter keyword" />

I.e. atoms contain some basic styling of DOM elements. Like color palette, font sizes or transitions. Later those parts could be combined into molecules. For example:

<form>
<label>Search the site</label>
<input type="text" placeholder="enter keyword" />
<input type="submit" value="search" />
</form>

So the form element contains several atoms. Abstracting the things like that brings flexibility, because we may use the same atoms to build another molecule. Together with that, we could reuse the same form in different contexts.

Brad didn't stop there. The organisms are something which is build of molecules. Following the same approach we may write the following and call it an organism:

<header>
<div class="logo">
<nav>
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contacts</a></li>
</ul>
</nav>
<form>
<label>Search the site</label>
<input type="text" placeholder="enter keyword" />
<input type="submit" value="search" />
</form>
</header>

The next thing in the concept are the templates. They are not related to the chemistry directly, but are put into web context. Once we start combining different organisms we are building template. Later those templates form our final pages.

You are probably already using similar approach to build your applications. However, naming the things in a reasonable manner brings good architecture. You and all your team mates will have something to catch on, during the development. Separation of the things to atoms and molecules is kinda important part, because it improves both, the working process and the maintenance of your web application.

OrganicCSS

Before a couple of months I wrote an article about Organic. It's a great small framework for JavaScript applications. It's more like a design pattern, and I personally like it a lot. I even used Organic in several projects and everything works pretty well. If you are interested in it, I strongly recommend reading the blog post here.

When I read the Brad Frost's article I was already familiar with similar concept, because I knew about Organic. Brad's work is amazing, but I decided to go deeper and try to write my own micro framework based on atomic design concept. I chose SASS as a preprocessor and create a repository in Github - https://github.com/krasimir/organic-css.

Atoms

Let's start with the smallest part of the framework - the atom. Its definition in wikipedia is The atom is a basic unit of matter. In the context of CSS, I think that it is a property and its value. For example:

margin-top: 24px;

Adding atoms just by writing styles directly inside the classes is not what I wanted. Because if I type something like that

body {
margin-top: 24px;
}
header {
margin-top: 24px;
}

the preprocessor will leave that as it is. The result which I want to get at the end is:

body, header {
margin-top: 24px;
}

In SASS this effect is achievable by using place holders. I.e.

%margin-top-24 {
margin-top: 24px;
}
body {
@extend %margin-top-24;
}
header {
@extend %margin-top-24;
}

So, I had to use placeholders. This also means that I had to have a lot of predefined placeholders, which I can use. At that moment, I decided that the framework will contain only atoms. And maybe few molecules with generic functions like the usual reset.css, grid definition and so on. I wanted to write something which acts as a base for the CSS development. Maybe project after project I'll see some patterns, which could be put in the core, but as a start I wanted to keep the repo clean and simple.

To make the things a little bit more consistently, I created a mixin for atom definition. So, here is an example:

@include define-atom("block") {
display: block;
}
@include define-atom("font-family") {
font-family: Georgia;
}

Using this approach I created a bunch of atoms, which I could easily apply in every project. You can check them here. I used some good practices from other frameworks so, not all the credits go to me. There is also a mixin for combining atoms in a molecule:

@mixin header { // <- molecule called 'header'
@include atoms((
block,
clearfix,
font-family
));
}

Molecules

Molecule is a DOM element which needs styling, but doesn't have children. Or if it has children they are not directly connected to it. For example <img src="logo.jpg" /> could be a molecule. If you find difficult to recognize the molecules in your page, just think of what is build by atoms. If some element is build by other molecules it is probably an organel. Just a few lines above I showed how to define a molecule:

@mixin login-box {
@include atoms((
block,
font-size-20,
margin-top-23,
bold
));
}

There is something interesting, which I faced with. Let's get the body tag. What it is? Is it a molecule or something else? Sure, it needs some styling via atoms, but in general contains other molecules. It should be something else. I made the conclusion that the CSS should be the leading part. I.e. if the body needs few atoms for its styling then it is a molecule, which means that, in theory, I should not attach any other molecules to it. This may seem a little bit impractical, but in most of the cases will keep you from using descent selectors, which is a good sign.

Organelles

Once you recognize which DOM elements are molecules you will see what organelles are. For example, the typical form element is a great example of organelle. It contains molecules like label, input or textarea.

.login-form {
@include label;
@include input;
@include textarea;
}

The organelles are maybe the first part of the framework, which is tightly connected to the current application. The atoms and molecules could be transferred between the different projects while the organelles may not.

More abstractions

Very often you may want to combine several organelles in something else. If that's the case then add another abstractions.

Atom → Molecule → Organelle → Cell → Tissue → Organ → Sys → Organism

It's a matter of choice how you will continue constructing your CSS. I used OrganicCSS only in one project so far, but I could say that it brings clarity. I put the different elements in their own directories and named the classes like that so I can easily find out what exactly I'm working with. For example if there is an organelle called header I simply change it to o-header. Later, when I read the HTML markup I could see that the CSS styles for this element are in organelles folder.

Conclusion

It was an interesting journey. I don't know if I'm going to use OrganicCSS in the future but that's not the most important part. The things which I've learned are what it matters. I knew that I had to change my CSS development process and I did it. I believe that we should talk more about architecture in CSS. As you can see we have a lot of good resources out there. We just have to find them, learn what they do and how they work. Only then we could decide what to use or not. Even better, when you see the whole picture you are able to create something which fits better in your needs.

原文链接：http://davidwalsh.name/starting-css （本内容由互联网资料整理而成）

CSS3单边阴影

话说，CSS3的事实标准出来那么久了，很多属性都开始去掉私有前缀了，如 box-show。如果你还不知道box-show是什么，那只能说你是个正常人类，不是前端攻城师，可以离开这里回去地球了。

既然你还在继续看到这，那么你可能知道box-shadow，不过我还是要讲概念，^_^。 box-shadow，顾名思义就是盒子阴影，可以给一个块级容器加上阴影或者发光效果。效果如下：

把阴影的颜色和透明度调整下，就可以整成发光效果了。不过今天的主角不是他。略过。

说回正事，这box-shadow虽然好用，可是有时还会遇到蛋疼的设计。 搞出只有一边的内阴影。而box-shadow最多只能做到剩下两边有阴影(看下面，看下面↓)，这可愁死了咱这苦命的娃啊。

不知道你囧没，反正我囧了~~

本着除非打死否则不用图片的思想， 还是被我找到了实现的方法,，嘿嘿~~先看看效果

demo啊，发疯地点这里吧

嗯咳，原理是用:before伪元素插入一个元素作为阴影的容器，绝对定位并铺满整个框。然后在这个容易用线性渐变画个背景就完成了。由于绝对定位，会覆盖到原本的内容，这时只要给阴影设置个 z-index: -1 据解决了。下面看看这神奇的代码~~

.gradient-shadow{
position: relative;
}
.gradient-shadow:before{
content: ' ';
background: -webkit-linear-gradient(top, #BBB,#EEE ,white 20%);
background: -moz-linear-gradient(top, #BBB,#EEE ,white 20%);
background: -o-linear-gradient(top, #BBB,#EEE ,white 20%);
background: linear-gradient(top, #BBB,#EEE ,white 20%);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;

z-index: -1;
}

html

<div  class="gradient-shadow">
<p>这里是只有一边的2B阴影</p>
</div>

原文链接：http://imatlas.com/posts/css3-single-box-shadow/ （本内容由互联网资料整理而成）

Javascript in WSH

日常生活中，时而有朋友会让我帮忙写个小程序，例如把几个文本文件处理一下生成新的文件，检测某个网站的某页面是否稳定，分析一个Excel文件得到某些结果文件等。当然，一般他们使用的都是Windows，所以肯定没法使用Linux Shell那些强力命令的。

有的同事给他们写过DOS批处理文件来做类似的事，但是说句实话，DOS批处理实在太太太TMD弱了。有的同事写了一个PHP程序，以console的形式调用，但是首先他要求安装PHP环境，其次还要求输入和输出必须是文本文件，肯定不能处理Excel之类的玩意，于是用起来就很不方便。至于使用VC来写程序，有点杀鸡用牛刀的感觉，而且不开源，修改起来很不方便。.NET？为了一个程序装一个Runtime？算了吧。

其实，很早以前，我就用JScript来做这些事了，确切地说，是用WSH来做这事。

WSH是Windows Scripting Host的简称，是微软提供的脚本宿主平台。实际上，如果采用jscript来写WSH脚本，它的语法和javascript是一样的，只不过因为它拥有本地权限，可以访问WScript对象、WSH Runtime对象以及其他任何COM自动化对象，包括Word/Excel/IE/IIS，以及WMI对象等。

微软的MSDN里有Windows Scripting的页面，可以找到各种资料。例如，下面就是一个打开IE，浏览深度网站的脚本：

varbrowser=WScript.createObject("InternetExplorer.Application");

browser.navigate2("http://www.shendu.com");

browser.visible=true;

其中InternetExplorer.Application就是IE对应的COM自动化对象的名称，如果想知道这个对象(即脚本中的browser对象)的所有属性、方法、事件等，可以在MSDN上找到对应对象的文档来查，例如IE对象的接口文档就在这里。

同理，我们也可以用类似的方法找到如何操作Word等对象。我做了一个例子，里面就有几个脚本，有的在平时的工作生活中还会用到的。

开发和使用WSH脚本还要注意下下面几个问题。

首先，除非你知道没事，不然不要在资源管理器里双击一个.js/.wsf文件运行它，因为它可能会不停调用WScript.echo，导致不停弹窗。这时候，Windows实际上在调用wscript来运行它，你可以切换到cmd下，通过cscript //nologo my-code-file.js来运行它。

其次，有时候你需要混合编程。例如我需要将一个汉字转化为对应的拼音时，我会用VBS的asc函数，这时候我需要把代码保存成wsf文件，而且编码要使用GBK编码。wsf文件的格式是这样的：

<job id="go">

<script language="vbscript">

FunctionmyAsc(ch)

myAsc=asc(ch)

EndFunction

</script>

<script language="javascript">

//一些js代码

</script>

</job>

这个时候，你需要这样运行它：cscript //nologo //job:go my-code-file.wsf。

第三，你可能需要制作一个图形界面给朋友用，这也很简单，只要把代码放在一个HTML里，然后把这个HTML的文件名后缀改成.hta文件就行了，记得我十年前把这样一个程序给朋友时，朋友觉得很奇怪，居然现在Windows程序可以这样写了

下面是一个例子：

<html>

<head>

<meta content="text/html; charset=utf-8"http-equiv="Content-Type" />

<title>HTA测试</title>

</head>

<body>

选择一个文件：<input type="file"id="file" />

<br />

<input type="button"value="计算行数与字符数"onclick="go()"/>

</body>

<script>

functiongo(){

varfilename=document.getElementById("file").value;

varfso=newActiveXObject("Scripting.FileSystemObject");

if(!fso.FileExists(filename)){

alert('请选择一个文本文件！');

return;

varf=fso.OpenTextFile(filename);

varlines=0,chars=0;

while(!f.AtEndOfStream){

varr=f.ReadLine();

lines++;

chars+=r.length;

f.Close();

alert("lines: "+lines+", chars: "+chars);

</script>

</html>

通过HTA，你可以使用HTML/CSS做出很漂亮的界面，同时也可以拥有很强的功能。

另外，你可能需要将WSH脚本加入Windows的任务计划中去，除了手工添加之外，还可以使用Schtasks命令。下面的命令就是将c:\windows\system32\cscript.exe //nologo “d:\My Documents\wsh\myjob.js”作为一个每小时运行的任务加入任务计划中去，其任务名为MyWSHJob。

schtasks /create /sc HOURLY /tn MyWSHJob /ru “” /rp “” /tr “\”c:\windows\system32\cscript.exe\” //nologo \”d:\My Documents\wsh\myjob.js\”"

如果要删除这个任务，使用下面的命令即可：

schtasks /delete /tn MyWSHJob /f

但是需要注意的是，如果你的WSH脚本里启动了图形界面的应用程序，例如IE，那么在运行脚本的时候必须打开桌面，说白了就是不能是退出登录状态。为了达到这一点要求，同时又要保证安全性，可能就需要专门为这个脚本做一个虚拟机，在虚拟机里面运行计划任务了。

最后一点，微软终于意识到自己的脚本系统太弱，推出了Power Shell，但是这个需要.NET运行时，而且传递的是对象，有些不习惯，也许以后会用吧。

原文链接：http://blog.raphaelzhang.com/2012/03/javascript-in-wsh/ （本内容由互联网资料整理而成）

JavaScript 的性能优化：加载和执行

无论当前 JavaScript 代码是内嵌还是在外链文件中，页面的下载和渲染都必须停下来等待脚本执行完成。JavaScript 执行过程耗时越久，浏览器等待响应用户输入的时间就越长。浏览器在下载和执行脚本时出现阻塞的原因在于，脚本可能会改变页面或 JavaScript 的命名空间，它们对后面页面内容造成影响。一个典型的例子就是在页面中使用document.write()。例如清单 1

清单 1 JavaScript 代码内嵌示例

<html>
<head>
<title>Source Example</title>
</head>
<body>
<p>
<script type="text/javascript">
document.write("Today is " + (new Date()).toDateString());
</script>
</p>
</body>
</html>

当浏览器遇到<script>标签时，当前 HTML 页面无从获知 JavaScript 是否会向<p> 标签添加内容，或引入其他元素，或甚至移除该标签。因此，这时浏览器会停止处理页面，先执行 JavaScript代码，然后再继续解析和渲染页面。同样的情况也发生在使用 src 属性加载 JavaScript的过程中，浏览器必须先花时间下载外链文件中的代码，然后解析并执行它。在这个过程中，页面渲染和用户交互完全被阻塞了。

回页首

脚本位置

HTML 4 规范指出 <script> 标签可以放在 HTML 文档的<head>或<body>中，并允许出现多次。Web 开发人员一般习惯在 <head> 中加载外链的 JavaScript，接着用 <link> 标签用来加载外链的 CSS 文件或者其他页面信息。例如清单 2

清单 2 低效率脚本位置示例

<html>
<head>
<title>Source Example</title>
<script type="text/javascript" src="script1.js"></script>
<script type="text/javascript" src="script2.js"></script>
<script type="text/javascript" src="script3.js"></script>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<p>Hello world!</p>
</body>
</html>

然而这种常规的做法却隐藏着严重的性能问题。在清单 2 的示例中，当浏览器解析到 <script> 标签（第 4 行）时，浏览器会停止解析其后的内容，而优先下载脚本文件，并执行其中的代码，这意味着，其后的 styles.css 样式文件和<body>标签都无法被加载，由于<body>标签无法被加载，那么页面自然就无法渲染了。因此在该 JavaScript 代码完全执行完之前，页面都是一片空白。图 1 描述了页面加载过程中脚本和样式文件的下载过程。

图 1 JavaScript 文件的加载和执行阻塞其他文件的下载

我们可以发现一个有趣的现象：第一个 JavaScript 文件开始下载，与此同时阻塞了页面其他文件的下载。此外，从 script1.js 下载完成到 script2.js 开始下载前存在一个延时，这段时间正好是 script1.js 文件的执行过程。每个文件必须等到前一个文件下载并执行完成才会开始下载。在这些文件逐个下载过程中，用户看到的是一片空白的页面。

从 IE 8、Firefox 3.5、Safari 4 和 Chrome 2 开始都允许并行下载 JavaScript 文件。这是个好消息，因为<script>标签在下载外部资源时不会阻塞其他<script>标签。遗憾的是，JavaScript 下载过程仍然会阻塞其他资源的下载，比如样式文件和图片。尽管脚本的下载过程不会互相影响，但页面仍然必须等待所有 JavaScript 代码下载并执行完成才能继续。因此，尽管最新的浏览器通过允许并行下载提高了性能，但问题尚未完全解决，脚本阻塞仍然是一个问题。

由于脚本会阻塞页面其他资源的下载，因此推荐将所有<script>标签尽可能放到<body>标签的底部，以尽量减少对整个页面下载的影响。例如清单 3

清单 3 推荐的代码放置位置示例

<html>
<head>
<title>Source Example</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<p>Hello world!</p>

<!-- Example of efficient script positioning -->
<script type="text/javascript" src="script1.js"></script>
<script type="text/javascript" src="script2.js"></script>
<script type="text/javascript" src="script3.js"></script>
</body>
</html>

这段代码展示了在 HTML 文档中放置<script>标签的推荐位置。尽管脚本下载会阻塞另一个脚本，但是页面的大部分内容都已经下载完成并显示给了用户，因此页面下载不会显得太慢。这是优化 JavaScript 的首要规则：将脚本放在底部。

回页首

组织脚本

由于每个<script>标签初始下载时都会阻塞页面渲染，所以减少页面包含的<script>标签数量有助于改善这一情况。这不仅针对外链脚本，内嵌脚本的数量同样也要限制。浏览器在解析 HTML 页面的过程中每遇到一个<script>标签，都会因执行脚本而导致一定的延时，因此最小化延迟时间将会明显改善页面的总体性能。

这个问题在处理外链 JavaScript 文件时略有不同。考虑到 HTTP 请求会带来额外的性能开销，因此下载单个 100Kb 的文件将比下载 5 个 20Kb 的文件更快。也就是说，减少页面中外链脚本的数量将会改善性能。

通常一个大型网站或应用需要依赖数个 JavaScript 文件。您可以把多个文件合并成一个，这样只需要引用一个<script>标签，就可以减少性能消耗。文件合并的工作可通过离线的打包工具或者一些实时的在线服务来实现。

需要特别提醒的是，把一段内嵌脚本放在引用外链样式表的<link>之后会导致页面阻塞去等待样式表的下载。这样做是为了确保内嵌脚本在执行时能获得最精确的样式信息。因此，建议不要把内嵌脚本紧跟在<link>标签后面。

回页首

无阻塞的脚本

减少 JavaScript 文件大小并限制 HTTP 请求数在功能丰富的 Web 应用或大型网站上并不总是可行。Web 应用的功能越丰富，所需要的 JavaScript 代码就越多，尽管下载单个较大的 JavaScript 文件只产生一次 HTTP 请求，却会锁死浏览器的一大段时间。为避免这种情况，需要通过一些特定的技术向页面中逐步加载 JavaScript 文件，这样做在某种程度上来说不会阻塞浏览器。

无阻塞脚本的秘诀在于，在页面加载完成后才加载 JavaScript 代码。这就意味着在 window 对象的 onload事件触发后再下载脚本。有多种方式可以实现这一效果。

延迟加载脚本

HTML 4 为<script>标签定义了一个扩展属性：defer。Defer 属性指明本元素所含的脚本不会修改 DOM，因此代码能安全地延迟执行。defer 属性只被 IE 4 和 Firefox 3.5 更高版本的浏览器所支持，所以它不是一个理想的跨浏览器解决方案。在其他浏览器中，defer 属性会被直接忽略，因此<script>标签会以默认的方式处理，也就是说会造成阻塞。然而，如果您的目标浏览器支持的话，这仍然是个有用的解决方案。清单 4 是一个例子

清单 4 defer 属性使用方法示例

<script type="text/javascript" src="script1.js" defer></script>

带有 defer 属性的<script>标签可以放置在文档的任何位置。对应的 JavaScript 文件将在页面解析到<script>标签时开始下载，但不会执行，直到 DOM 加载完成，即onload事件触发前才会被执行。当一个带有 defer 属性的 JavaScript 文件下载时，它不会阻塞浏览器的其他进程，因此这类文件可以与其他资源文件一起并行下载。

任何带有 defer 属性的<script>元素在 DOM 完成加载之前都不会被执行，无论内嵌或者是外链脚本都是如此。清单 5 的例子展示了defer属性如何影响脚本行为：

清单 5 defer 属性对脚本行为的影响

<html>
<head>
<title>Script Defer Example</title>
</head>
<body>
<script type="text/javascript" defer>
alert("defer");
</script>
<script type="text/javascript">
alert("script");
</script>
<script type="text/javascript">
window.onload = function(){
alert("load");
};
</script>
</body>
</html>

这段代码在页面处理过程中弹出三次对话框。不支持 defer 属性的浏览器的弹出顺序是：“defer”、“script”、“load”。而在支持 defer 属性的浏览器上，弹出的顺序则是：“script”、“defer”、“load”。请注意，带有 defer 属性的<script>元素不是跟在第二个后面执行，而是在 onload 事件被触发前被调用。

如果您的目标浏览器只包括 Internet Explorer 和 Firefox 3.5，那么 defer 脚本确实有用。如果您需要支持跨领域的多种浏览器，那么还有更一致的实现方式。

HTML 5 为<script>标签定义了一个新的扩展属性：async。它的作用和 defer 一样，能够异步地加载和执行脚本，不因为加载脚本而阻塞页面的加载。但是有一点需要注意，在有 async 的情况下，JavaScript 脚本一旦下载好了就会执行，所以很有可能不是按照原本的顺序来执行的。如果 JavaScript 脚本前后有依赖性，使用 async 就很有可能出现错误。

动态脚本元素

文档对象模型（DOM）允许您使用 JavaScript 动态创建 HTML 的几乎全部文档内容。<script>元素与页面其他元素一样，可以非常容易地通过标准 DOM 函数创建：

清单 6 通过标准 DOM 函数创建<script>元素

var script = document.createElement ("script");
script.type = "text/javascript";
script.src = "script1.js";
document.getElementsByTagName("head")[0].appendChild(script);

新的<script>元素加载 script1.js 源文件。此文件当元素添加到页面之后立刻开始下载。此技术的重点在于：无论在何处启动下载，文件的下载和运行都不会阻塞其他页面处理过程。您甚至可以将这些代码放在<head>部分而不会对其余部分的页面代码造成影响（除了用于下载文件的 HTTP 连接）。

当文件使用动态脚本节点下载时，返回的代码通常立即执行（除了 Firefox 和 Opera，他们将等待此前的所有动态脚本节点执行完毕）。当脚本是“自运行”类型时，这一机制运行正常，但是如果脚本只包含供页面其他脚本调用调用的接口，则会带来问题。这种情况下，您需要跟踪脚本下载完成并是否准备妥善。可以使用动态 <script> 节点发出事件得到相关信息。

Firefox、Opera, Chorme 和 Safari 3+会在<script>节点接收完成之后发出一个 onload 事件。您可以监听这一事件，以得到脚本准备好的通知：

清单 7 通过监听 onload 事件加载 JavaScript 脚本

var script = document.createElement ("script")
script.type = "text/javascript";

//Firefox, Opera, Chrome, Safari 3+
script.onload = function(){
alert("Script loaded!");
};

script.src = "script1.js";
document.getElementsByTagName("head")[0].appendChild(script);

Internet Explorer 支持另一种实现方式，它发出一个 readystatechange 事件。<script>元素有一个 readyState 属性，它的值随着下载外部文件的过程而改变。readyState 有五种取值：

- “uninitialized”：默认状态

- “loading”：下载开始

- “loaded”：下载完成

- “interactive”：下载完成但尚不可用

- “complete”：所有数据已经准备好

微软文档上说，在<script>元素的生命周期中，readyState 的这些取值不一定全部出现，但并没有指出哪些取值总会被用到。实践中，我们最感兴趣的是“loaded”和“complete”状态。Internet Explorer 对这两个 readyState 值所表示的最终状态并不一致，有时<script>元素会得到“loader”却从不出现“complete”，但另外一些情况下出现“complete”而用不到“loaded”。最安全的办法就是在 readystatechange 事件中检查这两种状态，并且当其中一种状态出现时，删除 readystatechange 事件句柄（保证事件不会被处理两次）：

清单 8 通过检查 readyState 状态加载 JavaScript 脚本

var script = document.createElement("script")
script.type = "text/javascript";

//Internet Explorer
script.onreadystatechange = function(){
if (script.readyState == "loaded" || script.readyState == "complete"){
script.onreadystatechange = null;
alert("Script loaded.");
}
};

script.src = "script1.js";
document.getElementsByTagName("head")[0].appendChild(script);

大多数情况下，您希望调用一个函数就可以实现 JavaScript 文件的动态加载。下面的函数封装了标准实现和 IE 实现所需的功能：

清单 9 通过函数进行封装

function loadScript(url, callback){
var script = document.createElement ("script")
script.type = "text/javascript";
if (script.readyState){ //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" || script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
};
} else { //Others
script.onload = function(){
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}

此函数接收两个参数：JavaScript 文件的 URL，和一个当 JavaScript 接收完成时触发的回调函数。属性检查用于决定监视哪种事件。最后一步，设置 src 属性，并将<script>元素添加至页面。此 loadScript() 函数使用方法如下：

清单 10 loadScript()函数使用方法

loadScript("script1.js", function(){
alert("File is loaded!");
});

您可以在页面中动态加载很多 JavaScript 文件，但要注意，浏览器不保证文件加载的顺序。所有主流浏览器之中，只有 Firefox 和 Opera 保证脚本按照您指定的顺序执行。其他浏览器将按照服务器返回它们的次序下载并运行不同的代码文件。您可以将下载操作串联在一起以保证他们的次序，如下：

清单 11 通过 loadScript()函数加载多个 JavaScript 脚本

loadScript("script1.js", function(){
loadScript("script2.js", function(){
loadScript("script3.js", function(){
alert("All files are loaded!");
});
});
});

此代码等待 script1.js 可用之后才开始加载 script2.js，等 script2.js 可用之后才开始加载 script3.js。虽然此方法可行，但如果要下载和执行的文件很多，还是有些麻烦。如果多个文件的次序十分重要，更好的办法是将这些文件按照正确的次序连接成一个文件。独立文件可以一次性下载所有代码（由于这是异步进行的，使用一个大文件并没有什么损失）。

动态脚本加载是非阻塞 JavaScript 下载中最常用的模式，因为它可以跨浏览器，而且简单易用。

使用 XMLHttpRequest(XHR)对象

此技术首先创建一个 XHR 对象，然后下载 JavaScript 文件，接着用一个动态 <script> 元素将 JavaScript 代码注入页面。清单 12 是一个简单的例子：

清单 12 通过 XHR 对象加载 JavaScript 脚本

var xhr = new XMLHttpRequest();
xhr.open("get", "script1.js", true);
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
var script = document.createElement ("script");
script.type = "text/javascript";
script.text = xhr.responseText;
document.body.appendChild(script);
}
}
};
xhr.send(null);

此代码向服务器发送一个获取 script1.js 文件的 GET 请求。onreadystatechange 事件处理函数检查 readyState 是不是 4，然后检查 HTTP 状态码是不是有效（2XX 表示有效的回应，304 表示一个缓存响应）。如果收到了一个有效的响应，那么就创建一个新的<script>元素，将它的文本属性设置为从服务器接收到的 responseText 字符串。这样做实际上会创建一个带有内联代码的<script>元素。一旦新<script>元素被添加到文档，代码将被执行，并准备使用。

这种方法的主要优点是，您可以下载不立即执行的 JavaScript 代码。由于代码返回在<script>标签之外（换句话说不受<script>标签约束），它下载后不会自动执行，这使得您可以推迟执行，直到一切都准备好了。另一个优点是，同样的代码在所有现代浏览器中都不会引发异常。

此方法最主要的限制是：JavaScript 文件必须与页面放置在同一个域内，不能从 CDN 下载（CDN 指"内容投递网络（Content Delivery Network）"，所以大型网页通常不采用 XHR 脚本注入技术。

回页首

减少 JavaScript 对性能的影响有以下几种方法：

- 将所有的<script>标签放到页面底部，也就是</body>闭合标签之前，这能确保在脚本执行前页面已经完成了渲染。

- 尽可能地合并脚本。页面中的<script>标签越少，加载也就越快，响应也越迅速。无论是外链脚本还是内嵌脚本都是如此。

- 采用无阻塞下载 JavaScript 脚本的方法：

- 使用<script>标签的 defer 属性（仅适用于 IE 和 Firefox 3.5 以上版本）；

- 使用动态创建的<script>元素来下载并执行代码；

- 使用 XHR 对象下载 JavaScript 代码并注入页面中。

通过以上策略，可以在很大程度上提高那些需要使用大量 JavaScript 的 Web 网站和应用的实际性能。

参考资料

- 加入 developerWorks 中文社区。查看开发人员推动的博客、论坛、组和维基，并与其他 developerWorks 用户交流。

关于作者

蔡愉晟 是 IBM 中国软件开发实验室 Smarter Commerce 旗下产品 DemandTec 的一名软件工程师，之前曾在 UT/LTD 部门工作，目前主要从事 DemandTec: End-2-End Promotion 产品的开发工作。对 HTML5、CSS3 相关技术有浓厚的兴趣。

关于报告滥用的帮助

报告滥用

关于报告滥用的帮助

报告滥用

IBM ID：
需要一个 IBM ID？
忘记 IBM ID？

密码：
忘记密码？
更改您的密码

保持登录。

单击提交则表示您同意developerWorks 的条款和条件。 使用条款

当您初次登录到 developerWorks 时，将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人，但您可以随时修改这些信息的显示状态。您的姓名（除非选择隐藏）和昵称将和您在 developerWorks 发布的内容一同显示。

当您初次登录到 developerWorks 时，将会为您创建一份概要信息，您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的，并且出于隐私保护的原因，不能是您的电子邮件地址。

昵称：

单击提交则表示您同意developerWorks 的条款和条件。 使用条款.

为本文评分

回页首

原文链接：http://www.ibm.com/developerworks/cn/web/1308_caiys_jsload/index.html （本内容由互联网资料整理而成）

【翻译】解读ECMAScript 6箭头函数

原文地址：http://www.nczonline.net/blog/2013/09/10/understanding-ecmascript-6-arrow-functions/

箭头函数是ECMAScript 6最受关注的更新内容之一。它引入了一种用「箭头」（=>）来定义函数的新语法，它…它碉堡了~。箭头函数与传统的JavaScript函数主要区别在于以下几点：

- 对 this 的关联。函数内置 this 的值，取决于箭头函数在哪儿定义，而非箭头函数执行的上下文环境。

- new 不可用。箭头函数不能使用 new 关键字来实例化对象，不然会报错。

- this 不可变。函数内置 this 不可变，在函数体内整个执行环境中为常量。

- 没有arguments对象。更不能通过arguments对象访问传入参数。只能使用显式命名或其他ES6新特性来完成。

这些差异的存在是有理可循的。首先，对this的绑定是JavaScript错误的常见来源之一。容易丢失函数内置数值，或得出意外结果。其次，将箭头函数限制为使用固定this引用，有利于JavaScript引擎优化处理。

语法

箭头函数的语法很简单，定义自变量，然后是箭头和函数主体。自变量和主题因使用不同可以采用更简洁的格式。下面这个例子就是采用传一个参数和返回一个值的箭头函数。

var reflect = value => value;
// 等同于：

var reflect = function(value) {
return value;
};

可以看出，传一个参数就直接写就好了，不用加小括号。箭头指向函数主体，不过函数主体也只是简单的一条返回语句，所以也不用加大括号。函数构造完毕赋给reflect加以引用。
若需传入多个参数，则应加上小括号。例如：

var sum = (num1, num2) => num1 + num2;
// 等同于：
var sum = function(num1, num2) {
return num1 + num2;
};

sum()方法为两参数相加并回传结果。跟前一个例子的唯一区别是传入了两个参数，所以要用小括号括起来。它与传统函数一样，括号内由逗号将传入参数分开。同样，如果该函数不需要传入参数，那也要以空括号来代替。

var sum = () => 1 + 2;
// 等同于：
var sum = function() {
return 1 + 2;
};

若你想使用标准的函数体，或者函数体内可能有更多的语句要执行，则要用大括号将函数体括起来，并明确定义返回值。例如：

var sum = (num1, num2) => { return num1 + num2; }
//等同于：
var sum = function(num1, num2) {
return num1 + num2;
};

大括号内的部分基本等同于传统函数，除了arguments参数不可用外。
因为大括号是函数主体的标志。而箭头函数若要返回自定义对象的话，就必须用小括号把该对象括起来先。例如：

var getTempItem = id = > ({
id: id,
name: "Temp"
});
// 等同于：
var getTempItem = function(id) {
return {
id: id,
name: "Temp"
};
};

上例可以看出，用小括号包含大括号则是对象的定义，而非函数主体。

使用

JavaScript最常见错误之一就是函数内部this关联。因为this是根据函数当前的执行环境去取值的，这样就会在调用时产生误解，以导致对其他的不相关对象产生了影响。参见下例：

var PageHandler = {
id: "123456",
init: function() {
document.addEventListener("click", function(event) {
this.doSomething(event.type); // error
}, false);
},
doSomething: function(type) {
console.log("Handling " + type + " for " + this.id);
}
};

在这段代码中，本意是想让PageHandler的init()方法用于构建交互作用，并在点击事件处理函数中调用this.doSomething()。但是代码并未按设计初衷来执行，运行时this指向了全局对象而不是PageHandler，从而造成this.doSomething()调用无效出现报错，因为全局对象中不存在doSomething方法。
当然，可以在函数中使用bind()将this与PageHandler明确关联起来，见下：

var PageHandler = {

id: "123456",

init: function() {
document.addEventListener("click", (function(event) {
this.doSomething(event.type);
}).bind(this), false);
},

doSomething: function(type) {
console.log("Handling " + type + " for " + this.id);
}
};

虽然看着有些怪，但现在代码执行是符合预期的。通过调用函数的bind(this)，又创建了一个已关联现有this的新函数返回，就是说为了达到目的额外又包了一层。
因为箭头函数已经支持this关联，所以这里用箭头函数会更爽快些，看下例：

var PageHandler = {

id: "123456",

init: function() {
document.addEventListener("click",
event = > this.doSomething(event.type), false);
},

doSomething: function(type) {
console.log("Handling " + type + " for " + this.id);
}
};

这个实例中的事件处理函数调用了this.doSomething()的箭头函数。this的取值即为init()内的this值。故而它等效于bind()。
箭头函数简明扼要的特性，也使它成为其他函数自变量的理想选择。例如，若要在ES5上，使用定制比较器来排列数组，典型的代码见下：

var result = values.sort(function(a, b) {
return a - b;
});

上例用了许多语法来实现一个简单的操作。若使用箭头函数，则可写成很精炼的代码：

var result = values.sort((a, b) => a - b);

数组的sort/map/reduce等方法都支持回调函数。用箭头函数可以简化书写流程，解放你的双手去做你想做的事情。

补充

箭头函数的确与传统函数有不同之处，但仍存在共同的特点。例如：

- 对箭头函数进行typeof操作会返回“function”。

- 箭头函数仍是Function的实例，故而instanceof的执行方式与传统函数一致。

- call/apply/bind方法仍适用于箭头函数，但就算调用这些方法扩充当前作用域，this也依旧不会变化。

箭头函数与传统函数最大的不同之处在，禁用new操作。

结论

箭头函数是ECMAScript 6一个备受关注的新特性，并且还在不断的优化着。用简短语法以定义函数或语句书写流程是大势所趋，他们必将屌炸天，无人可阻。它对关键字this的关联让开发者不再神烦，并通过JavaScript引擎优化，帮助其提高表现。说到这里，小伙伴们的大刀已经饥渴难耐了吧，若想试用箭头函数，打开最新版本的Firefox即可。【关于箭头函数的更多详情可以参考：尝试 ES6 中的箭头函数】

原文链接：http://www.75team.com/archives/504 （本内容由互联网资料整理而成）

【翻译】行高的相关计算——文档节选

翻译原文链接：http://www.w3.org/TR/2011/REC-CSS2-20110607/visudet.html#line-height

译者序：

翻译该段文档，是因为自己在写相应的样式时遇到了疑惑，于是找文档看说明，发现很多地方和自己以前的理解还是有很大的差异，阅读后收获颇丰，而且网上目前的中文参考资料中似乎也找不到原滋原味的定义。于是决定自己翻译一下，也算是对自己的锻炼吧。第一次翻译，错误和不足的地方欢迎大家指正。

ps：没想到短短的一段文档翻译居然用了两三周时间才完成。文章仅为翻译，对知识点的整理和总结等以后有时间再考虑吧。

阅读该文档时需注意每个用词，不同用词有不同含义，相似的用词往往指代的是不同的对象。一定要弄清楚文档描述说明的对象是什么。文档中“box”统一翻译成了“盒子”，“elements”统一翻译成了“元素”。

行高的计算(Line height calculations: the ‘line-height’ and ‘vertical-align’ properties)

正如在章节「行级格式化上下文(inline formatting contexts)」中的描述，用户代理将行内级盒子(inline-level boxes)布局到一个由行盒(line boxes)垂直排列而成的容器里。单个行盒的高度按下列规则进行判定：

1. 行盒中每个行级盒的高度都将通过计算获得。对于替换元素(replaced elements)，行级块元素(inline-block elements)和行级表单元素(inline-table elements)，其高度为他们外边框(margin box)的高度；对于行内盒(inline boxes)，其高度为他们的line-height。

2. 行级盒在垂直方向上依照他们的vertical-align属性进行对齐。当他们按top或者bottom的值进行对齐时，必须保证其排列方式能使行盒的高度尽可能的小。如果行级盒过高，对于行盒的基线(baseline)的定位，有多种方案，但css 2.1 规范并未对此进行定义。

3. 行盒的高度为他内部所有盒子中，最高的盒子的顶部和最低的盒子的底部之间的距离。（其计算包含‘strut’——将在‘line-height’章节之下进行说明）

空的行内元素生成空的行内盒，但这些盒子依然拥有外边距，内边距，边框和行高，因此产生的影响则是其高度的计算和非空元素的一样。

行距和半行距(Leading and half-leading)

css假定每种字体都能够通过指定在其基线上的一个特定高度和在其基线下的一个特定深度来对其进行度量。在此假定下，我们用A表示这个高度，用D表示这个深度。我们同时定义AD=A+D，及顶边到底边的距离。注意，该方法是在将字体作为一个整体进行度量时使用，而无需在意个别字形实际的上边缘和下边缘。

用户代理必须在一个非替换行内盒(non-replaced inline box)中根据每个字形的基线进行对齐。对每个字形，分别计算其A和D。注意，每个字形都是单独的元素，可能由不同的字体组成，因此也不必拥有相同的A和D。如果行内盒不包含任何字形，他将包含一个‘strut’（一个零宽的无形的字形），其A和D为元素第一个有效字体的A和D。

我们还需要确定添加到每个字形上的行距L，L=line-height-AD。行距的一半被添加到A上面，另一半被添加到D下面。最终我们得到基线之上A’=A+L/2和基线之下D’=D+L/2所确定的字形和他的行距的一个总高度。

提示：L可能是负数

行内盒通过包裹所有字形和字形上下两边的半行距(half-leading)所形成的高度就是line-height。子元素的盒子(boxes)对此高度不产生影响。

然而非替换元素的外边距，边框，内边距不参与行盒的计算。他们将被渲染到行内盒周围。这就是说，line-height指定的高度可能小于contained boxes的内容高度，内边距和边框的背景和高度可能溢出到相邻的行盒内。用户代理应该按文档顺序渲染盒子。这将会使后一行的边框副高到前一行的边框和文字之上。

提示：CSS 2.1 没有定义行内盒的内容区域是什么，所以不同的UA可能以不同的方式绘制背景和边框

‘line-height’

(译注：具体参数说明见链接)

对于内容由行内级元素组成的块级包含元素(block container element)，line-height指定了包含子元素的行盒的最小高度。如果每个行盒正好由一个零宽度的拥有元素的字体和行高的行内盒开始，则行盒的最小高度由基线以上的最小高度和基线以下的最小深度组成。我们称这个假想的盒子为“strut”。

字体基线上下的高度和深度的度量方式假定已包含在字体中。

对于非替换行内元素，line-height指定的高度被用于行盒高度的计算。

(译注：这段参数取值的说明的翻译省略)

当元素包含的文本被渲染成多种字体的时候，用户代理可以根据最大的字体尺寸来决定normal值。

提示：当在块级包含盒子中的所有行内盒（不包括替换元素，行级块元素等）的line-height取值相同且都拥有相同的字体时，连续的基线应该被打散，因为这对于在列方向上有不同字体但又必须进行对齐时，是非常重要的。例如在表格中。(译注：后半段理解不是太清楚，按猜测意译的。)

‘vertical-align’

(译注：具体参数说明见链接)

该属性影响一个由行内级元素产生的盒子在行盒内垂直方向上的定位。

提示：该属性在表格上下文中具有不同的含义，具体内容参见「table height algorithms」章节

以下取值仅在其参照对象为“行内元素的父元素”或“块级包含元素的父元素的 strut”时有意义。

在下列的定义中，对于行内级非替换元素，用于对齐的盒子为高度是line-height（包括盒子的字形和上下两边的半行距，见上文）的盒子。对于其他元素，用于对齐的盒子为其外边框。

baseline

使盒子的基线和父元素的基线在一条线上。如果盒子没有基线，这使其外边框的底边和父元素的基线在一条线上。

middle

使盒子的中线和父元素的基线加上x字符高度的一半对齐。

(译注：sub、super、text-top、text-bottom、<percentage>、<length>的取值说明翻译省略，可自行搜索相关含义)

以下取值使元素相对于行盒进行对齐。因为元素可能有已经参照其对齐的子元素，所以这些取值使用已对齐子树的边界来对其。行内级元素的已对齐子树(aligned subtree)包括这个元素和他所有的计算出的vertical-align的取值不为top或bottom的行内级子元素的已对齐子树。已对齐子树的顶部为子树中顶边最高的盒子的顶部，底部同理。

top

使已对齐子树的顶部和行盒的顶部对齐

使已对齐子树的顶部和行盒的底部对齐

inline-table的基线为表格第一行的基线。

当inline-block的子元素中没有在文档流中的行盒或者inline-block的overflow属性的计算值不为visible时，其基线为外边距的底边。否则inline-block的基线为其文档流中最后一个行盒的基线。

原文参见：
http://snadn.cnblogs.com/snadn/p/3313185.html

原文链接：http://www.75team.com/archives/501 （本内容由互联网资料整理而成）

Bootstrap 3 网格系统简介

After over 9 months of work, Bootstrap 3 is here. It introduces a new way of thinking on how the responsive grid works, when it is best applied, and how the styled elements within the breakpoints work as well.

Bootstrap 2’s grid was very straight forward. If you were using the fixed width containers, there was a normal, large, tablet, and mobile size. The base styles were all written within the context of the “desktop” width. Mobile styles were applied after through the responsive stylesheet. Compared to v3, it was very limited in out-of-the-box mobile convenience.

Bootstrap 3 has been heavily publicized as being mobile first. There’s been a design movement in the last year or two for “designing” mobile first, where you take your concepts and UX and plan it from the mobile perspective first, i.e. your interactions, wireframes, mockups, etc were all designed initially for the mobile experience. Bootstrap 3 has adopted that idea and built the framework on the idea that your base CSS and html should be from a mobile perspective by default.

Mobile First CSS

Great. So what does this actually *mean* if I’ve never done this before? Well, let’s just jump to a very simple example. Say you have an h1 tag at the top of your site. You design it up and check it out in your browser – looks great. Then you shrink it down to a mobile width, and the font is way too big! Here’s the thinking behind mobile first: Bootstrap expects that the styles you applied to the h1 are appropriate for the *mobile* widths. So if you chose your font size, padding, margin etc, at the desktop size, that will probably be way off at the mobile size.

Here’s an example of this:

h1 {

font-size:40px;

margin-bottom:20px;

margin-left:20px;

That is how you wanted it to look on the desktop, a nice big 40px font. But at a mobile size, it’s too big and the padding is too large. How would you have to do it with a mobile first CSS framework? Like this:

h1 {

font-size:22px;

margin:bottom10px;

@media min-width(@screen-tablet) {

font-size: 40px;

margin-bottom:20px;

margin-left:20px;

See, the actual base style is the mobile style. Anything that you wanted changed at the next larger size is encapsulated in the @screen-tablet media query. Our font is sized at 22px by default, but at the desktop size it is at 40px. And, you can see that I didn’t need a margin-left on the base style, but I did add one in on the @screen-tablet breakpoint size, so it only applies when you’re past that min-width.

The Grid’s Basic Markup

For the markup that goes into your HTML, there are big changes. There are now 4 different grid classes you can use to define your layouts. This is where if you haven’t worked with a framework like this before, or you are accustomed to Bootstrap v2, it is a new way of looking at it. There are now 4 column size class variants:

- col-xs-*

- col-sm-*

- col-md-*

- col-lg-*

Now, before you panic and think “I have to write 3-4-5 freaking styles for every class I make?!” Probably not. Most of the time, the styles work fine at all the sizes, especially at the tablet and larger sizes. It’s only when you see specific needs at the larger sizes that you have to add in the adjustments. It is a small amount of time added, but:

1. It’s way better than the old way of having whole mobile stylesheets and a “desktop first” CSS base.

2. Once you get used to it, the flexibility and power will allay any doubts.

The premise is that the grid is controlled by the viewport size via the media queries and that as the browser width gets wider, the different column class will overwrite the previous. So at the phone width, the “xs (extra small)” column is active. But if you stretch your browser out wide, then the “lg (large)” class is active and overwrites the smaller sizes. If you’re confused, hang on and keep reading. This is a whole new Bootstrap paradigm. Instead of the elastic band approach of Bootstrap 2, v3 gives you now incremental control at each breakpoint.

Useful right? No? Don’t know? Let’s keep going!

Example 1 – Basic Single Columns

I am going to try and make these explanations as dead simple as possible. You have 2 divs you want to be each 50% of the total container

<div class="">I’m on the left</div>

<div class="">I’m on the right</div>

Now, in Bootstrap 2, we would have used the class .span6 for both. This would have given us the 50%/50% split at the tablet and up sizes, and then it would snap to the 100% width columns at the mobile breakpoint. Not so in Bootstrap 3. Since this is a mobile first framework, all of the base columns are assumed to be 100% width, stacked vertically. Huh? So in the example above, if you wanted these 2 divs to be 50%/50%, you would FIRST have to decide at which breakpoints. If you say “I want them to be 50%/50% down to the desktop size, but not tablet or phone”, it would be written like this:

<div class="col-med-6">I'm on the left</div>

<div class="col-med-6">I'm on the right</div>

This says “Make me a 6 column at the medium size and up.” Anything smaller than medium, it goes back to the 100% width stacked layout. This is mobile first, everything assumes that you are designing for a mobile, extra small viewport. So, let’s say you want it to be a 50%/50% split all the way down to the smallest phone width, no matter what. You use a different class for that, one that says “keep me as a 50% column all the way down to the phone size.”  You would use the new “xs” extra small class:

<div class="col-xs-6">I’m on the right</div>

<div class="col-xs-6">I’m on the left</div>

This basically says “keep me at a 6 column width all the way down to the phone size, don’t ever switch me to the stacked mobile layout.” That means on a phone, it will still be a 50%/50% split on the columns since you used the specific col-xs-6 class. To take it the other direction, say you want to have the same divs be 50%/50% at the largest snapping point, and ONLY at that point. It’s just as easy:

<div class="col-lg-6">I’m on the right</div>

<div class="col-lg-6">I’m on the left</div>

That tells it to apply the “6 column” size at only the large size and up. As soon as you hit the break point going narrower, it will again assume that it’s a mobile design and take it to 100% width. I have made examples pages for this post, so Example 1 is demonstrating this most basic concept.

Mixed Width Columns

Now we have seen the basics of how the html markup classes work. But lets go deeper. Let’s use our 2 divs again and let’s give them the 50%/50% split at the medium viewport width:

<div class="col-md-6">I’m on the left</div>

<div class="col-md-6">I’m on the right</div>

Now, here’s where it’s new. Let’s say that you want it 50/50 at medium, but at large your design could really be better as a 33%/66%. So what we’re going to do is set it up to change the column widths at the breakpoint:

<div class="col-md-6 col-lg-4">I’m on the left</div>

<div class="col-md-6 col-lg-8">I’m on the right</div>

Does that make sense? Bootstrap is going to say “at the medium size, I look at classes with ‘md’ in them and use those. At the large size, I look at classes with the word ‘lg’ in them and use those.” In this case, our 2 divs will go from a 50%/50% split and then up to a 33%/66%. Just like that. This can be taken to another level, where we want to change it for the extra small phone size as well. Say we want to add the option for the columns to be split 25%/75% for tablets, we go like this:

<div class="col-sm-3 col-md-6 col-lg-4">I’m on the left</div>

<div class="col-sm-9 col-md-6 col-lg-8">I’m on the right</div>

Now this gives us 3 different column layouts at each point. On a phone, it will be 25% on the left, and 75% on the right. On a tablet, it will be 50%/50% again, and on a large viewport, it will be 33%/66%. 3 different layouts for each of the 3 responsive sizes! Check it out in example 2:

But, I know what some of you are thinking; that’s a lot of markup in your HTML, you could possibly use up to 4 different classes just for the grid. Some people mind that, some don’t. But there’s an answer to that too: mixins.

Mixin

Bootstrap 2 was set up to create columns from mixins, and v3 takes it even further. You can create your rows and columns purely from mixins and leave any grid markup out of your HTML. There are 2 basic mixin types for creating the grid:

- .make-row();

- .make-xs/sm/md/lg-column();

You use these mixins inside of elements that you want to serve those purposes. Here’s an example where I have a single div left-and-right that I want to be the row, and then left and right to be the columns inside:

<div class="left-and-right">

<div class="left">I'm on the left</div>

<div class="right">I'm on the right</div>

</div>

Without grid column classes, these divs will just assume the default behavior of block level elements. Since we want to use the grid, but don’t want to use any markup, we’ll create the row and columns using mixins, (using Less, of course). Using the HTML above, a block of Less could look like this:

.left-and-right {

.make-row();

.left {

.make-md-column(6);

.right {

.make-md-column(6);

That will add to those classes the properties of the col-md-6 that would go in the HTML otherwise. Using the mixins, you don’t have to include any markup in the HTML.

Going back to example 2 of multiple, different breakpoints on an element, you can do that with the mixins too. Once you know how you want the layout at each responsive size, you just add the column mixins within each media query. Here’s an example with mixins for all 4 layout sizes:

.left-and-right {

.make-row();

.left {

.make-xs-column(12);

@media(min-width: @screen-tablet) {

.make-sm-column(1);

@media(min-width: @screen-desktop) {

.make-md-column(7);

@media(min-width: @screen-large-desktop) {

.make-lg-column(4);

.right {

.make-xs-column(12);

@media(min-width: @screen-tablet) {

.make-sm-column(11);

@media(min-width: @screen-desktop) {

.make-md-column(5);

@media(min-width: @screen-large-desktop) {

.make-lg-column(8);

This changes the column widths of .left and .right at each layout. In this wacky example, the side by side .left and .right would be jumping around pretty drastically, but the effect is clearly visible here in example three:

Also in this example, since we are using the make-xs-column() mixin, the phone size grid will still maintain side-by-side columns and not the vertical stack. As of right now, Bootstrap doesn’t allow not having a column mixin in the base mobile size, so  you need to include a make-xs-column(12) like shown above so those root classes will have the Bootstrap base grid CSS attributes applied to them. If you want to use a custom mixin, I’ve made a dead simple one that can be used in case Bootstrap doesn’t account for this case in the future: Bootstrap 3 Smallest Column Mixin

Pull/Push/offset

In both the HTML class and mixin method, offsets and pull/push work in the same way. You can include them as classes right in the markup, or dynamically include them as mixins. One difference between using the HTML markup and the mixins is that if you use the HTML method, at the tablet width the offsets are disabled and don’t change the layout in any way. If you want offsets to be in effect at tablets widths, you can include them as mixins. I am not quite sure why there is this difference, but there is.

With the pull/push abilities, you can easily flip where columns are positioned, moving them left or right at different breakpoints, which also can let them move up/down on full mobile view. It adds a lot of possibilities on top of an already powerful grid system.

Using Both Responsive Class Attributes and Mixin Columns

Taking everything we’ve learned so far, we can leverage both the CSS responsive attributes and the column mixins to basically do anything we want. This is closer to how an exaggerated real world implementation might look:

.main-content{

.make-row();

.sidebar{

padding:20px;

@media(min-width:@screen-desktop){

padding:30px;

h2{

font-size:20px;

@media(min-width:@screen-desktop){

font-size:30px

.make-xs-column(12);

@media(min-width:@screen-tablet){

.make-sm-column(2);

@media(min-width:@screen-desktop){

.make-md-column(3);

.content-area{

line-height:1.2em;

@media(min-width:@screen-desktop){

line-height:1.6em;

h1{

font-size:30px;

@media(min-width:@screen-desktop){

font-size:40px;

.make-xs-column(12);

@media(min-width:@screen-tablet){

.make-sm-column(10);

@media(min-width:@screen-tablet){

.make-md-column(9);

This essentially would let you have an entirely different layout at each responsive width, both in the grid and the styles altogether, and it’s not that much work to write in the Less. And as a bonus, by using the column mixins you don’t need to change anything in your HTML if you’ve already got it how you want it.

One of the things you have to get used to remembering is that the styles now cascade “up and out” from the base mobile CSS. Even though you can just design for the desktop view like normal, you will then have to basically “port up” the CSS from mobile widths and move the desktop styles into the right media query, and then fix/replace the styles at the base level. This isn’t a problem if you don’t care about how perfect things are at mobile widths. If you do want your site to be a great mobile experience, keep 2 browser windows open – one at the desktop width, and one at mobile. That way you can at least see when something is terribly out of place in either view.

Give em’ the boot!

Bootstrap 3 moves the whole paradigm of mobile first CSS forward, and makes it more accessible to the people who may have never done mobile first before. It’s more dynamic, flexible, and in the end I think will be easier to use.

All in all, I am very excited to use Bootstrap 3. I was a huge fan of v2, and v3 is such a step forward it’s hard not to marvel at the work that the @twbootstrap guys (@md0, @fat) and Github contributors have put into this.

Go get Bootstrap now and give it a try! If you have any comments, questions, want some help, have ideas or anything else, post in the Disqus thread below.

Examples:

(As updates are made to Bootstrap 3, or my examples need refining, I’ll be updating this article and noting where I’ve done so)

原文链接：http://www.helloerik.com/bootstrap-3-grid-introduction （本内容由互联网资料整理而成）

The iOS 7 Design Cheat Sheet

The old simple radii values for rounded corners are gone. Apple introduced a new shape, which got named "superellipse" by Michael Flarup (I think that‘s a great way to describe this shape). Since Apple did not release an official template of the shape, you will have to use one of the unofficial templates out there, which are replicating the shape in more or less accurate ways. The best I‘ve came across so far is the App Icon Template, which is definitely a very good starting point when you‘re designing an app icon for iOS 7. As always, the rounded corners should not be included in your final exported assets - but you might need them while your design process if you want to add effects, such as a stroke or shadows, which are aligned to the corner of the icon.

Grid system

Apple developed a golden ratio grid system, which can be used to size and align elements on your icon correctly. Anyways, the grid template got criticized a lot by the design community, and it seems like designers (even Apple designers) are not following the grid system very strictly. Feel free to break rules if your icon looks better without taking care of the new grid system.

原文链接：http://ivomynttinen.com/blog/the-ios-7-design-cheat-sheet/ （本内容由互联网资料整理而成）

Google Chrome中的高性能网络(一)

Google Chrome的历史和指导原则

【译注】这部分不再详细翻译，只列出核心意思。

驱动Chrome继续前进的核心原则包括:

- Speed: 做最快的(fastest)的浏览器.

- Security:为用户提供最为安全的(most secure)的上网环境。

- Stability:提供一个健壮且稳定的(resilient and stable)的Web应用平台。

- Simplicity: 以简练的用户体验(simple user experience)封装精益求精的技术(sophisticated technology)。

本文关将注于第一点，速度。

关于性能的方方面面

一个现代浏览器就是一个和操作系统一样的平台。在Chrome之前的浏览器都是单进程的应用，所有页面共享相同的地址空间和资源。引入多进程架构这是Chrome最为著名的改进【译注:省略一些反复谈论的细节】。

一个进程内，Web应用主要需要执行三个任务:获取资源，页面排版及渲染，和运行JavaScript。渲染和脚本都是在运行中交替以单线程的方式运行的，其原因是为了保持DOM的一致性，而JavaScript本身也是一个单线程的语言。所以优化渲染和脚本运行无论对于页面开发者还是浏览器开发者都是极为重要的。

Chrome的渲染引擎是WebKit, JavaScript Engine则使用深入优论的V8 ("V8" JavaScript runtime)。但是，如果网络不畅，无论优化V8的JavaScript执行，还是优化WebKit的解析和渲染，作用其实很有限。巧妇难为无米之炊，数据没来就得等着!

相对于用户体验，作用最为明显的就是如何优化网络资源的加载顺序、优先级及每一个资源的延迟时间(latency)。也许你察觉不到，Chrome网络模块每天都在进步，逐步降低每个资源的加载成本：向DNS lookups学习，记住页面拓扑结构(topology of the web), 预先连接可能的目标网址，等等，还有很多。从外面来看就是一个简单的资源加载的机制，但在内部却是一个精彩的世界。

关于Web应用

开始正题前，还是先来了解一下现在网页或者Web应用在网络上的需求。

HTTP Archive 项目一直在追踪网页构建。除了页面内容外，它还会分析流行页面使用的资源数量，类型，头信息以及不同目标地址的元数据(metadata)。下面是2013年1月的统计资料，由300，000目标页面得出的平均数据:

- 1280 KB

- 包含88个资源(Images,JavaScript,CSS ...)

- 连接15个以上的不同主机(distinct hosts)。

这些数字在过去几年中一直持续增长( steadily increasing )，没有停下的迹象。这说明我们正不断地建构一个更加庞大的、野心勃勃的网络应用。还要注意，平均来看每个资源不过12KB, 表明绝大多数的网络传输都是短促(short and bursty)的。这和TCP针对大数据、流式(streaming)下载的方向不一致，正因为如此，而引入了一些并发症。下面就用一个例子来抽丝剥茧，一窥究竟......

一个Resource Request的一生

给定一个网页资源地址后，浏览器就会检查本地缓存和应用缓存。如果之前获取过并且有相应的缓存信息(appropriate cache headers)(如Expires,Cache-Control, etc.), 就会用缓存数据填充这个请求，毕竟最快的请求就是没有请求(the fastest request is a request not made)。否则，我们重新验证资源，如果已经失效(expired),或者根本就没见过，一个耗费网络的请求就无法避免地发送了。

给定了一个主机名和资源路径后，Chrome先是检查现有已建立的连接(existing open connections)是否可以复用, 即sockets指定了以(scheme、host和port)定义的连接池(pool)。但如果配置了一个代理，或者指定了 proxy auto-config (PAC)脚本，Chrome就会检查与proxy的连接。PAC脚本基于URL提供不同的代理，或者为此指定了特定的规则。与每一个代理间都可以有自己的socket pool。最后，上述情况都不存在，这个请求就会从DNS查询(DNS lookup)开始了，以便获得它的IP地址。

幸运的话，这个主机名已经被缓存过。否则，必须先发起一个DNS Query。这个过程所需的时间和ISP,页面的知名度，主机名在中间缓存(intermediate caches)的可能性，以及authoritative servers的响应时间这些因素有关。也就是说这里变量很多，不过一般还不致于到几百毫秒那么夸张。

拿到解析出的IP后,Chrome就会在目标地址间打开一个新TCP连接，我们就要执行一个3度握手("three-way handshake"): SYN > SYN-ACK > ACK。这个操作每个新的TCP连接都必须完成，没有捷径。根据远近，路由路径的选择，这个过程可能要耗时几百毫秒，甚至几秒。而到现在，我们连一个有效的字节都还没收到。

当TCP握手完成了，如果我们连接的是一个HTTPS地址，还有一个SSL握手过程，同时又要增加最多两轮的延迟等待。如果SSL会话被缓存了，就只需一次。

最后，Chrome终于要发送HTTP请求了 (如上面图示中的requestStart)。服务器收到请求后，就会传送响应数据(response data)回到客户端。这里包含最少的往返延迟和服务的处理时间。然后一个请求就完成了。但是，如果是一个HTTP重定向(redirect)的话？我们又要从头开始这个过程。如果你的页面里有些冗余的重定向，最好三思一下！

你得出所有的延迟时间了吗? 我们假设一个典型的宽带环境：没有本地缓存，相对较快的DNS lookup(50ms), TCP握手，SSL协商，以及一个较快服务器响应时间(100ms)和一次延迟(80ms,在美国国内的平均值):

- 50ms for DNS

- 80ms for TCP handshake (one RTT)

- 160ms for SSL handshake (two RTT's)

- 40ms （发送请求到服务器）

- 100ms (服务器处理)

- 40ms (服务器回传响应数据)

一个请求花了470毫秒, 其中80%的时间被网络延迟占去了。看到了吧，我们真得有很多事情要做！事实上,470毫秒已经很乐观了:

怎样才算"够快"?

前面可以看到服务器响应时间仅是总延迟时间的20%，其它都被DNS，握手等操作占用了。过去用户体验研究( user experience research )表明用户对延迟时间的不同反应：

延迟

用户反应

0 - 100ms

迅速

100 - 300ms

有点慢

300 - 1000ms

机器还在运行

1s+

想想别的事…...

10s+

我一会再来看看吧...

上表同样适用于页面的性能表现: 渲染页面，至少要在250ms内给个回应来吸引住用户。这就是简单地针对速度。从Google, Amazon, Microsoft,以及其它数千个站点来看，额外的延迟直接影响页面表现：流畅的页面会吸引更多的浏览、以及更强的用户吸引力(engagement)和页面转换率(conversion rates).

现在我们知道了理想的延迟时间是250ms，而前面的示例告诉我们，DNS Lookup, TCP和SSL握手，以及request的准备时间花去了370ms, 即便不考虑服务器处理时间，我们也超出了50%。

对于绝大多数的用户和网页开发者来说，DNS, TCP，以及SSL延迟都是透明，很少有人会想到它。这也就是为什么Chrome的网络模块那么的复杂。

我们已经识别出了问题，下面让我们深入一下实现的细节...

深入Chrome的网络模块

多进程架构

Chrome的多进程架构为浏览器的网络请求处理带来了重要意义，它目前支持四种不同的执行模式( four different execution models ).

默认情况下，桌面的Chrome浏览器使用process-per-site模式, 将不同的网站页面隔离起来, 相同网站的页面组织在一起。举个简单的例子: 每个tab独立一个进程。从网络性能的角度上说,并没什么本质上的不同，只是process-per-tabl模式更易于理解。

每一个tab有一个渲染进程(render process)，其中包括了用于解析页面(interpreting)和排版(layout out)的WebKit的排版引擎(layout engine), 即上图中的HTML Render。还有V8引擎和两者之间的DOM Bindings，如果你对这部分很好奇，可以看这里( great introduction to the plumbing )。

每一个这样的渲染进程被运行在一个沙箱环境中，只会对用户的电脑环境做极有限的访问--包括网络。而使用这些资源，每一个渲染进程必须和浏览内核进程(browser[kernel] process)沟通，以管理每个渲染进程的安全性和访问策略(access policies)。

进程间通讯(IPC)和多进程资源加载

渲染进程和内核进程之间的通讯是通过IPC完成的。在Linux和Mac OS上，使用了一个提供异步命名管道通讯方式的socketpair()。每一个渲染进程的消息会被序列化地到一个专用的I/O线程中，然后再由它发到内核进程。在接收端，内核进程提供一个过滤接口(filter interface)用于解析资源相关的IPC请求( ResourceMessageFilter ), 这部分就是网络模块负责的。

这样做其中一个好处是所有的资源请求都由I/O进程处理，无论是UI产生的活动，或者网络事件触发的交互。在内核进程(browser/kernel process)的I/O线程解析资源请求消息，将转发到一个ResourceDispatcherHost的单例(singleton)对象中处理。

这个单例接口允许浏览器控制每个渲染进程对网络的访问，也能达到有效和一致的资源共享：

- Socket pool 和 connection limits: 浏览器可以限定每一个profile打开256个sockets, 每个proxy打开32个sockets, 而每一组{scheme, host, port}可以打开6个。注意同时针对一组{host,port}最多允计打开6个HTTP和6个HTTPS连接。

- Socket reuse: 在Socket Pool中提供持久可用的TCP connections，以供复用。这样可以为新的连接避免额外建立DNS、TCP和SSL(如果需要的话)所花费的时间。

- Socket late-binding(延迟绑定): 网络请求总是当Scoket准备好发送数据时才与一个TCP连接关连起来，所以首先有机会做到对请求有效分级(prioritization)，比如，在socket连接过程中可能会到达到一个更高优先级的请求。同时也可以有更好的吞吐率(throughput),比如，在连接打开过程中，去复用一个刚好可用的socket, 就可以使用到一个完全可用的TCP连接。其实传统的TCP pre-connect(预连接)及其它大量的优化方法也是这个效果。

- Consistent session state (一致的会话状态): 授权、cookies及缓存数据会在所有渲染进程间共享。

- Global resource and network optimizations (全局资源和网络优化): 浏览器能够在所有渲染进程和未处理的请求间做更优的决策。比如给当前tab对应的请求以更好的优先级。

- Predictive optimizations （预测优化）: 通过监控网络活动，Chrome会建立并持续改善预测模型来提升性能。

- ... 项目还在增加中.

单就一个渲染进程而言, 透过IPC发送资源请求很容易，只要告诉浏览器内核进程一个唯一ID, 后面就交给内核进程处理了。

跨平台的资源加载

跨平台也是Chrome网络模块的一个主要考量，包括Linux, Windows, OS X, Chrome OS, Android, 和iOS。 为此，网络模块尽量实现成了单进程模式（只分出了独立的cache和proxy进程）的跨平台函数库, 这样就可以在平台间共用基础组件(infrastructure)并分享相同的性能优化，更有机会做到同时为所有平台进行优化。

相关的代码可以在这里找到the "src/net" subdirectory)。本文不会详细展开每个组件，不过了解一下代码结构可以帮助我们理解它的能力结构。 比如:

net/android

绑定到Android 运行时(runtime) [译注(Horky):运行时真是一个很烂的术语，翻和没翻一样。]

net/base

公共的网络工具函数。比如,主机解析，cookies, 网络转换侦测(network change detection),以及SSL认证管理

net/cookies

实现了Cookie的存储、管理及获取

net/disk_cache

磁盘和内存缓存的实现

net/dns

实现了一个异步的DNS解析器(DNS resolver)

net/http

实现了HTTP协议

net/proxy

代理(SOCKS 和 HTTP)配置、解析(resolution) 、脚本抓取(script fetching), ...

net/socket

TCP sockets,SSL streams和socket pools的跨平台实现

net/spdy

实现了SPDY协议

net/url_request

URLRequest, URLRequestContext和URLRequestJob的实现

net/websockets

实现了WebSockets协议

上面每一项都值得好好读读，代码组织的很好，你还会发现大量的单元测试。

Mobile平台上的架构和性能

移动浏览器正在大发展，Chrome团队也视优化移动端的体验为最高优先级。先要说明的是移动版的Chrome的并不是其桌面版本的直接移植，因为那样根本不会带来好的用户体验。移动端的先天特性就决定了它是一个资源严重受限的环境，在运行参数有一些基本的不同:

- 桌面用户使用鼠标操作，可以有重叠的窗口，大的屏幕，也不用担心电池。网络也非常稳定，有大量的存储空间和内存。

- 移动端的用户则是触摸和手势操作，屏幕小，电池电量有限，通过只能用龟速且昂贵的网络，存储空间和内存也是相当受限。

再者，不但没有典型的样板移动设备，反而是有一大批各色硬件的设备。Chrome要做的，只能是设法兼容这些设备。好在Chrome有不同的运行模式(execution models)，面对这些问题，游刃有余！

在Android版本上，Chrome同样运用了桌面版本的多进程架构- 一个浏览器内核进程，以及一个或多个渲染进程。但因为内存的限制，移动版的Chrome无法为每一个tabl运行一个特定的渲染进程，而是根据内存情况等条件决定一个最佳的渲染进程个数，然后就会在多个tab间共享这些渲染进程。

如果内存实在不足，或其它原因导致Chrome无法运行多进程，它就会切到单进程、多线程的模式。比如在iOS设备上，因为其沙箱机制的限制，Chrome只能运行在这种模式下。

关于网络性能，首先Chrome在Android和iOS使用的是各其它平台相同的网络模块。这可以做到跨平台的网络优化，这也是Chrome明显领先的优势之一。所不同的是需要经常根据网络情况和设备能力进行些调整，包括推测优化(speculative optimization)的优先级、socket的超时设置和管理逻辑、缓存大小等。

比如，为了延长电池寿命，移动端的Chrome会倾向于延迟关闭空闲的sockets (lazy closing of idle sockets), 通常是为了减少信号(radio)的使用而在打开新的socket时关闭旧的。另外因为预渲染(pre-rendering,稍后会介绍)会使用一定的网络和处理资源，它通常只在WiFi才会使用。

关于移动浏览体验会独立一章，也许就在POSA系列的下一期。
转载请注明出处:http://blog.csdn.net/horkychen
原文地址: http://www.igvita.com/posa/high-performance-networking-in-google-chrome/
系列索引:
Google Chrome中的高性能网络(一)

Google Chrome中的高性能网络(二)

Google Chrome中的高性能网络(三)

原文链接：http://blog.csdn.net/horkychen/article/details/9708103 （本内容由互联网资料整理而成）

当浏览器邂逅小数值

各浏览器对于计算后宽度和高度为含有小数的长度值时，其最终值会不一致。

最近做项目的时候遇到这个问题，网上也有很多相关的资料，借鉴了一些再加上自己总结的在这里和大家分享一下。

首先参见如下代码：

<div style="width: 304px; background-color: blue;">
<div style="width: 78%; background-color: red;">304 x 78% = 237.12</div>
</div>
<div style="width: 304px; background-color: blue;">
<div style="width: 88%; background-color: red;">304 x 88% = 267.52</div>
</div>
<div style="width: 304px; background-color: blue;">
<div style="width: 87%; background-color: red;">
<div style="width: 84%; background-color: yellow;">222 or 222.16</div>
</div>
</div>

接下来看看它在各浏览器的不同布局：

1.ie6，ie7，ie8，ff

当小数位的的值不足0.5时

当小数位的值>0.5时

当父元素的计算值为小数的情况

(ie6~8)

2.ie9
当小数位的的值不足0.5时

当小数位的值>0.5时

当父元素的计算值为小数的情况

3.Chrome，Safari，Opera

当小数位的的值不足0.5时

当小数位的值>0.5时

当父元素的计算值为小数的情况

ok，综上情况可以看出，各浏览器渲染表现如下图所示，但提及两点：

1.虽然ie9会在布局栏中保留小数位，可实际上无论小数位值多大，它最终渲染的时候是采取取整的方式。

2.对于ff，当父元素的计算值是小数的时候，子元素的计算值是直接按照父元素的实际计算值，而不是通过四舍五入得到的计算值。

原文链接：http://tid.tenpay.com/?p=1389 （本内容由互联网资料整理而成）

CSS属性选择器驱动的过滤搜索技术

by zhangxinxu from http://www.zhangxinxu.com
本文地址：http://www.zhangxinxu.com/wordpress/?p=3672

一、CSS选择器可以用来实现搜索功能

CSS选择器可以用来实现搜索功能。

以前提过CSS3的选择器结合表单元素可以用来控制元素的显隐，这里，类似的，还是CSS3的选择器，用来过滤和搜索页面元素。

二、demo走起

您可以狠狠地点击这里：CSS attr属性选择器实现列表过滤效果demo

demo页面输入任意的英文字符或中文，就能过滤省会以及直辖市了，如下图：

以往，我们要根据关键字确定哪些元素应该显示或隐藏需要借助JS的字符串匹配。但是，上面的匹配与显隐完全是CSS控制的，很神奇吧，更高效更方便，到底是如何实现的呢？

三、CSS搜索过滤元素的原理

CSS3选择器中，有一个叫做属性选择器的东西，有：[attr](有该属性), [attr=xxx](属性值是xxx), [attr^=xxx](属性值是xxx开头), [attr$=xxx](属性值xxx擦屁股), [attr*=xxx](属性值包含xxx)这些用法。

demo中的过滤使用的是任意匹配，也就是[attr*=xxx]这种用法。于是，我们再结合not选择器就可以把不匹配的元素给隐藏了，例如：

.list:not([data-index*="sh"]) { display: none; }

就是所有data-index值中不含有sh的列表隐藏。

我们来看下demo的HTML，部分列表省略，关键部分标记大姨妈：

<input type="search" class="search" id="city" placeholder="输入省会或直辖市名称" />
<label class="datalist" for="city">
<div class="list" data-index="重庆市chongqing">重庆市</div>
<div class="list" data-index="哈尔滨市haerbing">哈尔滨市</div>
<div class="list" data-index="长春市changchun">长春市</div>
...
</label>

可见，CSS实现搜索的关键就是data-index这个自定义属性间的匹配。

SO，我们要实现搜索或者过滤，只要动态改变[attr*=xxx]中xxx这个值就可以了，JS验证？No, No, No! 浏览器都帮你做了，兄弟。

于是，配合下面这点JS，效果即完成：

var eleStyle = document.createElement("style");
document.querySelector("head").appendChild(eleStyle);

// 文本框输入
document.querySelector("input").addEventListener("input", function() {
var val = this.value.trim().toLowerCase();
if (val !== '') {
// 改变CSS筛选规则
eleStyle.innerHTML = '.list:not([data-index*="'+ this.value +'"]) { display: none; }';
} else {
eleStyle.innerHTML = '';
}
});

四、兼容性

属性选择器IE8就开始支持了，不过如果要使用到not选择器，似乎又要IE9+浏览器了。

因此，本技术目前IE9+支持，IE6-IE8需要您继续加班写JS代码实现。

其实，属性选择器不仅仅可以实现过滤，包括元素高亮，图标动态标注等都是可以实现的，配合其他一些CSS行为，可能会有更灿烂的菊花盛开。

行文匆促，若有错误，在所难免，欢迎指正，欢迎讨论。

参考文章：Client-side full-text search in CSS

原创文章，转载请注明来自张鑫旭-鑫空间-鑫生活[http://www.zhangxinxu.com]
本文地址：http://www.zhangxinxu.com/wordpress/?p=3672

（本篇完）

标签： :not, 属性选择器, 搜索, 选择器

原文链接：http://www.zhangxinxu.com/wordpress/?p=3672 （本内容由互联网资料整理而成）

CSS3 3D Transformations: backface-visibility

This entry is part 5 of 5 in the series CSS3 Transformations

In my previous article we transformed various elements in three-dimensional space, e.g. rotating around the y-axis:

transform: rotateY(180deg);

The element is effectively reversed and the child elements show through:

Sometimes you’ll want that effect. But sometimes you won’t. Let’s create a playing card which can be flipped over on hover/focus using a 3D transformation in conjunction with a transition. Our HTML code defines the front and back of the ace of hearts:

<div class="card">
<div class="front"><span>A♥</span> ♥ <span>A♥</span></div>
<div class="back"></div>
</div>

In the starting state, the front is rotated 180 degrees. (Actually, I’ve used -179.9 degrees to ensure it always rotates the same way since browsers will use the shortest path):

div.card div.back
{
transform: perspective(400px) rotateY(0deg);
}

div.front
{
transform: perspective(400px) rotateY(-179.9deg);
}

On hover/focus, both sides are rotated clockwise around the y-axis with perspective to give the illusion of a flipping card:

div.card:hover div.back, div.card:focus div.back
{
transform: perspective(400px) rotateY(179.9deg);
}

div.card:hover div.front, div.card:focus div.front
{
transform: perspective(400px) rotateY(0deg);
}

Unfortunately, it doesn’t work: View the first 3D card flipping page…

The back on the card will always appear above the front because that’s the way it’s defined in the HTML. No amount of z-index manipulation shenanigans will help you.

Fortunately, there’s a simple solution. The backface-visibility (and -webkit-backface-visibility) can be assigned a value of:

- visible — the default; the element is reversed, or

- hidden — an element is hidden when it is reversed

We can therefore apply this to our front and back elements:

div.card div
{
backface-visibility: hidden;
}

Success! View the second 3D card flipping page…

If you reduce the animation speed (by increasing the time), you’d discover that div.front becomes visible after it has rotated by 90 degrees and div.back becomes invisible at the same time.

When combined with transitions and animations, 2D and 3D transformations become incredibly powerful and effective. It’s too easy to go overboard with migraine-inducing effects — sometimes, less is more — but the only limit is your imagination. Please post URLs to any interesting demonstrations you create.

原文链接：http://www.sitepoint.com/css3-transformations-3d-backface-visibility/ （本内容由互联网资料整理而成）

[原创]Flash新版本11.8上传文件时中文名显示乱码问题解决方案

今天（2013-09-12）下午，flashplayer升级到11.8.800.168，发现在IE下上传文件时，上传列表中的中文名显示乱码，如下所示：

实际选择的文件名是：

网上很多人都有反馈该问题。在仔细检查上传的业务文件和swfupload.js文件之后，终于找到了一线生机： 代码里有个方法能返回正常（非乱码）的文件名。下面是问题排查过程及最终解决方案。

在swfupload.js中查找到fileQueued(file)方法（flash获取到文件之后将文件加入到队列之后调用），发现在这个方法中的file.name已经是乱码，不过其内部调用了unescapeFilePostParams(file)方法，这个方法被多次调用，那就在这个方法内打印出参数file.name，控制台出现一列文件名，多数都是乱码，但是其中一个居然显示了正常的文件名。真幸运~

接下来找到所有调用了unescapeFilePostParams的方法，在这些方法内部打印出file.name，找到file.name正常的那个。最后定位到了getFile方法。这个方法根据id获取文件，或者获取队列中的第一个文件，在我们的业务代码中，只有startupload和cancelupload使用了。
定位getFile后，解决方案也诞生了~
在业务代码中，只需要在file_queued_handler函数中，将file参数使用getFile转换一下即可： file = swf.getFile(file.id)。这样得到的文件名就显示正常了。

最后附一张解决之后的图：

如果大家使用swfupload开发的flash上传出现类似的问题，可以参考我的解决方案。

原文链接：http://www.75team.com/archives/508 （本内容由互联网资料整理而成）

[译]为后代选择器和ID选择器而辩护

【本文译自 Zeldman （作为前端工程师，不要告诉我你不知道他是谁）在2012年11月写的《IN DEFENSE OF DESCENDANT SELECTORS AND ID ELEMENTS》。】
除了偶尔更新下《Designing With Web Standards》，我这些年已经不再写关于CSS和HTML的具体实践和细节问题了。长江后浪推前浪——其他设计师和开发者接过了我的枪。在很大程度上，无论对他们还是对我们这个行业，这都是件好事。要说清楚代码那些事，最佳人选永远是那些每天花25小时沉浸其中的家伙——我也曾是如此。当像我这样的老家伙转向战略和管理角色（让我们有新的创新领域，也可以有新的写作主题），新一代代码高手也继续着发现和传播新知。这就是生命的神奇轮回吧。

不过在这诸多美好之中，我偶尔也会发现狗屎。有一种观念——如今甚至已固化成信条——即所谓应该避免使用id——因为id“specificity【特化度】太高”——用class总是更可取。对这一信条，我必须称之为——胡扯。

据我所知，此观念来自于Nicole Sullivan著名的面向对象的CSS。这种书写HTML和CSS的方法论被设计用于规模达数千页面的网站——且这多达数千页面的网站是由多达数十个前端工程师经过数年时间建造出来——且通常这建造过程缺乏统一准则或样式指导方针（或者等到有统一准则和样式指导方针之时已然太晚）。在这样的网站上——在像Amazon或Facebook这样从一开始就一锅乱炖的网站上——因为他们有一大帮厨子却没有一个主厨——在这样的网站上，使用id和后代选择器的组合确可能引发问题，特别是当笨拙的码农试图通过创建更specific【更特化】的后代选择器规则来覆盖基于id的后代选择器规则的时候。

在这样特定（而奇葩）的环境下，开发者们不断决斗般的把一条又一条css规则加入到巨大的一坨样式表里，这样式表更像考古遗迹，而非现代代码的好范例。面对如此一坨，Nicole告诫避免基于id的后代选择器或许是明智的。如果你倒了血霉要去弄一个庞大的、开发得一塌糊涂的网站，又不被允许按照常识和最佳实践重构模板和CSS，你可能不得不依靠class而弃用后代选择器和id。

但在几乎所有其他环境下，正确运用id和后代选择器更可取，因为这样更富语义，也更节约带宽。

我一直以来所主张的使用id的方式，其实就是HTML5新增元素的前身。2000年时，我们没有footer元素，为了给该div中的内容赋以结构上的意义，我们这样写：div id="footer"。今天，根据人们访问我们网站所用的浏览器和设备，我们可以选择用HTML5的footer元素替代老方式。但若是我们不能使用HTML5元素，使用id也没有什么不对的。

至于后代选择器，只要这个网站不是由100只猴子设计的，我们完全可以假设开发者能以协调的方式对具有id的div或者HTML5元素内的后代元素赋以样式，并且处于不同id的div或HTML元素中的相同元素可以被赋以不同样式。比如footer中的段落和列表项跟aside中的段落和列表项就可以被赋以不同样式。id（或HTML5元素）和后代选择器就是用来干这个的。给sidebar中的每个段落元素都设上classname不仅无谓浪费带宽，更是粗鲁之极。

跟我念：id没有任何问题，只要你正确运用（表达语义、表达结构、不滥用）。认为class总是比后代选择器和富有语义、表达结构的id更好，这种观念全然谬误。

请注意：我不是在贬低我的朋友Nicole Sullivan的面向对象的CSS对于那些一团乱麻的网站的作用，正如我不会贬低挖掘机对清理灾难现场的作用。我只是不想用挖掘机来清理我的房间。

【完】

原文链接：http://hax.iteye.com/blog/1850571 （本内容由互联网资料整理而成）

[译]使用HTML、CSS和JavaScript实现iOS7原生组件

译者注： 为了方便下文的表述，首先明确几个定义：

在以上图示中：
红色框内部：状态栏（原文：status bar）
黄色框内部：导航条（原文：navigation bar）
浅蓝色框内部：导航按钮（原文：navigation button）
蓝色框内部：动作按钮（原文：action button）
紫色框内部：标题（原文：title）
绿色框内部：内容区域（原文：content area）

声明：本文代码基于 iOS7 beta6，所实现的效果可能会与尚未发布的正式版有差异。

现在有多关于 Web App 在功能性以及美观程度上是否能媲美 Native App 的争论。我也做了个尝试，仅仅在暑假训练了几个小时之后，我开发了一款华丽的电子贺卡——Dedicards，它已经和 Native App 的 UI 差异很小了。

由于目前 Apple 的 App 审核组认为 Dedicards 与他们尚未发布的秘密武器—— iOS7 过于相似，于是 Deicards 被无辜的无限期搁置……所以我才有了充足的时间来完成这篇文章，记下我的探究过程以及从中的收获。

为了便于演示，我写了一个简单的 app（当然，Web App，只有简单的几个页面而已），在线演示，源码。这个项目本来没有名字，不过为了“报答”不让我通过的 Apple 审核组的亲们，我决定给这个项目起名“泰森项目”，如果亲们恰巧看到了这篇文章，还希望你们不要想太多。。。

这一次我们只讨论 iPhone，以后我会有专门的文章讨论 iPad。写这篇文章时，我参考了 Ivo Mynttinen 的《iOS 7 Cheat Sheet》 和 Lim Chee Aun 的《How I built the Hacker News mobile web app》这两篇非常棒的文章，推荐大家也好好读一下！

1. HTML & CSS

1.1 概述

在这个项目中，我将使用 HTML，CSS，JavaScript 来实现一个 “Navigation View” 组件。如下图：

它主要分两部分：一是导航条，包含当前 View 的标题，以及一些按钮。导航条会固定在屏幕顶部，不随内容滚动。二是内容区域，当内容过长时，内容区域需要上下滚动。

和以往版本不同，iOS7 对这里的 UI 进行了大幅度的升级：导航条变为毛玻璃效果的半透明，也就是说当内容区域滚动到上部时，能透过导航条模糊的看到。不过这却给我的模拟带来了很大的麻烦，对于毛玻璃效果，到现在我也没有找到好的办法来模拟。我只好先放弃，就以简单的半透明替代。（其实在 Xcode 中，有一个属性是决定是否开启毛玻璃效果的，于是我 YY 自己完美模拟了未开启这个选项时的效果）。

1.2 字体和颜色

iOS7 换用了一种叫 Helvetica Neue Ultra Light 的字体，招来了骂声连片。就连我作为 light 字体的粉丝，也忍不住要吐槽：这玩意在非视网膜屏幕中根本看不清楚。不过还好，在最新的 beta 版中，这种字体加粗了一些，一定程度的改善了这种情况。在这个项目里，我根据元素选择不同的字体宽度，使用 font-weight:300 或 font-weight:500 。

对于颜色，我借助屏幕截图和 Photoshop 得到以下几种颜色：

- 蓝色 rgb(21, 125, 251) ，用于按钮

- 黑色 rgb(0, 0, 0) ，用于文本

- 灰色 rgb(200, 199, 204) ，用于边框

- 灰色 rgb(111, 111, 116) ，用于文本

- 灰色 rgb(248, 248, 248) ，用于导航栏背景

- 白色 rgb(255, 255, 255) ，用于view背景

1.3 导航条

导航栏条100%，高44px（视网膜屏为普通屏幕绝对长度的2倍，下同）。在给它加上 line-height: 44px 使标题能垂直居中。结构代码如下：

<header>
<button class="left arrow">
<div class="label">{Left Button Label}</div>
</button>
<h1>{View Title}</h1>
<button class="right bold">
<div class="label">{Action Button Label}</div>
</button>
</header>

顾名思义，导航条提供的是导航的功能，即 view 之间的切换，切换的效果是新的 view 从左边或者右边滑出。用户通过点击导航按钮来触发 view 切换动作，导航按钮的长相类似于下图（这是从通讯录里截的）：

不过事实上，上图不是导航按钮而是动作按钮，它的作用是弹出一个提示框（警告、确认之类的）或者切换到其他的 view（比如在邮件编辑界面，点击发送，新的 view 会从底部滑出）。真正导航按钮的左边或右边会有一个箭头，如下图：

对于导航按钮，我是用了.arrow 的类名。为了实现动画效果（第2章中介绍），我把按钮上的文字单独放在一个 div 中。这就是导航按钮的结构：

<button class="left arrow"></button>

为了防止按钮过长，我给按钮加上 max-width: 140px ，限制它不能超过半个导航条的长度。还有一个神奇的样式 text-overflow: ellipsis ，有了这个样式，浏览器会自动截断过长的文字，并在最后加上省略号。

在默认情况下，按钮内部 padding: 9px ，但是在.arraw 类中把 padding-left 或 padding-right 重置为23px，因为在按钮的一侧会增加一个箭头的背景图。

最后还有一个透视的效果，如果只是半透明就好办了，background-color: rgba(248, 248, 248, 0.9) 就行了。但其实导航栏上还有一个类似于毛玻璃的模糊效果。这个效果我暂时还没找到好的模拟方法，先放弃掉，就用半透明。如果你有不喜欢半透明，可以改成 background-color:rgb(248, 248, 248) ，相当于 Native App 在 Xcode 中把 translucent 属性设成no的效果。

1.4 内容区域

如之前说的，内容区域的高度是100%，它会在导航条下方滚动。那么如何实现这个滚动呢？ Lim Chee Aun 在他的文章中阐述一种方案：在实际内容 div(.content) 的外面套一层 div(.scroll)，并给.scroll 添加 -webkit-overflow: touch 的样式。结构如下：

<div class="scroll">
<div class="content">{Content}</div>
</div>

开始时我并不想使用这个方案，我尝试着用普通的滚动方式，并给导航栏添加 position:fixed 的样式，但是动画效果显示不正常，导航栏在滚动时也有问题。

所有后来换成了 Lim Chee Aun 的方案：首先，禁止 html 和 body 上的滚动；然后，把内容区域和导航条的位置都固定到顶部。样式代码如下：

header { position: absolute; top:0; }
.scroll { position: absolute; top:0; overflow: auto; -webkit-overflow-scrolling: touch; }

然后两层设置z-index，使导航条在内容区上部：

header { z-index:10; }
.scroll { z-index:1; }

恩，内容区域的框架已经 ok 了，下面是往里面填如列表。给每一个条目都加上灰色的底边边框（作为条目之间的分割线），另外添加 margin-left: 15px 和 padding-right: 15px 的样式（这样的效果是分割线不是剧中的而是靠右显示，效果参见 demo）。

1.5 回顾

整个结构如下（先无视.scrollMask，会在第2章中介绍）

<div class="view" id="view-{id}">
<header>
<button class="left arrow">
<div class="label">{Left Button Label}</div>
</button>
<h1>{View Title}</h1>
<button class="right bold">
<div class="label">{Action Button Label}</div>
</button>
</header>
<div class="scrollMask"></div>
<div class="scroll">
<div class="content">{Content}</div>
</div>
</div>

当 view 数量较少时可以通过简单的复制罗列。但是，当数量过多时，比如超过了10个，则比较容易产生混乱。则最好简化成2个 view（因为需要切换效果所以不能是1个），然后使用 JavaScript 动态填充 view 的内容。

2. 动画效果

2.1 动作描述

动画做起来还是比较麻烦的，因为一个看似简单的 view 切换动画其中包含了至少6种细节动画，并且导航条上不同类型的按钮（动作按钮和导航按钮）的效果也不尽相同。让我们把动画分解开来看（把待进入的 view 称为新的 view，待切出的 view 称为旧的 view）：

- 旧的内容区域开始滑出，（根据截图）大约向左移动了20%。同时内容区域的亮度降低10%；

- 旧的内容区域从左向右滑动的同时，它的上层淡出一个黑色的阴影；

- 旧标题从当前中间向屏幕左边缘滑动，同时淡出；

- 新标题从屏幕右边缘向中间位置滑动，同时淡入；

- 旧按钮淡出，新按钮淡入，中间没有间隔，连贯起来看非常漂亮；

除此之外，导航按钮上还有一些细微的效果（在 iOS7 以前没这些东西，导航栏只是作为一个整体滑动）：

- 旧标题从当前中间向屏幕左边缘滑动，同时淡出；

- 导航按钮上的文字从旧标题消失的地方开始向左（或向右，和导航箭头的方向一致）移动，移动到挨到箭头为止，同时淡出；

- 以上动画的同时，箭头淡入（不移动）。

亲们看懂了么？实在太难描述了，大家还是看图吧，也可以去 demo 中体验一下。

还有另外一种切换效果，不过特别简单，只是整个 view（包括导航栏和正文区域）从屏幕底部滑动到屏幕顶部。

2.2 CSS

首先使用translateX属性打开 GPU 加速功能。动画都通过 @-webkit-keyframes 描述实现。整体来说是比较简单的，唯一要注意的是 -webkit-animation-timing-funtion 这个属性。

由于 iOS7 原生动画使用的不是标准的缓动函数（easing function），所以需要使用贝尔塞曲线（cubic-bezier）来定义它。

iOS 本身使用的不是标准的缓动函数（easeing function），所以这里我使用贝尔塞曲线（cubic-bezier）来模拟它。

如上图，我使用了 Rob La Placa 开发的一个小工具Cubic Bezier Builder来创建曲线。

切换动画，开始时速度很快，然后趋于平缓。按钮上的动画是另外一种：开始时速度非常慢，在新的 view 即将就位的时候变得非常快。

为了和追求完美的苹果气质相符，我们还需要完善一个细节：view 切换时内容区域上方的阴影。

阴影整个一层 .scrollMask 覆盖在旧 view 之上新的 view 之下。当 view 变化是阴影开始淡出，在实现上改变它的 -webkit-box-shadow（原文误作-webkit-drop-shadow）rgba 参数中的 a（透明度）。与此同时，内容区域亮度降低，通过把 .scroll 层的透明度从1变为0.9来模拟。

2.3 JavaScript

View 之间的切换以及一些动画的触发需要依赖 JavaScript 来时实现。具体来说，JavaScript 中实现一个Slide()函数：在开始切换时为要移动的 view 添加过渡效果的类名，然后侦听 webkitAnimationEnd 事件，在 view 滑出界面以后把它隐藏掉，同时去掉过渡效果的类名。

这个函数接受四个参数，最后一个可选：

- slideType：接受固定的字符串，如“sl”（从左向右滑动），“sr”（从右向左滑动），“popin”（从底部向上滑动）和“popout”（从顶部向下滑动）

- vin： 要滑如的 view 的 id

- vout：要滑出的 view 的 id

- callback [可选]：动画结束后执行的回调函数

你可以读一下 app.js 的源码，里面有一个 slideOpt 的对象，他是一个从动作类型（slideType）到动作对应类名的映射。例如“sl”动作对应的新 view 类名是 .slin 旧 view 对应的类名是 .slout。

3. 其他细节

3.1 iOS6、视网膜屏、普通屏

虽然以上的工作都在打造一款 Web App，不过你也可以通过 PhoneGap 等框架把它包装成一个 app。作为 app，iOS7 中，状态栏浮在最顶部，所以内容顶部需要空出20px。这种情况下我们给 body 元素加上 .native 的类名，在 .native 中写这个样式。

另一个需要注意的点是视网膜屏。在使用视网膜屏的 iPhone 上，浏览器会自动的把 320x480px 的窗口有转化成 640x960px。大部分情况下这种自动转换效果都比较理想。但是它会把常用的1px宽度的边框转化成2px，那样边框会显得很宽很臃肿。而且显然我们没办法设置0.5px宽度的边框。不过，困难都是纸老虎，Stephan Bönnemann 就给出了一种解决方案（Brad Birdsall 在这篇博文中也介绍了相同的方案），简单地讲就是用 box-shadow: 0 1px 1px -1px rgba(200, 199, 204, .5) 替换 border-bottom:1px solid rgb(200, 199, 204)。

不过使用这种在非视网膜屏以及 iOS6 及更低版本的系统中又不灵了。我们只好进行区分对待，可以通过使用 -webkit-max-device-pixel-ratio: 1 这个 media query 来区分是否是视网膜屏。至于怎么区分系统版本是否在iOS6或更低，我目前只想到了使用 JavaScript 来判断系统版本，在低版本的给 view 添加特定的类名（在我的 demo 中使用的是.ios6）。

3.2 标题

iOS7 对标题处理的是非常优雅的，这也符合苹果的一贯作风。Lim Chee Aun 专门有篇文章HackerWeb article对此做了详细的描写。

这种效果是使用纯 CSS 没法实现的，所以我又一次请出了 JavaScript。

首先遍历所有的 h1 元素：

var textboxes = document.querySelectorAll("h1");
for (var i=0; i&lt;(textboxes.length-1); i++)
TextboxResize(textboxes[i]);

这样所有的 h1 元素都经过 TextboxResize() 函数的处理。

根据不同的情形分为以下几种处理策略：

- 默认情况下标题剧中：
这里TextboxResize()取左右两边按钮中最长的一个的长度，作为 h1 元素的左右边距，再把 h1 的 text-align 设为 center，这样就实现标题居中而且不会盖住两侧的按钮。

- 如果按照默认方案，设置边距后剩下的空间放不下标题：
在这种情况下，减小按钮较短的按钮一侧的边距，增大另一侧。并使标题文字向按钮较长的一侧对齐（即左边按钮较长居左对齐，右边按钮较长居右对齐）。这样处理使标题比较靠近中间的位置。

- 如果按上面的方案，剩余空间仍然无法容纳标题：
这时就给 h1 加一个强大的 css 属性 text-overflow: ellipsis，浏览器会自动截断文字并添加省略号。

- 如果标题过长，并且按钮中存在带箭头的导航按钮，这时要把按钮上的文字隐藏掉，来给标题腾出空间：
具体做法是，当发现标题的空间不够用并且存在含有 .arrow 类名的按钮时，把按钮元素的 innerHTML 置空。

3.3 导航条上的事件

这里我想实现 iOS 原生应用中点击状态栏就会滚动回顶部的效果。

但是由于无法获取到状态栏的点击事件，所以这里只能使用点击导航栏来模拟这个操作。在 TextboxResize() 函数中给每一个h1元素都绑上了点击事件 ScrollTop() 。

在 ScrollTop() 中使用了一个定时器让内容区平滑的滚回到顶部。

注意：如果你的 app 要使用 PhoneGap 包装或者只需要兼容 iOS7。那么你可以模仿的更像一些：移除导航条上20px的 padding-top（本是用来给 iOS7 中的状态栏作为背景，防止和内容重叠）。然后在顶部增加一个20px高的 div，并绑定点击事件触发 ScrollTop()，这样就能完美的模拟了 iOS7 原生的效果——点击状态栏返回内容顶部。

3.4 触击事件

触屏设备上的触击事件就相当于 pc 上的鼠标点击。但是，现在 JavaScript 好像不能原生的支持触击事件，所以我们仍然使用 onclick 来定义。但是有一个问题：iOS 会自动的在用户触摸屏幕和浏览器响应事件之间添加一个300ms的延时。

虽然只有300ms，但是仍然会让用户觉得比较卡，响应不及时。我使用了一种简单的解决方案：通过 FT Labs 开发的Fastclick库，只需要一句话 FastClick.attach(document.body); 就可以消除延时。

总结

这篇文章只是我在写 Dedicards 的时候总结的几个技巧，仅供大家参考。这个方案本身还存在不小的改进的空间，比如，正文滚动时，滚动条有一部分是被导航条盖住的，还有导航条背景模糊的问题等等，这些问题肯定会有一些巧妙的解决方案。请不要吝啬你的电子，大胆的分享出来吧

最后，我再一次说明这只是一个技术原型而不是真正地解决方案。而且我始终认为，对于大型程序，Native App 才是王道。如果你本身是一个 Web 开发人员并且只准备做一个展示图文之类的“小” App，这个方案应该很适合你。同样，如果你的 App 只是通向一些网站的入口，那应该也很合适。

强烈的欢迎大家来 HN 一起讨论或者直接在本文中留言。

（原文）最后更新：2013.9.7

本文译自 Côme Courteault 的 Blog，原文地址：http://c2prods.com/web/2013/cloning-the-ui-of-ios-7-with-html-css-and-javascript/

原文链接：http://www.jedm.cn/2013/09/%E8%AF%91%E4%BD%BF%E7%94%A8html%E3%80%81css%E5%92%8Cjavascript%E6%9D%A5%E6%A8%A1%E6%8B%9Fios7-ui/ （本内容由互联网资料整理而成）

[译] 自定义元素 – 在 HTML 中定义新元素

本文翻译自 Custom Elements: defining new elements in HTML，在保证技术要点表达准确的前提下，行文风格有少量改编和瞎搞。

本文目录

注意！这篇文章介绍的 API 尚未完全标准化，并且仍在变动中，在项目中使用这些实验性 API 时请务必谨慎。

引言

现在的 web 严重缺乏表达能力。你只要瞄一眼“现代”的 web 应用，比如 GMail，就会明白我的意思。

看看这一坨 DIV，这也叫现代？然而可悲的是，这就是我们构建 web 应用的方式。难道 web 开发就不能追求更粗更硬更长……哦不对，是更高更快更强的奥林匹克精神？

用时髦标记整点儿像样的

HTML 为我们提供了一个完美的文档组织工具，然而 HTML 规范定义的元素却很有限。

假如 GMail 的标记不是那么糟糕，结果会怎样？

<hangout-module>
<hangout-chat from="Paul, Addy">
<hangout-discussion>
<hangout-message from="Paul" profile="profile.png" profile="118075919496626375791" datetime="2013-07-17T12:02">
<p>Feelin' this Web Components thing.</p>
<p>Heard of it?</p>
</hangout-message>
</hangout-discussion>
</hangout-chat>
<hangout-chat>...</hangout-chat>
</hangout-module>

亮瞎狗眼颠覆三观！这清晰的结构，不识字也看得懂啊！最爽的是，它还有很强的可维护性，只要瞧一眼它的声明结构就可以清楚地知道它到底要干嘛。

赶紧开始吧

自定义元素允许开发者定义新的 HTML 元素类型。该规范只是 web 组件模块提供的众多新 API 中的一个，但它也很可能是最重要的一个。缺少自定义元素带来的以下特性，web 组件根本玩不转：

1. 定义新的 HTML/DOM 元素

2. 基于其他元素创建扩展元素

3. 给一个标签绑定一组自定义功能

4. 扩展已有 DOM 元素的 API

注册新元素

使用 document.register() 可以创建一个自定义元素

var XFoo = document.register('x-foo');
document.body.appendChild(new XFoo());

document.register() 的第一个参数是标签名，这个标签名必须包括一个连字符（-）。因此，诸如 <x-tags>、<my-element>、 <my-awesome-app> 都是合法的标签名，而 <tabs> 和 <foo_bar> 则不是。这个限定使解析器能很容易的区分自定义元素和 HTML 规范定义的元素，同时确保了 HTML 增加新标签时的向前兼容。

第二个参数是一个可选（译注：经测试，Chrome 29 中不能省略第二个参数）的对象，用于描述该元素的原型。在这里可以为元素添加自定义功能（公开属性和方法）。这个到 添加 JS 属性和方法 一节再细说。

自定义元素默认会继承 HTMLElement 的原型，因此上一个示例等同于：

var XFoo = document.register('x-foo', {
prototype: Object.create(HTMLElement.prototype)
});

调用 document.register('x-foo') 向浏览器注册了这个新元素，并返回一个可以用来创建 <x-foo> 元素实例的构造器。如果你不想使用构造器，也可以使用其他实例化元素的技术。

提示：如果你不希望在 window 全局对象中创建元素构造器，还可以把它放进命名空间：

var myapp = {};
myapp.XFoo = document.register('x-foo');

扩展原生元素

假设原生 <button> 元素不能满足你的需求，你想将其增强为一个“超级按钮”，可以通过创建一个继承 HTMLButtonElement 原型的新元素，来扩展 <button> 元素：

var MegaButton = document.register('mega-button', {
prototype: Object.create(HTMLButtonElement.prototype)
});

这类自定义元素被称为类型扩展自定义元素。它们以继承一个特定的 HTMLElement 的方式表达了“元素 X 是一个 Y”。

示例：

<button is="mega-button">

元素如何提升

你有没有想过为什么 HTML 解析器不会对不是规范定义的标签报错？比如我们在页面中声明一个 <randomtag>，一切都很和谐。根据 HTML 规范的表述，非规范定义的元素将使用 HTMLUnknownElement 接口。<randomtag> 不是规范定义的，它会继承自 HTMLUnknownElement。

对自定义元素来说，情况就不一样了。拥有合法元素名的自定义元素将继承 HTMLElement。你可以打开控制台（不知道快捷键的都滚粗……），运行下面这段代码，看看结果是不是 true：

// “tabs”不是一个合法的自定义元素名
document.createElement('tabs').__proto__ === HTMLUnknownElement.prototype

// “x-tabs”是一个合法的自定义元素名
document.createElement('x-tabs').__proto__ == HTMLElement.prototype

注意：在不支持 document.register() 的浏览器中，<x-tabs> 仍为 HTMLUnknownElement。

unresolved（未提升）元素

由于自定义元素是由 JavaScript 代码 document.register() 注册的，因此它们可能在元素定义被注册到浏览器之前就已经声明或创建过了。比如你可以先在页面中声明 <x-tabs>，再调用 document.register('x-tabs')。

在被提升到其定义之前，这些元素被称为“unresolved 元素”。它们是拥有合法自定义元素名的 HTML 元素，只是还没有注册成为自定义元素。

下面这个表格看起来更直观一些：

类型

继承自

示例

unresolved 元素

HTMLElement

<x-tabs>、<my-element>、<my-awesome-app>

未知元素

HTMLUnknownElement

<tabs>、<foo_bar>

实例化元素

我们创建普通元素用到的一些技术也可以用于自定义元素。和所有标准定义的元素一样，自定义元素既可以在 HTML 中声明，也可以通过 JavaScript 在 DOM 中创建。

实例化自定义标签

声明元素：

<x-foo></x-foo>

在 JS 中创建 DOM：

var xFoo = document.createElement('x-foo');
xFoo.addEventListener('click', function(e) {
alert('Thanks!');
});

使用 new 操作符创建实例：

var xFoo = new XFoo();
document.body.appendChild(xFoo);

实例化类型扩展元素

实例化类型扩展自定义元素的方法和普通自定义标签惊人的相似。

声明：

<!-- <button> “是一个”超级按钮 -->
<button is="mega-button">

在 JS 中创建 DOM：

var megaButton = document.createElement('button', 'mega-button');
// megaButton instanceof MegaButton === true

看，这是一个接收第二个参数为 is 属性值的 document.createElement() 重载。

使用 new 操作符：

var megaButton = new MegaButton();
document.body.appendChild(megaButton);

现在，我们已经学习了如何使用 document.register() 来向浏览器注册一个新标签。但这还不够，接下来我们要向新标签添加属性和方法。

添加 JS 属性和方法

自定义元素最强大的地方在于，你可以在元素定义中加入属性和方法，给元素绑定特定的功能。你可以把它想象成一种给你的元素创建公开 API 的方法。

下面是一个完整的示例：

var XFooProto = Object.create(HTMLElement.prototype);
// 1. 为 x-foo 创建 foo() 方法
XFooProto.foo = function() {
alert('foo() called');
};

// 2. 定义一个只读属性 "bar".
Object.defineProperty(XFooProto, "bar", {value: 5});

// 3. 注册 x-foo
var XFoo = document.register('x-foo', {prototype: XFooProto});

// 4. 创建一个 x-foo 实例.
var xfoo = document.createElement('x-foo');

// 5. 插入页面
document.body.appendChild(xfoo);

构造原型的方法多种多样，如果你不喜欢上面这种方式，还有一个更简洁的例子：

var XFoo = document.register('x-foo', {
prototype: Object.create(HTMLElement.prototype, {
bar: {
get: function() { return 5; }
},
foo: {
value: function() {
alert('foo() called');
}
}
})
});

以上两种方式，第一种使用了 ES5 的 Object.defineProperty，第二种则使用了 get/set。

生命周期回调方法

元素可以定义特殊的方法，来注入其生存期内关键的时间点。这些方法各自有特定的名称和用途，它们被恰如其分地命名为生命周期回调：

回调方法名称

调用时间点

createdCallback

创建元素实例

enteredDocumentCallback

向文档插入实例

leftDocumentCallback

从文档中移除实例

attributeChangedCallback(attrName, oldVal, newVal)

添加，移除，或修改一个属性

示例：为 <x-foo> 定义 createdCallback() 和 enteredDocumentCallback()

var proto = Object.create(HTMLElement.prototype);

proto.createdCallback = function() {...};
proto.enteredDocumentCallback = function() {...};

var XFoo = document.register('x-foo', {prototype: proto});

所有生命周期回调都是可选的，你可以只在需要关注的时间点定义它们。举个例子，你有一个很复杂的元素，它会在 createdCallback() 打开一个 indexedDB 连接。在将其从 DOM 移除时，leftDocumentCallback() 会做一些必要的清理工作。注意：不要过于依赖这些生命周期方法（如果用户直接关闭浏览器标签，生命周期方法是没有机会执行的），仅将其作为可能的优化点。

另一个生命周期回调的例子是为元素设置默认的事件监听器：

proto.createdCallback = function() {
this.addEventListener('click', function(e) {
alert('Thanks!');
});
};

添加标记

我们已经创建好 <x-foo> 并添加了 JavaScript API，但它还没有任何内容。要不我们给它整点？

生命周期回调在这个时候就派上用场了。我们甚至可以用 createdCallback() 给一个元素赋予一些默认的 HTML：

var XFooProto = Object.create(HTMLElement.prototype);

XFooProto.createdCallback = function() {
this.innerHTML = "<b>I'm an x-foo-with-markup!</b>";
};

var XFoo = document.register('x-foo-with-markup', {prototype: XFooProto});

实例化这个标签并在 DevTools 中观察，可以看到如下结构：

用 Shadow DOM 封装内部实现

Shadow DOM 是一个封装内容的强大工具，配合使用自定义元素就更神奇了！

Shadow DOM 为自定义元素提供了：

1. 一种隐藏内部实现的方法，从而将用户与血淋淋的实现细节隔离开。

2. 简单有效的样式隔离。

从 Shadow DOM 创建元素，跟创建一个渲染基础标记的元素非常类似，区别在于 createdCallback() 回调：

var XFooProto = Object.create(HTMLElement.prototype);

XFooProto.createdCallback = function() {
// 1. Attach a shadow root on the element.
var shadow = this.createShadowRoot();

// 2. Fill it with markup goodness.
shadow.innerHTML = "<b>I'm in the element's Shadow DOM!</b>";
};

var XFoo = document.register('x-foo-shadowdom', {prototype: XFooProto});

我们并没有直接设置 <x-foo-shadowdom> 的 innerHTML，而是为其创建了一个用于填充标记的 Shadow Root。在 DevTools 中选中“显示 Shadow DOM”，你就会看到一个可以展开的 #document-fragment：

这就是 Shadow Root！

从模板创建元素

HTML Template 是另一组跟自定义元素完美融合的新 API。

模板元素可用于声明 DOM 片段。它们可以被解析并在页面加载后插入，以及延迟到运行时才进行实例化。模板是声明自定义元素结构的理想方案。

示例：注册一个由模板和 Shadow DOM 创建的元素：

<template id="sdtemplate">
<style>
p { color: orange; }
</style>
<p>I'm in Shadow DOM. My markup was stamped from a &amplt;template&ampgt;.</p>
</template>

<script>
var proto = Object.create(HTMLElement.prototype, {
createdCallback: {
value: function() {
var t = document.querySelector('#sdtemplate');
this.createShadowRoot().appendChild(t.content.cloneNode(true));
}
}
});
document.register('x-foo-from-template', {prototype: proto});
</script>

短短几行做了很多事情，我们挨个来看都发生了些什么：

1. 我们在 HTML 中注册了一个新元素：<x-foo-from-template>

2. 这个元素的 DOM 是从一个模板创建的

3. Shadow DOM 隐藏了该元素的实现细节

4. Shadow DOM 也对元素的样式进行了隔离（p {color: orange;} 不会把整个页面都搞成橙色）

牛逼！

为自定义元素增加样式

和其他 HTML 标签一样，自定义元素也可以通过选择器定义样式：

<style>
app-panel {
display: flex;
}
[is="x-item"] {
transition: opacity 400ms ease-in-out;
opacity: 0.3;
flex: 1;
text-align: center;
border-radius: 50%;
}
[is="x-item"]:hover {
opacity: 1.0;
background: rgb(255, 0, 255);
color: white;
}
app-panel > [is="x-item"] {
padding: 5px;
list-style: none;
margin: 0 7px;
}
</style>

<app-panel>
<li is="x-item">Do</li>
<li is="x-item">Re</li>
<li is="x-item">Mi</li>
</app-panel>

为使用 Shadow DOM 的元素增加样式

有了 Shadow DOM 场面就热闹得多了，它可以极大增强自定义元素的能力。

Shadow DOM 为元素增加了样式封装的特性。Shadow Root 中定义的样式不会暴露到宿主外部或对页面产生影响。对自定义元素来说，元素本身是宿主。样式封装的属性也使得自定义元素能够为自己定义默认样式。

Shadow DOM 的样式是一个很大的话题！如果你想更多地了解它，推荐你阅读我写的其他文章：

- Polymer 文档：《元素样式指南》。

- 发表于 html5rocks.com 的《Shadow DOM 201：CSS 和样式》

使用 :unresolved 伪类避免无样式内容闪烁（FOUC）

为了缓解无样式内容闪烁的影响，自定义元素规范提出了一个新的 CSS 伪类 :unresolved。在浏览器调用你的createdCallback()（请看生命周期回调方法一节）之前，这个伪类都可以匹配到 unresolved 元素。一旦产生调用，就意味着元素已经完成提升，成为它被定义的形态，该元素就不再是一个 unresolved 元素。

Chrome 29 已经原生支持 :unresolved 伪类。

示例：注册后渐显的 <x-foo> 标签：

x-foo {
opacity: 1;
transition: opacity 300ms;
}
x-foo:unresolved {
opacity: 0;
}

请记住 :unresolved 伪类只能用于 unresolved 元素，而不能用于继承自 HTMLUnkownElement 的元素（请看元素如何提升一节）。

<style>
/* 给所有未提升元素添加边框 */
:unresolved {
border: 1px dashed red;
display: inline-block;
}
/* 未提升的 x-panel 文本内容为红色 */
x-panel:unresolved {
color: red;
}
/* 完成注册的 x-panel 文本内容为绿色 */
x-panel {
color: green;
display: block;
padding: 5px;
display: block;
}
</style>

<panel>
I'm black because :unresolved doesn't apply to "panel".
It's not a valid custom element name.
</panel>

<x-panel>I'm red because I match x-panel:unresolved.</x-panel>

了解更多 :unresolved 的知识，请看 Polymer 文档《元素样式指南》。

历史和浏览器支持

特性检测就是检查浏览器是否提供了 document.register() 接口：

function supportsCustomElements() {
return 'register' in document;
}

if (supportsCustomElements()) {
// 使用自定义元素 API
} else {
// 使用其他类库创建组件
}

浏览器支持

Chrome 27 和 Firefox 23 都提供了对 document.register() 的支持，不过之后规范又有一些演化。Chrome 31 将是第一个支持新规范的版本。提示：在 Chrome 31 中使用自定义元素，需要开启 about:flags 中的“实验性 web 平台特性（Experimental Web Platform features）”选项。

在浏览器支持稳定之前，也有一些很好的过渡方案：

- Google Polymer 框架提供了一个 polyfill

- Mozilla 开发的 x-tags 类库

HTMLElementElement 怎么了？

紧跟过标准的人都知道曾经有一个 <element> 标签。它非常好用，你只要像下面这样就可以声明式的注册一个新元素：

<element name="my-element">
...
</element>

不幸的是，在它的提升过程、边界案例，以及末日般的复杂场景中，需要处理大量的时序问题。<element> 因此被迫搁置。2013 年 8 月，Dimitri Glazkov 在 public-webapps 邮件组中宣告废弃 <element>，至少目前看来是废掉了。

值得注意的是，Polymer 实现了用 形式声明式地注册元素。这是怎么做到的？它用的正是 document.register('polymer-element') 以及从模板创建元素一节介绍的技术。

结语

自定义元素为我们提供了一个工具，通过它我们可以扩展 HTML 的词汇，赋予它新的特性，并把不同的 web 平台连接在一起。结合其他新的基本平台，如 Shadow DOM 和模板，我们领略了 web 组件的宏伟蓝图。标记语言将再次变得很时髦！

如果你对使用 web 组件感兴趣，建议你去看看 Polymer 框架，从它开始玩吧。

原文链接：http://forcefront.com/2013/custom-elements-defining-new-elements-in-html/ （本内容由互联网资料整理而成）

HTML5 的 IndexedDB

One of the more interesting developments in web standards lately is the Indexed Database (IndexedDB for short) specification. For a fun time you can read the spec yourself. In this tutorial I’ll be explaining this feature and hopefully giving you some inspiration to use this powerful feature yourself.

Overview

As a specification, IndexedDB is currently a Candidate Recommendation.

In a nutshell, IndexedDB provides a way for you to store large amounts of data on your user’s browser. Any application that needs to send a lot of data over the wire could greatly benefit from being able to store that data on the client instead. Of course storage is only part of the equation. IndexedDB also provides a powerful indexed based searching API to retrieve the data you need.

You may wonder how IndexedDB differs from other storage mechanisms?

Cookies are extremely well supported, but have legal implications and limited storage space. Also – they are sent back and forth to the server with every request, completely negating the benefits of client-side storage.

Local Storage is also very well supported, but limited in terms of the total amount of storage you can use. Local Storage doesn’t provide a true “search” API as data is only retrieved via key values. Local Storage is great for “specific” things you may want to store, for example, preferences, whereas IndexedDB is better suited for Ad Hoc data (much like a database).

Before we go any further though, let’s have an honest talk about the state of IndexedDB in terms of browser support. As a specification, IndexedDB is currently a Candidate Recommendation. At this point the folks behind the specification are happy with it but are now looking for feedback from the developer community. The specification may change between now and the final stage, W3C Recommendation. In general, the browsers that support IndexedDB now all do in a fairly consistent manner, but developers should be prepared to deal with prefixes and take note of updates in the future.

As for those browsers supporting IndexedDB, you’ve got a bit of a dilemma. Support is pretty darn good for the desktop, but virtually non-existent for mobile. Let’s see what the excellent site CanIUse.com says:

Chrome for Android does support the feature, but very few people are currently using that browser on Android devices. Does the lack of mobile support imply you shouldn’t use it? Of course not! Hopefully all our readers are familiar with the concept of progressive enhancement. Features like IndexedDB can be added to your application in a manner that won’t break in non-supported browsers. You could use wrapper libraries to switch to WebSQL on mobile, or simply skip storing data locally on your mobile clients. Personally I believe the ability to cache large blocks of data on the client is important enough to use now even without mobile support.

Let’s Get Started

We’ve covered the specification and support, now let’s look at using the feature. The very first thing we should do is check for IndexedDB support. While there are tools out there that provide generic ways to check for browser features, we can make this much simpler since we’re just checking for one particular thing.

document.addEventListener("DOMContentLoaded", function(){

if("indexedDB" in window) {
console.log("YES!!! I CAN DO IT!!! WOOT!!!");
} else {
console.log("I has a sad.");
}

},false);

The code snippet above (available in test1.html if you download the zip file attached to this article) uses the DOMContentLoaded event to wait for the page to load. (Ok, that’s kind of obvious, but I recognize this may not be familiar to folks who have only used jQuery.) I then simply see if indexedDB exists in the window object and if so, we’re good to go. That’s the simplest example, but typically we would probably want to store this so we know later on if we can use the feature. Here’s a slightly more advanced example (test2.html).

var idbSupported = false;

document.addEventListener("DOMContentLoaded", function(){

if("indexedDB" in window) {
idbSupported = true;
}

},false);

All I’ve done is created a global variable, idbSupported, that can be used as a flag to see if the current browser can use IndexedDB.

Opening a Database

IndexedDB, as you can imagine, makes use of databases. To be clear, this isn’t a SQL Server implementation. This database is local to the browser and only available to the user. IndexedDB databases follow the same rules as cookies and local storage. A database is unique to the domain it was loaded from. So for example, a database called “Foo” created at foo.com will not conflict with a database of the same name at goo.com. Not only will it not conflict, it won’t be available to other domains as well. You can store data for your web site knowing that another web site will not be able to access it.

Opening a database is done via the open command. In basic usage you provide a name and a version. The version is very important for reasons I’ll cover more later. Here’s a simple example:

var openRequest = indexedDB.open("test",1);

Opening a database is an asynchronous operation. In order to handle the result of this operation you’ll need to add some event listeners. There’s four different types of events that can be fired:

- success

- error

- upgradeneeded

- blocked

You can probably guess as to what success and error imply. The upgradeneeded event is used both when the user first opens the database as well as when you change the version. Blocked isn’t something that will happen usually, but can fire if a previous connection was never closed.

Typically what should happen is that on the first hit to your site the upgradeneeded event will fire. After that – just the success handler. Let’s look at a simple example (test3.html).

var idbSupported = false;
var db;

document.addEventListener("DOMContentLoaded", function(){

if("indexedDB" in window) {
idbSupported = true;
}

if(idbSupported) {
var openRequest = indexedDB.open("test",1);

openRequest.onupgradeneeded = function(e) {
console.log("Upgrading...");
}

openRequest.onsuccess = function(e) {
console.log("Success!");
db = e.target.result;
}

openRequest.onerror = function(e) {
console.log("Error");
console.dir(e);
}

}

},false);

Once again we check to see if IndexedDB is actually supported, and if it is, we open a database. We’ve covered three events here – the upgrade needed event, the success event, and the error event. For now focus on the success event. The event is passed a handler via target.result. We’ve copied that to a global variable called db. This is something we’ll use later to actually add data. If you run this in your browser (in one that supports IndexedDB of course!), you should see the upgrade and success message in your console the first time you run the script. The second, and so forth, times you run the script you should only see the success message.

Object Stores

So far we’ve checked for IndexedDB support, confirmed it, and opened a connection to a database. Now we need a place to store data. IndexedDB has a concept of “Object Stores.” You can think of this as a typical database table. (It is much more loose than a typical database table, but don’t worry about that now.) Object stores have data (obviously) but also a keypath and an optional set of indexes. Keypaths are basically unique identifiers for your data and come in a few different formats. Indexes will be covered later when we start talking about retrieving data.

Now for something crucial. Remember the upgradeneeded event mentioned before? You can only create object stores during an upgradeneeded event. Now – by default – this will run automatically the first time a user hits your site. You can use this to create your object stores. The crucial thing to remember is that if you ever need to modify your object stores, you’re going to need to upgrade the version (back in that open event) and write code to handle your changes. Lets take a look at a simple example of this in action.

var idbSupported = false;
var db;

document.addEventListener("DOMContentLoaded", function(){

if("indexedDB" in window) {
idbSupported = true;
}

if(idbSupported) {
var openRequest = indexedDB.open("test_v2",1);

openRequest.onupgradeneeded = function(e) {
console.log("running onupgradeneeded");
var thisDB = e.target.result;

if(!thisDB.objectStoreNames.contains("firstOS")) {
thisDB.createObjectStore("firstOS");
}

}

openRequest.onsuccess = function(e) {
console.log("Success!");
db = e.target.result;
}

openRequest.onerror = function(e) {
console.log("Error");
console.dir(e);
}

}

},false);

This example (test4.html) builds upon the previous entries so I’ll just focus on what’s new. Within the upgradeneeded event, I’ve made use of the database variable passed to it (thisDB). One of the properties of this variable is a list of existing object stores called objectStoreNames. For folks curious, this is not a simple array but a “DOMStringList.” Don’t ask me – but there ya go. We can use the contains method to see if our object store exists, and if not, create it. This is one of the few synchronous functions in IndexedDB so we don’t have to listen for the result.

To summarize then – this is what would happen when a user visits your site. The first time they are here, the upgradeneeded event fires. The code checks to see if an object store, “firstOS” exists. It will not. Therefore – it is created. Then the success handler runs. The second time they visit the site, the version number will be the same so the upgradeneeded event is not fired.

Now imagine you wanted to add a second object store. All you need to do is increment the version number and basically duplicate the contains/createObjectStore code block you see above. The cool thing is that your upgradeneeded code will support both people who are brand new to the site as well as those who already had the first object store. Here is an example of this (test5.html):

var openRequest = indexedDB.open("test_v2",2);

openRequest.onupgradeneeded = function(e) {
console.log("running onupgradeneeded");
var thisDB = e.target.result;

if(!thisDB.objectStoreNames.contains("firstOS")) {
thisDB.createObjectStore("firstOS");
}

if(!thisDB.objectStoreNames.contains("secondOS")) {
thisDB.createObjectStore("secondOS");
}

}

Adding Data

Once you’ve got your object stores ready you can begin adding data. This is – perhaps – one of the coolest aspects of IndexedDB. Unlike traditional table-based databases, IndexedDB lets you store an object as is. What that means is you can take a generic JavaScript object and just store it. Done. Obviously there’s some caveats here, but for the most part, that’s it.

Working with data requires you to use a transaction. Transactions take two arguments. The first is an array of tables you’ll be working with. Most of the time this will be one table. The second argument is the type of transaction. There are two types of transactions: readonly and readwrite. Adding data will be a readwrite operation. Let’s start by creating the transaction:

//Assume db is a database variable opened earlier
var transaction = db.transaction(["people"],"readwrite");

Note the object store, “people”, is just one we’ve made up in the example above. Our next full demo will make use of it. After getting the transaction, you then ask it for the object store you said you would be working with:

var store = transaction.objectStore("people");

Now that you’ve got the store you can add data. This is done via the – wait for it – add method.

//Define a person
var person = {
name:name,
email:email,
created:new Date()
}

//Perform the add
var request = store.add(person,1);

Remember earlier we said that you can store any data you want (for the most part). So my person object above is completely arbitrary. I could have used firstName and lastName instead of just name. I could have used a gender property. You get the idea. The second argument is the key used to uniquely identify the data. In this case we’ve hard coded it to 1 which is going to cause a problem pretty quickly. That’s ok – we’ll learn how to correct it.

The add operation is ascynchronous, so lets add two event handlers for the result.

request.onerror = function(e) {
console.log("Error",e.target.error.name);
//some type of error handler
}

request.onsuccess = function(e) {
console.log("Woot! Did it");
}

We’ve got an onerror handler for errors and onsuccess for good changes. Fairly obvious, but let’s see a complete example. You can find this in the file test6.html.

>

<!doctype html>
<html>
<head>
</head>

<body>

<script>
var db;

function indexedDBOk() {
return "indexedDB" in window;
}

document.addEventListener("DOMContentLoaded", function() {

//No support? Go in the corner and pout.
if(!indexedDBOk) return;

var openRequest = indexedDB.open("idarticle_people",1);

openRequest.onupgradeneeded = function(e) {
var thisDB = e.target.result;

if(!thisDB.objectStoreNames.contains("people")) {
thisDB.createObjectStore("people");
}
}

openRequest.onsuccess = function(e) {
console.log("running onsuccess");

db = e.target.result;

//Listen for add clicks
document.querySelector("#addButton").addEventListener("click", addPerson, false);
}

openRequest.onerror = function(e) {
//Do something for the error
}

},false);

function addPerson(e) {
var name = document.querySelector("#name").value;
var email = document.querySelector("#email").value;

console.log("About to add "+name+"/"+email);

var transaction = db.transaction(["people"],"readwrite");
var store = transaction.objectStore("people");

//Define a person
var person = {
name:name,
email:email,
created:new Date()
}

//Perform the add
var request = store.add(person,1);

request.onerror = function(e) {
console.log("Error",e.target.error.name);
//some type of error handler
}

request.onsuccess = function(e) {
console.log("Woot! Did it");
}
}
</script>

<input type="text" id="name" placeholder="Name"><br/>
<input type="email" id="email" placeholder="Email"><br/>
<button id="addButton">Add Data</button>

</body>
</html>

The example above contains a small form with a button to fire off an event to store the data in IndexedDB. Run this in your browser, add something to the form fields, and click add. If you’ve got your browser dev tools open, you should see something like this.

This is a great time to point out that Chrome has an excellent viewer for IndexedDB data. If you click on the Resources tab, expand the IndexedDB section, you can see the database created by this demo as well as the object just entered.

For the heck of it, go ahead and hit that Add Data button again. You should see an error in the console:

The error message should be a clue. ConstraintError means we just tried to add data with the same key as one that already existed. If you remember, we hard coded that key and we knew that was going to be a problem. It’s time to talk keys.

Keys

Keys are IndexedDB’s version of primary keys. Traditional databases can have tables without keys, but every object store needs to have a key. IndexedDB allows for a couple different types of keys.

The first option is to simply specify it yourself, like we did above. We could use logic to generate unique keys.

Your second option is a keypath, where the key is based on a property of the data itself. Consider our people example – we could use an email address as a key.

Your third option, and in my opinion, the simplest, is to use a key generator. This works much like an autonumber primary key and is the simplest method of specifying keys.

Keys are defined when object stores are created. Here are two examples – one using a key path and one a generator.

thisDb.createObjectStore("test", { keyPath: "email" });
thisDb.createObjectStore("test2", { autoIncrement: true });

We can modify our previous demo by creating an object store with an autoIncrement key:

thisDB.createObjectStore("people", {autoIncrement:true});

Finally, we can take the Add call we used before and remove the hard coded key:

var request = store.add(person);

That’s it! Now you can add data all day long. You can find this version in test7.html.

Reading Data

Now let’s switch to reading individual pieces of data (we’ll cover reading larger sets of data later). Once again, this will be done in a transaction and will be asynchronous. Here’s a simple example:

var transaction = db.transaction(["test"], "readonly");
var objectStore = transaction.objectStore("test");

//x is some value
var ob = objectStore.get(x);

ob.onsuccess = function(e) {

}

Note that the transaction is read only. The API call is just a simple get call with the key passed in. As a quick aside, if you think using IndexedDB is a bit verbose, note you can chain many of those calls as well. Here’s the exact same code written much tighter:

db.transaction(["test"], "readonly").objectStore("test").get(X).onsuccess = function(e) {}

Personally I still find IndexedDB a bit complex so I prefer the ‘broken out’ approach to help me keep track of what’s going on.

The result of the get’s onsuccess handler is the object you stored before. Once you have that object you can do whatever you want. In our next demo (test8.html) we’ve added a simple form field to let you enter a key and print the result. Here is an example:

The handler for the Get Data button is below:

function getPerson(e) {
var key = document.querySelector("#key").value;
if(key === "" || isNaN(key)) return;

var transaction = db.transaction(["people"],"readonly");
var store = transaction.objectStore("people");

var request = store.get(Number(key));

request.onsuccess = function(e) {

var result = e.target.result;
console.dir(result);
if(result) {
var s = "&lt;h2>Key "+key+"&lt;/h2>&lt;p>";
for(var field in result) {
s+= field+"="+result[field]+"&lt;br/>";
}
document.querySelector("#status").innerHTML = s;
} else {
document.querySelector("#status").innerHTML = "&lt;h2>No match&lt;/h2>";
}
}
}

For the most part, this should be self explanatory. Get the value from the field and run a get call on the object store obtained from a transaction. Notice that the display code simply gets all the fields and dumps them out. In a real application you would (hopefully) know what your data contains and work with specific fields.

Reading More Data

So that’s how you would get one piece of data. How about a lot of data? IndexedDB has support for what’s called a cursor. A cursor lets you iterate over data. You can create cursors with an optional range (a basic filter) and a direction.

As an example, the following code block opens a cursor to fetch all the data from an object store. Like everything else we’ve done with data this is asynchronous and in a transaction.

var transaction = db.transaction(["test"], "readonly");
var objectStore = transaction.objectStore("test");

var cursor = objectStore.openCursor();

cursor.onsuccess = function(e) {
var res = e.target.result;
if(res) {
console.log("Key", res.key);
console.dir("Data", res.value);
res.continue();
}
}

The success handler is passed a result object (the variable res above). It contains the key, the object for the data (in the value key above), and a continue method that is used to iterate to the next piece of data.

In the following function, we’ve used a cursor to iterate over all of the objectstore data. Since we’re working with “person” data we’ve called this getPeople:

function getPeople(e) {

var s = "";

db.transaction(["people"], "readonly").objectStore("people").openCursor().onsuccess = function(e) {
var cursor = e.target.result;
if(cursor) {
s += "&lt;h2>Key "+cursor.key+"&lt;/h2>&lt;p>";
for(var field in cursor.value) {
s+= field+"="+cursor.value[field]+"&lt;br/>";
}
s+="&lt;/p>";
cursor.continue();
}
document.querySelector("#status2").innerHTML = s;
}
}

You can see a full demo of this in your download as file test9.html. It has an Add Person logic as in the earlier examples, so simply create a few people and then hit the button to display all the data.

So now you know how to get one piece of data as well as how to get all the data. Let’s now hit our final topic – working with indexes.

They Call This IndexedDB, Right?

We’ve been talking about IndexedDB for the entire article but haven’t yet actually done any – well – indexes. Indexes are a crucial part of IndexedDB object stores. They provide a way to fetch data based on their value as well as specifying if a value should be unique within a store. Later we’ll demonstrate how to use indexes to get a range of data.

First – how do you create an index? Like everything else structural, they must be done in an upgrade event, basically at the same time you create your object store. Here is an example:

var objectStore = thisDb.createObjectStore("people",
{ autoIncrement:true });
//first arg is name of index, second is the path (col);
objectStore.createIndex("name","name", {unique:false});
objectStore.createIndex("email","email", {unique:true});

In the first line we create the store. We take that result (an objectStore object) and run the createIndex method. The first argument is the name for the index and the second is the property that will be indexed. In most cases I think you will use the same name for both. The final argument is a set of options. For now, we’re just using one, unique. The first index for name is not unique. The second one for email is. When we store data, IndexedDB will check these indexes and ensure that the email property is unique. It will also do some data handling on the back end to ensure we can fetch data by these indexes.

How does that work? Once you fetch an object store via a transaction, you can then ask for an index from that store. Using the code above, here is an example of that:

var transaction = db.transaction(["people"],"readonly");
var store = transaction.objectStore("people");
var index = store.index("name");

//name is some value
var request = index.get(name);

First we get the transaction, followed by the store, and then index. As we’ve said before, you could chain those first three lines to make it a bit more compact if you want.

Once you’ve got an index you can then perform a get call on it to fetch data by name. We could do something similar for email as well. The result of that call is yet another asynchronous object you can bind an onsuccess handler to. Here is an example of that handler found in the file test10.html:

request.onsuccess = function(e) {

var result = e.target.result;
if(result) {
var s = "&lt;h2>Name "+name+"&lt;/h2>&lt;p>";
for(var field in result) {
s+= field+"="+result[field]+"&lt;br/>";
}
document.querySelector("#status").innerHTML = s;
} else {
document.querySelector("#status").innerHTML = "&lt;h2>No match&lt;/h2>";
}
}

Note that an index get call may return multiple objects. Since our name is not unique we should probably modify the code to handle that, but it isn’t required.

Now let’s kick it up a notch. You’ve seen using the get API on the index to get a value based on that property. What if you want to get a more broad set of data? The final term we’re going to learn today are Ranges. Ranges are a way to select a subset of an index. For example, given an index on a name property, we can use a range to find names that begin with A up to names that begin with C. Ranges come in a few different varieties. They can be “everything below some marker”, “everything above some marker”, and “something between a lower marker and a higher marker.” Finally, just to make things interesting, ranges can be inclusive or exclusive. Basically that means for a range going from A-C, we can specify if we want to include A and C in the range or just the values between them. Finally, you can also request both ascending and descending ranges.

Ranges are created using a toplevel object called IDBKeyRange. It has three methods of interest: lowerBound, upperBound, and bound. lowerBound is used to create a range that starts at a lower value and returns all data “above” it. upperBound is the opposite. And – finally – bound is used to support a set of data with both a lower and upper bound. Let’s look at some examples:

//Values over 39
var oldRange = IDBKeyRange.lowerBound(39);

//Values 40a dn over
var oldRange2 = IDBKeyRange.lowerBound(40,true);

//39 and smaller...
var youngRange = IDBKeyRange.upperBound(40);

//39 and smaller...
var youngRange2 = IDBKeyRange.upperBound(39,true);

//not young or old... you can also specify inclusive/exclusive
var okRange = IDBKeyRange.bound(20,40)

Once you have a range, you can pass it to an index’s openCursor method. This gives you an iterator to loop over the values that match that range. As a practical manner, this isn’t really a search per se. You can use this to search content based on the beginning of a string, but not the middle or end. Let’s look at a full example. First we’ll create a simple form to search people:

Starting with: <input type="text" id="nameSearch" placeholder="Name"><br/>
Ending with: <input type="text" id="nameSearchEnd" placeholder="Name"><br/>
<button id="getButton">Get By Name Range</button>

We’re going to allow for searches that consist of any of the three types of ranges (again, a value and higher, a highest value, or the values within two inputs). Now let’s look at the event handler for this form.

function getPeople(e) {
var name = document.querySelector("#nameSearch").value;

var endname = document.querySelector("#nameSearchEnd").value;

if(name == "" &amp;&amp; endname == "") return;

var transaction = db.transaction(["people"],"readonly");
var store = transaction.objectStore("people");
var index = store.index("name");

//Make the range depending on what type we are doing
var range;
if(name != "" &amp;&amp; endname != "") {
range = IDBKeyRange.bound(name, endname);
} else if(name == "") {
range = IDBKeyRange.upperBound(endname);
} else {
range = IDBKeyRange.lowerBound(name);
}

var s = "";

index.openCursor(range).onsuccess = function(e) {
var cursor = e.target.result;
if(cursor) {
s += "&lt;h2>Key "+cursor.key+"&lt;/h2>&lt;p>";
for(var field in cursor.value) {
s+= field+"="+cursor.value[field]+"&lt;br/>";
}
s+="&lt;/p>";
cursor.continue();
}
document.querySelector("#status").innerHTML = s;
}

}

From top to bottom – we begin by grabbing the two form fields. Next we create a transaction and from that get the store and index. Now for the semi-complex part. Since we have three different types of ranges we need to support we have to do a bit of conditional logic to figure out which we’ll need. What range we create is based on what fields you fill in. What’s nice is that once we have the range, we then simply pass it to the index and open the cursor. That’s it! You can find this full example in test11.html. Be sure to enter some values first so you have data to search.

What’s Next?

Believe it or not – we’ve only begun our discussion on IndexedDB. In the next article, we’ll cover additional topics, including updates and deletes, array based values, and some general tips for working with IndexedDB.

原文链接：http://net.tutsplus.com/tutorials/javascript-ajax/working-with-indexeddb/ （本内容由互联网资料整理而成）

字符编码的前世今生

由于“字符编码”这个话题牵涉到的历史久远、机构众多、专业术语较多，所以本篇文章可能会略长，为了避免内容过于枯燥，我会尽量用一种通俗易懂的语言来写这篇文章。
其中本文的第一篇章会对历史中的主要字符编码进行介绍，由于篇幅较长，如果读者对此已很了解，可直接跳过进行第二章的阅读。
完成本篇文章的过程中参考和阅读了大量的文章和文献，写本篇文章的目的一是让自己对“字符编码”能够做一个较深的理解，二是希望给曾经徘徊或正在徘徊在编码困惑中的前端们一个很好的参考，搞清楚字符编码问题是前端万事之基石。
由于本人才疏学浅，好多信息也是从网络和书籍中参考而来，错误之处难免，请大家指正。
------------------题记

跟随历史的足迹看字符编码

古代的通信方式

很久很久以前，人们之间的长途通讯主要是用信鸽、骑马送报、烽烟等方式进行：

世界第一条电报

直到1837年，世界第一条电报诞生，当时美国科学家莫尔斯尝试用一些“点”和“划”来表示不同的字母、数字和标点符号，这套表示字符的方式也被称为“摩尔斯电码”：

世界第一台计算机

再后来到了1946年，世界第一台计算机诞生。发明计算机的同学们用8个晶体管的“通”或“断”组合出一些状态来表示世间万物，不过当时的计算机有一间半教室那么大，六头大象重，从现在看来这简直就是个怪物，但在当时却是震惊世界与改变世界的一项重要发明：

ASCII

8个晶体管的“通”或“断”即可以代表一个字节，刚开始，计算机只在美国使用，所有的信息在计算机最底层都是以二进制（“0”或“1”两种不同的状态）的方式存储，而8位的字节一共可以组合出256（2的8次方）种状态，即256个字符，这对于当时的美国已经是足够的了，他们尝试把一些终端的动作、字母、数字和符号用8位(bit)来组合：

- 0000 0000 ~ 0001 1111 共 33 种状态用来表示终端的特殊动作，如打印机中的响铃为 0000 0111 ，当打印机遇到 0000 0111 这样的字节传过来时，打印机就开始响铃；

- 0010 0000 ~ 0010 1111 、 0011 1010~0110 0000 和 0111 1101 ~ 0111 1110 共 33 种状态来表示英式标点符号，如 0011 1111 即代表英式问号“?”；

- 0011 0000 ~ 0011 1001 共 10 种状态来表示“0~9”10个阿拉伯数字；

- 0100 0001 ~ 0101 1010 和 0110 0001 ~ 0111 1010共 52种状态来表示大小写英文字母；

自此，一共只用到了128种状态，即128个字符，刚好占用了一个字节中的后7位，共包括33个控制字符和95个可显示字符，这一字符集被称为ASCII（American Standard Code for Information Interchange，美国信息交换标准代码），这一套字符集在1967年被正式公布。

讲到这里，引出几个基础概念：

- 比特（bit）：也可称为“位”，是计算机信息中的最小单位，是 binary digit（二进制数位） 的 缩写，指二进制中的一位

- 字节（Byte）：计算机中信息计量的一种单位，一个位就代表“0”或“1”，每8个位（bit）组成一个字节（Byte）

- 字符（Character）：文字与符号的总称，可以是各个国家的文字、标点符号、图形符号、数字等

- 字符集（Character Set）：是多个字符的集合

- 编码（Encoding）： 信息从一种形式或格式转换为另一种形式的过程

- 解码（decoding）： 编码的逆过程

- 字符编码（Character Encoding）： 按照何种规则存储字符

现在我们来看我们文章开头提到的第一条电报的诞生，莫尔斯编码中包含了大小写英文字母和数字等符号。

- 这里的每一个符号其实就是⌈字符⌋，

- 而这所有的字符的集合就叫做⌈字符集⌋，

- “点”或“划”与字符之间的对应关系即可以称为⌈字符编码⌋。

而电报的原理是：

“点”对应于短的电脉冲信号，“划”对应于长的电脉冲信号，这些信号传到对方，接收机把短的电脉冲信号翻译成“点”，把长的电脉冲信号转换成“划”，译码员根据这些点划组合就可以译成英文字母，从而完成了通信任务。

- 这里把字符表示为“点”或“划”并对应为电脉冲信号的过程既是⌈编码⌋，

- 而译码员把接收机接收到的脉冲信号转化成点划后译成字符的过程即为⌈解码⌋。

而对于计算机诞生之后，只不过是将摩斯电码中的“点”和“划”换成了以8位字节二进制流的方式表示，如数字1的二进制流是0011 0001，对应的十进制流是49，十六进制流是31。

EASCII

虽然刚开始计算机只在美国使用，128个字符的确是足够了，但随着科技惊人的发展，欧洲国家也开始使用上计算机了。不过128个字符明显不够呀，比如法语中，字母上方有注音符号，于是，一些欧洲国家就决定，利用字节中闲置的最高位编入新的符号。比如，法语的é的二进制流为1000 0010，这样一来，这些欧洲国家的编码体系，可以表示最多256个字符了。 但是，这里又出现了新的问题。不同的国家有不同的字母，因此，哪怕它们都使用256个符号的编码方式，代表的字母却不一样。比如，1000 0010在法语编码中代表了é，在希伯来语编码中却代表了字母Gimel (?)，在俄语编码中又会代表另一个符号。但是不管怎样，所有这些编码方式中，0--127表示的符号是一样的，不一样的只是128--255的这一段。 EASCII（Extended ASCII，延伸美国标准信息交换码）由此应运而生，EASCII码比ASCII码扩充出来的符号包括表格符号、计算符号、希腊字母和特殊的拉丁符号:

GB2312

EASCII码对于部分欧洲国家基本够用了，但过后的不久，计算机便来到了中国，要知道汉字是世界上包含符号最多并且也是最难学的文字。 据不完全统计，汉字共包含了古文、现代文字等近10万个文字，就是我们现在日常用的汉字也有几千个，那么对于只包含256个字符的EASCII码也难以满足天朝的需求了。 于是⌈中国国家标准总局⌋（现已更名为⌈国家标准化管理委员会⌋）在1981年，正式制订了中华人民共和国国家标准简体中文字符集，全称《信息交换用汉字编码字符集·基本集》，项目代号为GB 2312 或 GB 2312-80（GB为国标汉语拼音的首字母），此套字符集于当年的5月1日起正式实施。

包含字符：

共包含7445个字符，6763个汉字和682个其他字符（拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母）

存储方式：

基于EUC存储方式，每个汉字及符号以两个字节来表示，第一个字节为“高位字节”，第二个字节为“低位字节”

BIG5

要知道港澳台同胞使用的是繁体字，而中国大陆制定的GB2312编码并不包含繁体字，于是信息工业策进会在1984年与台湾13家厂商签定“16位个人电脑套装软件合作开发（BIG-5）计划”，并开始编写并推出BIG5标准。 之后推出的倚天中文系统则基于BIG5码，并在台湾地区取得了巨大的成功。在BIG5诞生后，大部分的电脑软件都使用了Big5码，BIG5对于以台湾为核心的亚洲繁体汉字圈产生了久远的影响，以至于后来的window 繁体中文版系统在台湾地区也基于BIG5码进行开发。

包含字符：

共收录13,060个汉字及441个符号

编码方式：

用两个字节来为每个字符编码，第一个字节称为“高位字节”，第二个字节称为“低位字节”

Unicode

由来：

在计算机进入中国大陆的相同时期，计算机也迅速发展进入了世界各个国家。 特别是对于亚洲国家而言，每个国家都有自己的文字，于是每个国家或地区都像中国大陆这样去制定了自己的编码标准，以便能在计算机上正确显示自己国家的符号。 但带来的结果就是国家之间谁也不懂别人的编码，谁也不支持别人的编码，连大陆和台湾这样只相隔了150海里，都使用了不同的编码体系。 于是，世界相关组织意识到了这个问题，并开始尝试制定统一的编码标准，以便能够收纳世界所有国家的文字符号。 在前期有两个尝试这一工作的组织：

国际标准化组织（ISO）及国际电工委员会（IEC）于1984年联合成立了ISO/IEC小组，主要用于开发统一编码项目； 而Xerox、Apple等软件制造商则于1988年组成了统一码联盟，用于开发统一码项目。 两个组织都在编写统一字符集，但后来他们发现各自在做相同的工作，同时世界上也不需要两个不兼容的字符集，于是两个组织就此合并了双方的工作成果，并为创立一个单一编码表而协同工作。

1991年，两个组织共同的工作成果Unicode 1.0正式发布，不过Unicode 1.0并不包含CJK字符（即中日韩）。

- Unicode 1.0：1991年10月

- Unicode 1.0.1：1992年6月

- Unicode 1.1：1993年6月

- Unicode 2.0：1997年7月

- Unicode 2.1：1998年5月

- Unicode 2.1.2：1998年5月

- Unicode 3.0：1999年9月

- Unicode 3.1：2001年3月

- Unicode 3.2：2002年3月

- Unicode 4.0：2003年4月

- Unicode 4.0.1：2004年3月

- Unicode 4.1：2005年3月

- Unicode 5.0：2006年7月

- Unicode 5.1：2008年4月

- Unicode 5.2：2009年10月

- Unicode 6.0：2010年10月

- Unicode 4.1：2005年3月

- Unicode 6.1：2012年1月31日

- Unicode 6.2：2012年9月

ISO/IEC 8859

ISO/IEC小组在1984年成立后的第三年（即1987年）开始启动ISO 8859标准的编写，ISO 8859是一系列8位字符集的标准，主要为世界各地的不同语言（除CJK）而单独编写的字符集，一共定义了15个字符集：

- ISO/IEC 8859-1：西欧语言

- ISO/IEC 8859-2  ：中欧语言

- ISO/IEC 8859-3 ：南欧语言

- ISO/IEC 8859-4： 北欧语言

- ISO/IEC 8859-5： 斯拉夫语

- ISO/IEC 8859-6： 阿拉伯语

- ISO/IEC 8859-7：希腊语

- ISO/IEC 8859-8：希伯来语

- ISO/IEC 8859-9：土耳其语

- ISO/IEC 8859-10： 北日耳曼语

- ISO/IEC 8859-11：泰语

- ISO/IEC 8859-13： 波罗的语族

- ISO/IEC 8859-14： 凯尔特语族

- ISO/IEC 8859-15：西欧语言，收录芬兰语字母和大写法语重音字母，以及欧元（€）符号

- ISO/IEC 8859-16 ：东南欧语言，主要供罗马尼亚语使用，并加入欧元（€）符号

其中ISO/IEC 8859-1至ISO/IEC 8859-4四个项目早在1982年就已经编写出来，只不过是由ANSI与ECMA合作完成，并于1985年正式公布，ISO/IEC小组成立后，这一成果被其收录，并改名为ISO/IEC 8859 前四个项目。 大家其实发现以上15个字符集中并没有代号为“ISO/IEC 8859 -12”的字符集，据说-12号本来是预留给印度天城体梵文的，但后来却搁置了（阿三有了自己的编码－ISCII）。由于英语没有任何重音字母，故可使用以上十五个字符集中的任何一个来表示。

ISO/IEC 10646 / UCS

1993年，ISO/IEC 10646标准第一次发表，ISO/IEC 10646是ISO 646的扩展，定义了1个31位的字符集。ISO 10646标准中定义的字符集为UCS，UCS是Universal Character Set的缩写，中文译作通用字符集。

版本：

- ISO/IEC 10646-1：第一次发表于1993年，现在的公开版本是2000年发表的ISO/IEC 10646-1:2000。

- ISO/IEC 10646-2：在2001年发表。

包含字符：

最初的ISO 10646-1:1993的编码标准，即Unicode 1.1，收录中国大陆、台湾、日本及韩国通用字符集的汉字共计20,902个，当然每个版本的Unicode标准的字符集所包含的字符数不尽相同，UCS包含了已知语言的所有字符，除了拉丁语、希腊语、斯拉夫语、希伯来语、阿拉伯语、亚美尼亚语、格鲁吉亚语，还包括中文、日文、韩文这样的方块文字，此外还包括了大量的图形、印刷、数学、科学符号。 UCS给每个字符分配一个唯一的代码，并且赋予了一个正式的名字，通常在表示一个Unicode值的十六进制数的前面加上“U+”，例如“U+0041”代表字符“A”。

编码方案：

UCS仅仅是一个超大的字符集，关于UCS制定的编码方案有两种：UCS-2和UCS-4，Unicode默认以UCS-2编码。 顾名思义，UCS-2就是用两个字节编码，UCS-4就是用4个字节（实际上只用了31位，最高位必须为0）编码。那么UCS-2其实可以容纳的字符数为65536（2的16次方），而UCS-4可以容纳的字符数为2147483648（2的31次方）。其实对于UCS-2已经是完全够用了，基本可以包含世界所有国家的常用文字，如果需要考虑一些偏僻字，那么UCS-4则绝对可以满足了，21亿个字符哪怕是整个宇宙也够用了吧！

UTF

Unicode 诞生，随之而来的计算机网络也发展了起来，Unicode 如何在网络上传输也是一个必须考虑的问题，于是在1992年，面向网络传输的UTF标准出现了。 UTF是Unicode Transformation Format的缩写，中文译作Unicode转换格式。其实我们从现在可以把Unicode看作是一个标准或组织，而UCS就是一个字符集，那么UCS在网络中的传输标准就是UTF了。 前面提到了UCS的编码实现方式为UCS-2和UCS-4，即要么是每个字符为2个字节，要么是4个字节。如果一个仅包含基本7位ASCII字符的Unicode文件，每个字符都使用2字节的原Unicode编码传输，其第一字节的8位始终为0，这就造成了比较大的浪费。但是，聪明的人们发明了UTF-8，UTF-8采用可变字节编码，这样可以大大节省带宽，并增加网络传输效率。

UTF-8

使用1~4个字节为每个UCS中的字符编码：

- 128个ASCII字符只需一个字节编码（Unicode范围由U+0000至U+007F）

- 拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母需要二个字节编码（Unicode范围由U+0080至U+07FF）

- 大部分国家的常用字（包括中文）使用三个字节编码

- 其他极少使用的生僻字符使用四字节编码

UTF-16/UCS-2

UCS-2的父集，使用2个或4个字节来为每个UCS中的字符编码：

- 128个ASCII字符需两个字节编码

- 其他字符使用四个字节编码

UTF-32/UCS-4

等同于UCS-4，对于所有字符都使用四个字节来编码

GB13000

前面提到了Unicode的迅速发展，至1993年时，包含CJK的Unicode 1.1已经发布了，天朝的ZF也意识到了需要一个更大的字符集来走向世界，于是在同一年，中国大陆制定了几乎等同于Unicode1.1的GB13000.1-93国家编码标准（简称GB13000）。是的，你没听错，中华人民共和国信息产业部把Unicode里的所有东东拿过来，然后自己重新修订发布了下，改为了国家标准GB13000。此标准等同于 ISO/IEC 10646.1:1993和Unicode 1.1。

GBK

1995年，在GB13000诞生后不久，中国教育科研网（NCFC）与美国NCFnet直接联网，这一天是中国被国际承认为开始有网际网路的时间。此后网络正式开始在中国大陆接通，个人计算机开始在中国流行，虽然当时只是高富帅才消费得起的产品。中国是一个十几亿人口的大国，微软意识到了中国是一个巨大的市场，当时的微软也将自己的操作系统市场布局进中国，进入中国随之而来要解决的就是系统的编码兼容问题。 之前的国家编码标准GB 2312，基本满足了汉字的计算机处理需要，它所收录的汉字已经覆盖中国大陆99.75%的使用频率。但对于人名、古汉语等方面出现的罕用字和繁体字，GB 2312不能处理，因此微软利用了GB2312中未使用的编码空间，收录了GB13000中的所有字符制定了汉字内码扩展规范GBK（K为汉语拼音 Kuo Zhan中“扩”字的首字母）。所以这一关系其实是大陆把Unicode1.1借鉴过来改名为了GB13000，而微软则利用GB2312中未使用的编码空间收录GB13000制定了GBK。所以GBK是向下完全兼容GB2312的。

包含字符：

共收录21886个字符， 其中汉字21003个， 字符883个

编码方式：

GBK只不过是把GB2312中未使用的空间，编码了其他字符，所以GBK同样是用两个字节为每个字符进行编码。

GB18030

微软到了99年前后，说GBK已经落伍了，现在流行UTF-8标准，准备全盘转换成UTF-8，但中国ZF不是吃素的，编写并强制推出了GB18030标准。GB18030的诞生还有一个原因是GBK只包含了大部分的汉字和繁体字等，我们的少数民族兄弟根本木有考虑！中国有56个民族，其中有12个民族有自己的文字，那怎么办呢？在2000年，电子工业标准化研究所起草了GB18030标准，项目代号“GB 18030-2000”，全称《信息技术-信息交换用汉字编码字符集-基本集的扩充》。此标准推出后，在中国大陆之后的所售产品必须强制支持GB18030标准，不然不得卖！（这招挺狠的 - -#）

版本：

- GB 18030-2000

- GB 18030-2005

包含字符：

GB18030收录了GBK中的所有字符，并将Unicode中其他中文字符（少数民族文字、偏僻字）也一并收录进来重新编码。其中GB 18030-2000共收录27533个汉字，而GB 18030-2005共包含70244个汉字。

编码方式：

采用多字节编码，每个字符由1或2或4个字节进行编码

前端眼中的字符编码

前面我们穿越回过去对字符编码做了下了解，那么这些字符编码跟我们到底有啥关系？

基本原理：

当我们打开编辑器coding时，按下ctrl+s的那一刻，其实等于是将自己的工作成果存储进了计算机，而这里最关键的是我们以什么字符编码来进行存储，我们以intellij编辑器为例：

我们在编写此文档时，是以UTF-8编码方式进行coding，当我们按下ctrl+s时，则此文档以utf-8编码方式存储进了计算机（右下角的UTF-8），而head区域中的<meat charset="utf-8">的作用则是告诉浏览器此文档以utf-8编码方式编码。 我们此时用Hex编辑器打开这个文件，来看看他的二进制流：

其中红框标注出的即为“小海”两个中文字的二进制流，第一个为"11100101 10110000 10001111"转化为十六进制则为“E5B08F”，第二个为“10110101 10110111 00001101”转化为十六进制为“E6B5B7”，而当我们去查询UTF-8的码表时发现“E5B08F”对应的字符为“小”，“E6B5B7”对应的字符则为“海”，至此当我们用浏览器进行预览页面时，由于浏览器同样以UTF-8方式对此页面进行解码，“小海”两个字则可以被正确的显示出来。

乱码是个XX

做过前端的基本都遇到过乱码问题吧？好吧，下面就带大家来揭开这一神秘的面纱。

我们用notepad打开上面的文件，并重新以GBK方式编码，然后用intellij打开后：

乱了有木有！居然变成了“C??”，木有道理呀！我在用notepad编辑文件时采用的是gbk编码，而头部申明的也是gbk，本身notepad打开也是正常，但用intellij打开却乱了！

罪魁祸首：编辑器默认编码。每个编辑器都会有默认编码，如果没有为一个项目单独设置过默认编码，打开一个单独的文件，编辑器往往以自己的默认编码去解码这个文件，如上图，我们的inellij编辑器的默认是UTF-8解码，而文件是GBK编码方式，那么打开肯定就是乱的拉。

所以编辑器也是一个因素，DW则可以智能判断文件的编码方式，上述文件用DW打开并不会乱码，而intellij可能对中文的支持并不是很好，所以还不能智能判断中文编码，默认以UTF-8解码（当然默认编码自己是可以修改的）。

很多读者可能还有一个疑问，为啥乱码出来的是“C??”？ 其实原理已在上面的基本原理中做过介绍，即编辑器ctrl+s存进计算机时是GBK，但尝试用utf-8来解析，对应的utf-8中的码表中却找到了“C??”，感兴趣的同学可以自己研究下。

我们现在将文件重新编辑，即编辑时采用GBK，但头部申明为UTF-8：

然后用浏览器打开后，就是这样了：

乱了有木有！这个其实和编辑器打开一个文件乱码的原理是一致的：即编辑器编码时所采用的字符编码和解码时所采用的字符编码不一致。上述栗子，我们在coding时采用的是GBK编码，但头部却告诉浏览器这个文档是UTF-8编码，那么浏览器在用UTF-8解码时就会出现了乱码。

申明编码的方式

我们在coding时需要告诉浏览器自己的文件采用了什么字符编码，下面列出一些常见的方法：

<meta charset="gb2312"> //html5

<meta http-equiv="Content-Type" content="text/html; charset=gb2312"> //html4 xhtml

<script src="http://ossweb-img.qq.com/images/js/foot.js" charset="gb2312"></script>

<link href="http://gameweb-img.qq.com/css/common.css" rel="stylesheet" charset="gb2312" >

我们可以在head区域的meta元素中为整个页面申明编码方式，也可以为单独的外链文件申明编码方式（link/script等元素）。问题是如果页面头部和外链文件中只有部分申明或者全部申明，那么对应的到底是以什么方式解码呢？这里就有一个优先级的问题，具体的判定关系如下：

通过上述判定，我们其实可以发现，一个页面中优先级最高的其实是服务端的编码设置，如果一旦服务端设置了编码A，那么页面即以A来解析。 目前Google采用的是这一做法，这样的传输效率会更高，不需要在头部额外再单独申明编码，但这样其实也有一定的风险，除了需要有一个严谨的编码规范，还需要确保服务器上的页面都保持同一编码，一旦不一致就会造成乱码，所以目前这一方案在国内用的并不多。 其他的，如果外链资源设置了编码C，那么即以C来解析，无论服务端和头部是否申明编码。 但必须要提醒大家的是：申明的编码只是告诉浏览器相关的内容是以什么方案去解码，并不是这一部分内容就采用了这个编码。所以大家在coding时的编码一定要确保和你申明的保持统一，不然就会出现乱码的问题。

BOM是个神马

BOM是byte-order mark的缩写，为Unicode标准为了用来区分一个文件是UTF-8还是UTF-16或UTF-32编码方式的记号，又称字节序。

UTF-8以单字节为编码单元，并没有字节序的问题，而UTF-16以两个字节为编码单元，在解释一个UTF-16文本前，首先要弄清楚每个编码单元的字节序。例如“奎”的Unicode编码是594E，“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”，那么这是“奎”还是“乙”？这是UTF-16文件开头的BOM就有作用了。

采用Unicode编码方式的文件如果开头出现了“FEFF”，“FEFF”在UCS中是不存在的字符，也叫做“ZERO WIDTH NO-BREAK SPACE”，那么就表明这个文件的字节流是Big-Endian（高字节在前）的；如果收到“FFFE”，就表明字节流是Little-Endian（低字节在前）。

在UTF-8文件中放置BOM主要是微软的习惯，BOM其实是为UTF-16和UTF-32准备的，微软在UTF-8使用BOM是因为这样可以把UTF-8和ASCII等编码明确区分开，但这样的文件在Window以外的其他操作系统里会带来问题。

我们以Window下的文本文件为例：

在保存时可以选择ANSI、Unicode、Unicode big endian和UTF-8四种编码方式。

- 其中ANSI是默认的编码方式，对于英文文件是ASCII编码，对于简体中文文件是GB2312编码（只针对Windows简体中文版，如果是繁体中文版会采用Big5码）；

- Unicode其实是UTF-16 endian big编码方式，这个把带有BOM的小端序UTF-16称作Unicode而又不详细说明，也是微软的习惯；

- 而Unicode big endian则是带有BOM的大端序编码方式

目前UTF-16通常用于系统文件的编码，而UTF-32由于对每个字符都采用四个字节编码，所以现在互联网中大部分都采用UTF-8来进行编码传输。

关于未来的展望

概述

（左图：中国地区ALEXA排名前20的站点所采用的编码占比）                  （右图：腾讯互娱所有业务所采用的编码占比）

左图表明GB2312、GBK与UTF-8编码三分天下，而右图显示腾讯互娱的业务大多数采用了GB2312，零星的采用了其他编码。总的就是不同的字符编码方案基本都存在了，而这也与各公司业务的历史原因也有一定的关系。 当我们在项目的最初期时采用了一种非Unicode编码方案时，随着业务的壮大，积累的页面越来越多，到后期想去改成Unicode编码方案，就会担心出错的问题，所以现在大多数公司都采用了延用初期编码的方式，如淘宝，腾讯互娱等，以及四大门户。

摆在眼前的问题

可是，某一天了，我们的网站用户港澳台用户也变多了，我们需要支持繁体怎么办？

某一天，我们的业务拓展到东南亚了，我们需要我们的网站也能支持那些国家的语言怎么办？

如今，国内大多数公司采用的方案是，为相应的环境单独做一套编码文件，如 http://big5.china.com.cn/ ，又如 http://big5.qidian.com。

再比如，哪一天了，我们的网站需要支持少数民族的语言怎么办？

难道像某某企业这样切成图么？

嗯，这一切都只是暂时的方案，但人一旦变得懒起来，就不愿意去改变一些东西，就比如UTF-8。

拥抱国际化标准

一切就等着我们敞开胸怀去拥抱，而不是沉浸在过去的喜悦中。最终的编码方案决定权在我们自己手里，改变，只是时间的问题。

参考资源及文献列表：

http://zh.wikipedia.org/wiki/ISO_10646

http://zh.wikipedia.org/wiki/%E4%BD%8D%E5%85%83%E7%B5%84%E9%A0%86%E5%BA%8F%E8%A8%98%E8%99%9F

http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html http://www.imkevinyang.com/2010/06/%E5%85%B3%E4%BA%8E%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81%EF%BC%8C%E4%BD%A0%E6%89%80%E9%9C%80%E8%A6%81%E7%9F%A5%E9%81%93%E7%9A%84.html http://zh.wikipedia.org/wiki/Gb2312 http://zh.wikipedia.org/wiki/GBK http://zh.wikipedia.org/wiki/GB18030

http://www.unicode.org/

http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html

http://zh.wikipedia.org/wiki/Big5

原文链接：http://tgideas.qq.com/webplat/info/news_version3/804/808/811/m579/201307/218730.shtml （本内容由互联网资料整理而成）

针对长列表的AngularJS性能调优

摘要：AnglarJS是一款非常棒的Web框架，但其在处理包含复杂数据结构的大型列表时，会出现运行速度慢的情况。遇到此种情况，该如何解决？该文给出了7条AngularJS性能调优的建议。

AnglarJS作为一款优秀的Web框架，可大大简化前端开发的负担。近日Sebastian Fröstl在一篇博文《AngularJS Performance Tuning for Long Lists》中表示AnglarJS在处理包含复杂数据结构的大型列表时，其运行速度会非常慢。他在文中同时分享了解决方案。下面为该文的译文。

AnglarJS很棒，但当处理包含复杂数据结构的大型列表时，其运行速度就会非常慢。这是我们将核心管理页面迁移到AngularJS过程中遇到的问题。这些页面在显示500行数据时本应该工作顺畅，但首个方法的渲染时间竟花费了7秒，太可怕了。

后来，我们发现了在实现过程中存在两个主要性能问题。一个与“ng-repeat ”指令有关，另一个与过滤器有关。

下文将分享我们通过不同的方法解决性能问题的经验，希望可以给你带来启示。

AngularJS 中的ng-repeat在处理大型列表时，速度为什么会变慢？

AngularJS中的ng-repeat在处理2500个以上的双向数据绑定时速度会变慢。这是由于AngularJS通过“dirty checking”函数来检测变化。每次检测都会花费时间，所以包含复杂数据结构的大型列表将降低你应用的运行速度。

提高性能的先决条件

时间记录指令

为了测量一个列表渲染所花费的时间，我们写了一个简单的程序，通过使用“ng-repeat”的属性“$last”来记录时间。时间存放在TimeTracker服务中，这样时间记录就与服务器端的数据加载分开了。

// Post repeat directive for logging the rendering time
angular.module('siApp.services').directive('postRepeatDirective',
['$timeout', '$log',  'TimeTracker',
function($timeout, $log, TimeTracker) {
return function(scope, element, attrs) {
if (scope.$last){
$timeout(function(){
var timeFinishedLoadingList = TimeTracker.reviewListLoaded();
var ref = new Date(timeFinishedLoadingList);
var end = new Date();
$log.debug("## DOM rendering list took: " + (end - ref) + " ms");
});
}
};
}
]);

// Use in HTML:
<tr ng-repeat="item in items" post-repeat-directive>…</tr>

Chrome开发者工具的时间轴（Timeline）属性

在Chrome开发者工具的时间轴标签中，你可以看见事件、每秒内浏览器帧数和内存分配。“memory”工具用来检测内存泄漏，及页面所需的内存。当帧速率每秒低于30帧时就会出现页面闪烁问题。“frames”工具可帮助了解渲染性能，还可显示出一个JavaScript任务所花费的CPU时间。

通过限制列表的大小进行基本的调优

缓解该问题，最好的办法是限制所显示列表的大小。可通过分页、添加无限滚动条来实现。

分页，我们可以使用AngularJS的“limitTo”过滤器（AngularJS1.1.4版本以后）和“startFrom”过滤器。可以通过限制显示列表的大小来减少渲染时间。这是减少渲染时间最高效的方法。

// Pagination in controller
$scope.currentPage = 0;
$scope.pageSize = 75;
$scope.numberOfPages = function() {
return Math.ceil($scope.displayedItemsList.length/ $scope.pageSize);
};

// Start from filter
angular.module('app').filter('startFrom', function() {
return function(input, start) {
return input.slice(start);
};

// Use in HTML
// Pagination buttons
<button ng-repeat="i in getNumber(numberOfPages()) track by $index" ng-click="setCurrentPage($index)">{{$index + 1}}</button

// Displayed list
<tr ng-repeat="item in displayedItemsList | startFrom: currentPage * pageSize  | limitTo:pageSize" /tr>

如果你不能/不想使用分页，但过滤过程又很慢，这时一定要检查前五步，并使用“ng-show”隐藏掉多余的列表元素。

无限滚动条

如果你希望进一步了解该方法，可访问“ http://binarymuse.github.io/ngInfiniteScroll/”，

七大调优法则

1.渲染没有数据绑定的列表

这是最明显的解决方案，因为数据绑定是性能问题最可能的根源。如果你只想显示一次列表，并不需要更新、改变数据，放弃数据绑定是绝佳的办法。不过可惜的是，你会失去对数据的控制权，但除了该法，我们别无选择。进一步了解： https://github.com/Pasvaz/bindonce。

2.不要使用内联方法计算数据

为了在控制器中直接过滤列表，不要使用可获得过滤链接的方法。“ng-repeat”会评估每个 [$digest( http://docs.angularjs.org/api/ng.$rootScope.Scope#$digest)%5D表达式。在我们的案例中，“filteredItems()”返回过滤链接。如果评估过程很慢，它将迅速降低整个应用的速度。

<li ng-repeat="item in filteredItems()"> //这并不是一个好方法，因为要频繁地评估。
<li ng-repeat="item in items"> //这是要采用的方法

3.使用两个列表（一个用来进行视图显示，一个作为数据源）

将要显示的列表与总的数据列表分开，是非常有用的模型。你可以对一些过滤进行预处理，并将存于缓存中的链接应用到视图上。下面案例展示了基本实现过程。filteredLists变量保存着缓存中的链接，applyFilter方法来处理映射。

/* Controller */
// Basic list
var items = [{name:"John", active:true }, {name:"Adam"}, {name:"Chris"}, {name:"Heather"}];

// Init displayedList
$scope.displayedItems = items;

// Filter Cache
var filteredLists['active'] = $filter('filter)(items, {"active" : true});

// Apply the filter
$scope.applyFilter = function(type) {
if (filteredLists.hasOwnProperty(type){ // Check if filter is cached
$scope.displayedItems = filteredLists[type];
} else {
/* Non cached filtering */
}
}

// Reset filter
$scope.resetFilter = function() {
$scope.displayedItems = items;
}

/* View */
<button ng-click="applyFilter('active')">Select active</button>
<ul><li ng-repeat="item in displayedItems">{{item.name}}<li></ul>

4.在其他模板中使用ng-if来代替ng-show

如果你用指令、模板来渲染额外的信息，例如通过点击来显示列表项的详细信息，一定要使用  ng-if（AngularJSv. 1.1.5以后）。ng-if可阻止渲染（与ng-show相比）。所以其它DOM和数据绑定可根据需要进行评估。

<li ng-repeat="item in items">
<p> {{ item.title }} </p>
<button ng-click="item.showDetails = !item.showDetails">Show details</buttons>
<div ng-if="item.showDetails">
{{item.details}}
</div>
</li>

5.不要使用ng-mouseenter、ng-mouseleave等指令

使用内部指令，像ng-mouseenter，AngularJS会使你的页面闪烁。浏览器的帧速率通常低于每秒30帧。使用jQuery创建动画、鼠标悬浮效果可以解决该问题。确保将鼠标事件放入jQuery的.live()函数中。

6.关于过滤的小提示：通过ng-show隐藏多余的元素

对于长列表，使用过滤同样会减低工作效率，因为每个过滤都会创建一个原始列表的子链接。在很多情况下，数据没有变化，过滤结果也会保持不变。所以对数据列表进行预过滤，并根据情况将它应用到视图中，会大大节约处理时间。

在ng-repeat指令中使用过滤器，每个过滤器会返回一个原始链接的子集。AngularJS 从DOM中移除多余元素（通过调用 $destroy），同时也会从$scope中移除他们。当过滤器的输入发生改变时，子集也会随着变化，元素必须进行重新链接，或着再调用$destroy。

大部分情况下，这样做很好，但一旦用户经常过滤，或者列表非常巨大，不断的链接与销毁将影响性能。为了加快过滤的速度，你可以使用ng-show和ng-hide指令。在控制器中，进行过滤，并为每项添加一个属性。依靠该属性来触发ng-show。结果是，只为这些元素增加ng-hide类，来代替将它们移除子列表、$scope和DOM。

- 触发ng-show的方法之一是使用表达式语法。ng-show的值由表达式语法来确定。可以看下面的例子：

- <input ng-model="query"></input>
<li ng-repeat="item in items" ng-show="([item.name] | filter:query).length">{{item.name}}</li><span style="font-size: 14px; line-height: 24px; font-family: Helvetica, Tahoma, Arial, sans-serif; white-space: normal;"></span>

- 另一个方法是为ng-show传递一个属性，并在单独的子控制器进行计算。该方法稍有点复杂，但却是更明晰的方法。

7.关于过滤的小提示：防抖动输入

解决第6点提出的持续过滤问题的另一个方法是防抖动用户输入。例如，如果用户输入一个搜索关键词，只当用户停止输入后，过滤器才会被激活。使用该防抖动服务的一个很好的解决方案请见： http://jsfiddle.net/Warspawn/6K7Kd/。将它应用到你的视图及控制器中，如下所示。

/* Controller */
// Watch the queryInput and debounce the filtering by 350 ms.
$scope.$watch('queryInput', function(newValue, oldValue) {
if (newValue === oldValue) { return; }
$debounce(applyQuery, 350);
});
var applyQuery = function() {
$scope.filter.query = $scope.query;
};

/* View */
<input ng-model="queryInput"/>
<li ng-repeat= item in items | filter:filter.query>{{ item.title }} </li>

（编译：陈秋歌 审校：夏梦竹）

原文链接： AngularJS Performance Tuning for Long Lists

本文为CSDN编译整理，未经允许不得转载，如需转载请联系market#csdn.net(#换成@)

原文链接：http://www.csdn.net/article/2013-09-18/2816972-AngularJS-performance-tuning-for-long-list （本内容由互联网资料整理而成）

相似图片搜索的原理（二）

二年前，我写了《相似图片搜索的原理》，介绍了一种最简单的实现方法。

昨天，我在isnowfy的网站看到，还有其他两种方法也很简单，这里做一些笔记。

一、颜色分布法

每张图片都可以生成颜色分布的直方图（color histogram）。如果两张图片的直方图很接近，就可以认为它们很相似。

任何一种颜色都是由红绿蓝三原色（RGB）构成的，所以上图共有4张直方图（三原色直方图 + 最后合成的直方图）。

如果每种原色都可以取256个值，那么整个颜色空间共有1600万种颜色（256的三次方）。针对这1600万种颜色比较直方图，计算量实在太大了，因此需要采用简化方法。可以将0～255分成四个区：0～63为第0区，64～127为第1区，128～191为第2区，192～255为第3区。这意味着红绿蓝分别有4个区，总共可以构成64种组合（4的3次方）。

任何一种颜色必然属于这64种组合中的一种，这样就可以统计每一种组合包含的像素数量。

上图是某张图片的颜色分布表，将表中最后一栏提取出来，组成一个64维向量(7414, 230, 0, 0, 8, ..., 109, 0, 0, 3415, 53929)。这个向量就是这张图片的特征值或者叫"指纹"。

于是，寻找相似图片就变成了找出与其最相似的向量。这可以用皮尔逊相关系数或者余弦相似度算出。

二、内容特征法

除了颜色构成，还可以从比较图片内容的相似性入手。

首先，将原图转成一张较小的灰度图片，假定为50x50像素。然后，确定一个阙值，将灰度图片转成黑白图片。

如果两张图片很相似，它们的黑白轮廓应该是相近的。于是，问题就变成了，第一步如何确定一个合理的阙值，正确呈现照片中的轮廓？

显然，前景色与背景色反差越大，轮廓就越明显。这意味着，如果我们找到一个值，可以使得前景色和背景色各自的"类内差异最小"（minimizing the intra-class variance），或者"类间差异最大"（maximizing the inter-class variance），那么这个值就是理想的阙值。

1979年，日本学者大津展之证明了，"类内差异最小"与"类间差异最大"是同一件事，即对应同一个阙值。他提出一种简单的算法，可以求出这个阙值，这被称为"大津法"（Otsu's method）。下面就是他的计算方法。

假定一张图片共有n个像素，其中灰度值小于阙值的像素为 n1 个，大于等于阙值的像素为 n2 个（ n1 + n2 = n ）。w1 和 w2 表示这两种像素各自的比重。

w1 = n1 / n

w2 = n2 / n

再假定，所有灰度值小于阙值的像素的平均值和方差分别为 μ1 和 σ1，所有灰度值大于等于阙值的像素的平均值和方差分别为 μ2 和 σ2。于是，可以得到

类内差异 = w1(σ1的平方) + w2(σ2的平方)

类间差异 = w1w2(μ1-μ2)^2

可以证明，这两个式子是等价的：得到"类内差异"的最小值，等同于得到"类间差异"的最大值。不过，从计算难度看，后者的计算要容易一些。

下一步用"穷举法"，将阙值从灰度的最低值到最高值，依次取一遍，分别代入上面的算式。使得"类内差异最小"或"类间差异最大"的那个值，就是最终的阙值。具体的实例和Java算法，请看这里。

有了50x50像素的黑白缩略图，就等于有了一个50x50的0-1矩阵。矩阵的每个值对应原图的一个像素，0表示黑色，1表示白色。这个矩阵就是一张图片的特征矩阵。

两个特征矩阵的不同之处越少，就代表两张图片越相似。这可以用"异或运算"实现（即两个值之中只有一个为1，则运算结果为1，否则运算结果为0）。对不同图片的特征矩阵进行"异或运算"，结果中的1越少，就是越相似的图片。

（完）

原文链接：http://www.ruanyifeng.com/blog/2013/03/similar_image_search_part_ii.html （本内容由互联网资料整理而成）

前端们需要了解的图像压缩技术

Introduction

As images continue to be the largest part of webpage content, it’s critically important for web developers to take aggressive control of their image sizes and quality in order to deliver a fastest loading, responsive site for their users. Hitting this sweet-spot is not free; you can automate a ‘good enough’ value most of the time, but for the best savings, you need to test quality levels using your human eye. This article will provide a bit of reason, history, and technique to understand and properly address image compression issues for your website.

TL;DR : Image Compression Checklist

1. Compress Images with the right format at the lowest acceptable quality level

1. Hand-tune (where possible) your compression quality for all images

2. Automate the rest to get the best performance

2. Investigate using WebP for all your image needs

3. Save your images with progressive options to improve user perception of your pages’ load times

4. Investigate other interesting ways to get better compression, or transparency. Think outside the box!

Why Small is Big

Simplistically, larger pages inevitably take longer to load. There’s an unending body of research that shows that users of slow sites, spend less time on the site, click through less, click fewer ads, and spend less. Small sites, like AutoAnything, cut their load time in half, and saw revenue grow by 13 percent. And large sites, like Amazon have shown that for every 100 milliseconds of slowdown, they experienced a 1 percent drop in revenue. And let’s not forget that the 2012 presidential campaign based its entire fundraising success on making their website load instantly.

What’s worse is that users have to pay to download your website.
While bigger pages hurt performance for desktop users, too, the biggest victims of page bloat are mobile users. Not only does a 1MB page take forever to load, it can also deliver a nasty shock when you get your phone bill.

Even most ‘unlimited’ data plans for mobile, aren’t truly ‘unlimited free.’ Most of them will charge a flat rate for access up to 2GB or so, and passing that amount can cost more money. Not to mention that there’s many areas of the world without these types of ‘all you can eat’ billing plans, where cost-to-download information is a serious concern for users, as a research paper by AT-T highlighted:

mobile data traffic cost problems are severely hindering the use of mobile services on handheld devices today
…
It was interesting that users try to understand the billing rules even when the carrier does not provide this information. Based on connection indicators, information visible on the phone bill, and previous experience on data traffic billing, people create a perceived billing model that affects their mobile browsing usage patterns.

The folks over at mobiforge provided even more context, putting the entire argument in terms of costs:

AT-T charge as much as $19.97/MB for roaming data in certain countries. Taking some of the examples from Guy's spreadsheet, and using the AT-T roaming tariff, is a peak at 1pictureaday.com really worth $178? Do you really need to visit thenextweb.com for $44 or vogue.co.uk for $65? At $17 microsoft.com is a relative bargain.

For roaming users these page weights are prohibitive for all but the most essential tasks.

Big Images are a big problem. We can see the the largest increase in sizes come from images which can spell bad news for mobile, where a picture literally costs a thousand words.
Inappropriate image formatting is a common performance culprit. Images being too large, not compressed enough, or having a quality setting way too high can all lead to these images being bloated and oversized which has a direct impact on the loading of your site. Picking the right compression method to yield the best results is easily achieved by getting to know what’s going on under the hood.

Types of compression algorithms

There are generally two stages in an image compressor, a lossy phase, and lossless phase. Lossy compression algorithms will modify the source stream such that you lose information that cannot be restored upon decompression.Most lossy algorithms in image compression take advantage of how the human visual system works, often removing information that we really can’t see, and in the process, saving bytes. For example, limiting the colors used in an image; fewer colors means there’s less data to run around. Generally, when you save an image in a format supporting Lossy compression, you’re asked what “quality level” you’d like for the image, effectively, what you’re choosing is a scalar value which trades file-size for image-quality. Savvy web developers realize that there is a sweet-spot for images, such that the quality level is high enough, and the file size is low as possible.

Before

After

0.123, 1.2345, 21.2165, 21.999, 12.123

0,0,20,20,10

Figure 1 - An example of lossy compression. Values are quantized to the smallest multiple of 10 they occupy. This transform cannot be reversed.

After a lossy compressor, a lossless variant is then applied, that is, the data, once uncompressed, is restored to it’s exact state, before compression. These are typical compression algorithms that allow the source stream to be recovered directly without any loss of precision or information. In Images, popular Lossless codecs include LZ77, RLE, and Arithmetic encoding. Lossless compression algorithms are the backbone of compression, often squeezing out the last percentages of data from your content, constantly struggling with information theory to reduce your data sizes.

Before

After

aaaaabbbbbcccddddeeeeffffaaaaabb

a5b4c2d4e4f4a5bb0

Figure 2 - An example of lossless compression. Runs of values are encoded as the symbol followed by the length of the run. We can properly restore the origional stream. Note that if the length of the run is <= 2 characters, it makes sense to just leave the symbols alone. You see this at the end of the stream with ‘bb’.

Image Formats

An image format typically chains together various lossy + lossless algorithms to grant compression savings. There’s multiple formats adopted by web browsers, each with different features and performance tradeoffs. To be clear, there’s not a “one size fits all” format for the web (currently). Different types of images should be encoded into different formats depending on what type of image it is, what the browser supports, and what needs the page has.

There’s typically three decisions that go into the choice of an image format for a web developer.

- Does it need transparency?

- Does it need animation?

- Does it need high quality data?

'Lena' is a common image used in the evaluation and comparision of image compression algorithms.

PNG is a simple format that supports transparency and lossless compression. It allows you to define an alpha channel for your image, to mask out transparent areas, as well as an option to enable a lossless Deflate compressor on the data. (Deflate is a combination of two lossless compressors, LZ77, and Huffman). Because compression is lossless, image quality remains identical to the source image, this causes issues however, in that the file sizes tend to be quite bloated, and not as small as they could be.

GIF is another format which supports transparency, alongside animation (which is the direct reason for the whole ‘cats on the internet’ thing..). The GIF format contains two stages of compression, a lossy palletization step (restricting the entire image to only 256 colors) followed by a lossless LZW compressor. The process of quantizing the colors of the image down to only 256 provides an aggressive quality reduction at the benefit of better compression sizes, which tends to produce better compression from the LZW end of things.

If you don’t need transparency, or animation, then JPG is the best format for you. It was generally designed to handle the compression of high-quality photo data, but provides a configurable set of Lossy compression options, allowing you to trade off compression quality vs. image size as your application needs it.

If you’re looking for more of a ‘one stop shop’ for your image format, then WebPshould be on your radar. The format boasts not only superior compression quality/size, but also transparency and animations as well. It uses both a lossy and lossless compressor combination, and much like JPG, will allow you to define your quality level vs. file size. Of course, this new image format hasn't been adopted across all browsers just yet, so web developers who’ve adopted it are currently in the early phases of working through usability issues. Although a 30% savings over JPG, alongside increased server-side adoption prove that WebP is a dominant format for any sites dealing with image bloat problems.

Compression

Lossless

Lossy

Transparency

Animation

PNG

Good

Yes

No

Full

No

GIF

OK

Yes

Yes

Binary

Yes

JPG

Good

Yes

Yes

No

No

WebP

Great

Yes

Yes

Full

Yes

Figure 3 - Feature set for specific browser supported formats

Trading Quality for Size

For those image types which have a quality setting that you can adjust, it’s worth noting that the biggest wins you can get is by hand-optimizing the quality setting to get the smallest file. Google Webmaster Help has a great video that walks you through some ways to test quality against your image, and how to test perception properly.
And as imgmin project points out, there’s generally a small change in user perceived quality for JPG compression between levels 75 and 100:

For an average JPEG there is a very minor, mostly insignificant change in *apparent* quality from 100-75, but a significant filesize difference for each step down. This means that many images look good to the casual viewer at quality 75, but are half as large than they would be at quality 95. As quality drops below 75 there are larger apparent visual changes and reduced savings in filesize.

And further goes to show that most large websites tend to oscillate their images around this quality=75 mark for almost all of their JPG images:

Site

JPG Quality

Google Images Thumbnails

74-76

Facebook full-size images

85

Yahoo frontpage JPEGs

69-91

Youtube frontpage JPEGs

70-82

Wikipedia images

80

Windows live background

82

Twitter user JPEG images

30-100

Figure 4 - Average JPG quality level used for top websites

Customizing the settings for each image on your page to balance the tradeoff between quality and size will yield the best savings at the best quality levels. These larger sites tend to have a plethora of images, and generally have no way of hand-optimizing each one, so custom, per-image quality-level adjustment is almost impossible. Some developers have taken a more automated approach to this type of encoding; often taking the output from artists, and running their own heuristics and encodings processes on the images during a build. This type of setup fits a nice middle ground between customization and automation that will help the majority of web developers out there. You can also adopt apps like MiniJPG which will auto-tune your JPG compression level to give the best possible quality.

A quite drastic approach that developers are using to attack image size footprint is to reduce any simplistic icons and images to SVG files, and allow them to be rasterized by the client before being displayed. This type of process trades file-size for client-speed, saving bits on the wire, but incurring more client-side overhead to reconstruct the image when it’s being rendered. As such SVG image format is quite different than the other types of files, in that it is a vector format; meaning that the final image is procedurally generated using shape information defined in the file to a specific resolution of output image. When an SVG image is loaded, it’s converted to a raster format (a 2D array of pixels, like a bitmap) before being displayed.

Figure 5 - An example raster image (on the left) compared to a vector image (on the right) Notice that the vector image is much simpler, and contains less per-pixel detail. This is because the format type does not yield itself to produce high quality data.

Think of SVG as a file format that allows you to store an image ‘description’ at a very low memory footprint, and generate a high-quality, resolution independent image on the client, regardless of the size of the source data. One of the limitations of the SVG format is that it can only represent a certain type of image quality, that is to say that vector images tend to be simplistic, only using a set of primitive types to define how to generate colors on the screen . A field of grass in a prairie for instance, would require too many complex shapes to yield compression savings. Raster images are best used for photos, and other information-dense images, where Vector images are great for things like logos or simple image patterns.

Images quality, sizes and multiple resolution screens.

One of the large issues that developers are facing is the size of monitor pixels against the size of images created. That is, if an author creates image content for a desktop website, there’s a good chance that the image dimensions and quality levels have been tailored to viewing on large, desktop resolution monitors. Mobile devices throw a problem in, however, as their screen sizes are much smaller, and their connections are more expensive. As such, users can be recieving a larger image than they can display, or need.

There’s a few ways to address this issue.

One solution involves precomputing images, offline, for each resolution you need. Most static websites can generate this easily as an offline build step, perhaps resizing the images with toolchains like Grunt. This technique benefits from the fact that images are properly cached on their native device resolutions, and you’re not losing loading time, or transfer cost to get the information to the client. On the negative side, however, is the madness involved with managing this exponential increase in your data set, and the additional logic to send the information to the intended users.

Another approach, intended for the boom of high-DPI mobile devices, involves playing games with image quality, image dimensions, and client-side cost for image resizing. Effectively, you can store your image at 2x resolution (upscale process), however when you export it to a lossy format, choose a very low quality (resulting in high compression) option. The intention here is to choose a quality level such that the compressed larger image, is smaller than the compressed smaller image.

On the client, you can specify the intended dimensions of the image (which should be less than the current size of the image, since it’s been upscaled). The web-browser will downscale the image to the intended resolution, a process which can blur noise artifacts introduced from the low quality compression value; in some cases, all together.. The end result is a smaller file, that scales to multiple screen resolutions easily, and does not introduce significant quality degradation.

Image sizes, User perception and load times

Looking at the bottom line, the only thing that matters is that a site appears to load fast to users. Appearing faster is being faster, and perceived performance is more important that actual speed.

There’s a two dominant ways to display images over the web.

1. Wait for the whole image to be downloaded, and display it once its’ done

2. Display part of the image that you have downloaded so far.

No browser uses the first option, simply because it makes the page appears as slow as possible.

The second option is what most of the web is built on now. I’m sure we’re all quite familiar with the style of ‘revealing’ the image from the top-down over time. This is because the images are typically stored in raster order, or rather the first bytes of the image that the browser receives starts at the top-left of the image and moves horizontally across the row. It’s worth noting that if we store our image in a different method, we could change what bits come down the wire first, which changes how the image is seen.

This “progressive” method of encoding can have a beneficial impact to user perception that a page is loading ‘fast’ (note, this is debated, depending on user). This works by encoding a few extra versions of the image, at smaller resolutions which can be transferred faster to the user. This allows the user to see a display of the image that progressively gets sharper as the image downloads more.

Coddinghorror.com has a great example that shows off the visual difference between these two technologies. You can see that the standard method creates a top-down reveal of the image, while the progressive one ‘refines’ the visual as more data is received.

Linear

Progressive

Figure 6 - An example of linear vs. progressive loading for images.

If unicorns aren’t your thing, you can also check out a more in-depth example at Patrick Meenan’s blog, or even try this out on your own images using Patrick’s interactive tool.

Using this property in your image is extremely easy to do : Simply save your GIF or PNG images with the "interlaced" option, or your JPEG images with the "progressive" option. and start making your users love the load times of your website. Although it’s worth noting that progressive images are not supported in all browsers just yet, and loading a progressive image on those platforms can actually cause worse performance.

Images outside the box

The internet is full of brilliant web developers, and no article on image compression would be complete without pointing out some of the great hacks, workarounds, and generally impressive things that these developers have created to allow them to create smaller, higher quality, and impressive images.

Splitting your transparent layer for improved compression.

HTML5 game developers typically send around more image data than your standard website, most of it being transparent frames for a flipbook animation. Sadly that forces these files to use the PNG option in order to get transparency. However a few developers have devised a few work-arounds for images to get better compression and transparency. For example, you can split your color data, and transparency data into two separate image files (two JPGs, for example), and restoring them on the client using a CANVAS element. Although this does increase the number of requests that occur on the network, the savings in image size can be significant for developers who have tons of transparent images on their site (like).

Improve PNG compression through better processing.

PNG’s Deflate option is a lossless encoder, but that shouldn’t stop you from embracing a lossy preprocessor if you want one. Image processing tools like ImageAlpha and ImageOptim, can compress your PNG image in a lossy method as a pre-process before passing it off to the final PNG format. This creates a two-step process where your lossy, and lossless compression are done by two separate applications. The results are impressive, the reduced color space allows the lossless compressor to find, and make, more frequent matches in the file, yielding to better compression.

Once you've exported your PNG, it's time to re-pack your PNG data using advanced compressors to generate a smaller PNG file. Tools like advPNG will take your already exported PNG, and run it through a better Deflate compressor to get a smaller file. Or you could combine PNGOUT with tools like OptiPNG or Zopfli to get the same effect. Of course, each of these systems creates slightly different results, given the input systems, so it may be wise to adopt a system which will compress against multiple compressors and pick the smallest file; If you're feeling lazy, ScriptPNG will do the heavy lifting for you.

Not all animations are created equal.

The SublimeText team launched a website in which they wanted to have a rich animation showing off features of the editor. Rather than using a video, or a standard GIF, they generated a custom animation and packing system to provide great image animation at a much, much smaller size. The technique allows them to display a high-quality animation across multiple platforms without the need for advanced video, or a flash plugin.

More than one way to responsive image.

Since user perception is the most important thing in a website, it’s worth noting that there’s other ways to create ‘perceived’ faster loading websites. Recently, the BBC changed how their site handles responsive images. Their technique allows a smaller image to be downloaded to the client first (so there’s some visibility) and allow the higher-resolution image to be lazy-loaded as needed. You can find a more detailed description of their technique, alongside an open-source version to play with on your own site.

Conclusion

Images are a tricky content type that can increase the quality and user perception of your site, but also can undermine your efforts for fast loading, responsive quality. Before you ship your site live, make sure you follow the Image Compression Checklist:

1. Compress Images with the right format at the lowest acceptable quality level

1. Hand-tune (where possible) your compression quality for all images

2. Automate the rest to get the best performance

2. Investigate using WebP for all your image needs

3. Save your images with progressive options to improve user perception of your pages’ load times

4. Investigate other interesting ways to get better compression, or transparency. Think outside the box!

Useful Tools

原文链接：http://www.html5rocks.com/en/tutorials/speed/img-compression/ （本内容由互联网资料整理而成）