<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>前端叨叨客 on 前端叨叨客</title>
    <link>http://jyu213.github.io/</link>
    <description>Recent content in 前端叨叨客 on 前端叨叨客</description>
    <generator>Hugo -- gohugo.io</generator>
    <lastBuildDate>Wed, 18 Oct 2017 00:00:00 +0000</lastBuildDate>
    <atom:link href="/" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Rollup 和 Webpack 之 Tree Shaking</title>
      <link>http://jyu213.github.io/blog/2017/10/18/rollup-%E5%92%8C-webpack-%E4%B9%8B-tree-shaking/</link>
      <pubDate>Wed, 18 Oct 2017 00:00:00 +0000</pubDate>
      
      <guid>http://jyu213.github.io/blog/2017/10/18/rollup-%E5%92%8C-webpack-%E4%B9%8B-tree-shaking/</guid>
      <description>

&lt;p&gt;这个话题最早源于和同事之前的一次讨论。Webpack 也支持 Tree Shaking 了，同样 Rollup 也是，那么它们之间实现是一致的么？写了一半，中间拖了几个月，然后社区中又有两篇比较不错的文章，然后又拖了好久，才慢慢补齐了文章。拖延症伤不起啊😂。&lt;/p&gt;

&lt;h3 id=&#34;概念&#34;&gt;概念&lt;/h3&gt;

&lt;p&gt;在此之前先简单的谈谈 Tree Shaking 的概念。最早应该是从 Rollup 来的吧，不过其实简单理解的话，可以当成是 &lt;code&gt;dead code elimination&lt;/code&gt; 的另一种说辞，就是把无用代码剔除掉。它们本质的区别在于，Tree Shaking 是导入有用的代码，而 &lt;code&gt;dead code elimination&lt;/code&gt; 是排除无用代码。更学术的解释可以看 Rich_Harris 的&lt;a href=&#34;https://medium.com/@Rich_Harris/tree-shaking-versus-dead-code-elimination-d3765df85c80#.p4izirx8z&#34;&gt;官方说明&lt;/a&gt;。&lt;/p&gt;

&lt;h3 id=&#34;rollup&#34;&gt;Rollup&lt;/h3&gt;

&lt;p&gt;Rollup 作用于顶级 AST 节点上，依赖于 ES6 模块的静态解析。ES6 模块有个特性很好，就是完全的静态结构，这样导入和导出的声明都放在了模块最顶层，而且都是非动态的。正因这个设计的强大，才使用 Rollup 的 Tree Shaking 得以实现。&lt;/p&gt;

&lt;p&gt;我们先从简单的例子开始看。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;// action.js
export const walk = () =&amp;gt; console.log(&#39;jianjian is walking&#39;)
export const run = () =&amp;gt; console.log(&#39;jianjian is running&#39;)

// index.js
import {walk} from &#39;./action.js&#39;
walk()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;action.js&lt;/code&gt; 中定义了两个行为函数并导出，在 &lt;code&gt;index.js&lt;/code&gt; 中使用 &lt;code&gt;walk&lt;/code&gt; 函数。Rollup 编译后的结果如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;&#39;use strict&#39;;
const walk = () =&amp;gt; console.log(&#39;jianjian is walking&#39;);
walk();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;很明显，未使用到的 &lt;code&gt;run&lt;/code&gt; 函数则在编译的时候被移除掉了。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;如果是 CommonJS 写法的话，还需要通过 &lt;code&gt;rollup-plugin-commonjs&lt;/code&gt; 插件来转换一下。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;再来看一看对类的处理。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;// action.js
class action1 {
  talk() {
    console.log(&#39;jianjian is talking&#39;)
  }
  walk() {
    console.log(&#39;jianjian is walking&#39;)
  }
}

class action2 {
  walk() {
    console.log(&#39;jianjian is walking&#39;)
  }
}
export {
    action1,
    action2
}

// index.js
import {action1, action2} from &#39;./class.js&#39;

let act = new action1()
act.talk()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;输出的结果如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;&#39;use strict&#39;;

class action1 {
  talk() {
    console.log(&#39;jianjian is talking&#39;);
  }
  walk() {
    console.log(&#39;jianjian is walking&#39;);
  }
}

let act = new action1();
act.talk();

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;类 &lt;code&gt;action1&lt;/code&gt; 中定义了两个函数，&lt;code&gt;walk&lt;/code&gt; 未使用到， 但是实际结果还是会输出的，而 &lt;code&gt;action2&lt;/code&gt; 未使用到则不输出。如果打包的时候加了 babel 将 class 语法转换为 ES5 的实现的话就无能为力了，毕竟对动态语法的分析有可能导致更大的问题，有兴趣的同学可以参看&lt;a href=&#34;https://github.com/rollup/rollup/issues/349&#34;&gt;话题讨论&lt;/a&gt;。这也导致 Tree shaking 在实际的使用场景中显得有些尴尬，毕竟目前能优化的空间上有限。&lt;/p&gt;

&lt;p&gt;Rollup 的主要构建流程做了如下几步：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;查找。找到对应 &lt;code&gt;entry&lt;/code&gt; 模块的所有依赖项并导入(可以是 &lt;code&gt;plugin&lt;/code&gt; 处理后的内容，上面讲到的 &lt;code&gt;commonjs&lt;/code&gt; 的处理就是如此)，返回模块包含 &lt;code&gt;code&lt;/code&gt;, &lt;code&gt;ast&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt; 等的 JSON 信息。同时存储相关的依赖 &lt;code&gt;imports&lt;/code&gt;, &lt;code&gt;externals&lt;/code&gt; 等等。&lt;/li&gt;
&lt;li&gt;绑定。将索引与之相关联，来生成完整的依赖代码。&lt;/li&gt;
&lt;li&gt;标记。引用所有需要被包含的申明( Tree Shaking 就是在这一步进行处理)&lt;/li&gt;
&lt;li&gt;排序。使用增强的拓扑排序对模块进行排序，解决诸如全局命名冲突等问题。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;而  Tree Shaking 实际针对 AST 进行删减处理，主要有以下内容，具体可以查找对应 AST 语法。如果错误，欢迎指正。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;classDeclaration&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;conditional express&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;ExportDefaultDeclaration&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;FunctionDeclaration&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;isStatement&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;SequenceExpression&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Statement&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;VariableDeclaration&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;VariableDeclarator&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;​&lt;/p&gt;

&lt;p&gt;不对上面语法树替换做进一步说明了，主要展开来篇幅有点长。&lt;/p&gt;

&lt;h3 id=&#34;webpack&#34;&gt;Webpack&lt;/h3&gt;

&lt;p&gt;再来看看 Webpack 的相关处理。同样的先从函数入手。取了核心的编译后的文件，如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

&amp;quot;use strict&amp;quot;;
Object.defineProperty(__webpack_exports__, &amp;quot;__esModule&amp;quot;, { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__action_js__ = __webpack_require__(2);

Object(__WEBPACK_IMPORTED_MODULE_0__action_js__[&amp;quot;a&amp;quot; /* walk */])()



/***/ }),
/* 2 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

&amp;quot;use strict&amp;quot;;
const walk = () =&amp;gt; console.log(&#39;walk&#39;)
/* harmony export (immutable) */ __webpack_exports__[&amp;quot;a&amp;quot;] = walk;

const run = () =&amp;gt; console.log(&#39;run&#39;)
/* unused harmony export run */
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;walk&lt;/code&gt; 和 &lt;code&gt;run&lt;/code&gt; 函数还在，区别在于 &lt;code&gt;run&lt;/code&gt; 函数处有 &lt;code&gt;unused harmony export run&lt;/code&gt; 的注释，从而在 &lt;code&gt;UglifyjsWebpackPlugin&lt;/code&gt; (底层用的是 uglify-js) 的时候做删除处理。&lt;/p&gt;

&lt;p&gt;类的结果处理类似，这里不具体展开了。&lt;/p&gt;

&lt;p&gt;抛除 Webpack 整个复杂的构建过程，在  Tree Shaking  中主要处理的两步，&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;抓取所有模块合并到一个包文件中，任何未导入的文件都不会被导出&lt;/li&gt;
&lt;li&gt;在执行压缩的过程中，移除 dead code&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;我个人觉得 Webpack 的这个处理方式还是 DCE 而不该定义做  Tree Shaking。不过也就名字而已。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;todo&#34;&gt;TODO&lt;/h2&gt;

&lt;p&gt;待续😂…&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>ES6 proxy</title>
      <link>http://jyu213.github.io/blog/2017/09/28/es6-proxy/</link>
      <pubDate>Thu, 28 Sep 2017 00:47:14 +0800</pubDate>
      
      <guid>http://jyu213.github.io/blog/2017/09/28/es6-proxy/</guid>
      <description>&lt;p&gt;Proxy，顾名思义就是代理，是指在目标对象前加一层拦截（traps），可用于对访问对象的拦截和过滤。那么这个和上一节讲到的 Decorator 有什么区别呢？&lt;/p&gt;

&lt;p&gt;Decorator 是给对象添加一些额外的职责，说白了是保持原有的逻辑不变。而 Proxy 的话更倾向于为对象提供一种代理，从而控制对这个对象的访问。&lt;/p&gt;

&lt;p&gt;先来看看基本的实例。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;let proxy = new Proxy(target, handler)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;target&lt;/code&gt; 表示要拦截的对象，可以是 &lt;code&gt;Array&lt;/code&gt;，&lt;code&gt;Object&lt;/code&gt;，&lt;code&gt;Function&lt;/code&gt; 或者另一个 &lt;code&gt;Proxy&lt;/code&gt;。&lt;code&gt;handler&lt;/code&gt; 表示要拦截的行为。而作用的结果则体现在 Proxy 的实例 &lt;code&gt;proxy&lt;/code&gt; 上。如果目标没有拦截，就等同于原对象。&lt;/p&gt;

&lt;p&gt;对于具体的 API 这里就不做展开了，需要补充的同学可以直接&lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy&#34;&gt;点击查看&lt;/a&gt;。无非是监听对象的操作，然后执行相应的目标行为。比如 &lt;code&gt;get&lt;/code&gt;，&lt;code&gt;set&lt;/code&gt;，&lt;code&gt;deleteProperty&lt;/code&gt; 等等。&lt;/p&gt;

&lt;p&gt;从一个简单的 get 操作来看看 proxy 实际是如何操作的。在取对象 obj 值的时候，记录一条日志。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;let obj = {a: 1}
let proxy = new Proxy(obj, {
    get (target, key, proxy) {
        console.log(`get target key ${target[key]}`)
        return target[key]
    }
})
console.log(proxy.a)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;在 Proxy 之前，我们会做类似功能来模拟。通过 globalGetInterceptor 函数来实现具体的对象操作内容。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;// babel-plugin-proxy
var defaultHandle = {
    get: function(obj, propName) {
        return obj[propName]
    }
}
var Proxy = function(target, handle) {
    this.target = target
    this.handle = handle

    this.handle.get = this.handle.get || defaultHandle.get
}
Proxy.getTrap = function(propName) {
    return this.handle.get(this.target, propName)
}
function globalGetInterceptor(obj, propName) {
    if (obj instanceof Proxy) {
        return obj.getTrap(propName)
    }
    var value = defaultHandle.get(obj, propName)
    if (typeof value === &#39;function&#39;) {
        return value.bind(this)
    } else {
        return value
    }
}
globalGetInterceptor(proxy, &#39;a&#39;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;实际上，Proxy 的应用场景挺广的。目前看到他们常用有：
* 对对象访问的控制
* 降低函数或类的复杂度
* 对资源的检验&lt;/p&gt;

&lt;p&gt;通过具体的例子来演示一下。&lt;/p&gt;

&lt;p&gt;第一个 &lt;code&gt;console&lt;/code&gt; 的例子，稍微扩展一下的话，就可以当做监控来使用。比如在 get 或者 set 方法中加入对应的埋点等操作等等。&lt;/p&gt;

&lt;p&gt;还是用上面讲到的 obj 对象。我们也可以做一些校验，访问控制等等。比如我们只允许 obj 属性赋值是数字。不然就报错。例子如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;let obj = {a: 1}
let proxy = new Proxy(obj, {
    set (target, key, newValue) {
        if (isNaN(newValue)) {
            throw &#39;Error: isNaN&#39;
        }
        target[key] = newValue
    }
})
proxy.b = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;还有更高阶的，比如双向绑定等等。不一一例举了。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>ES7 Decorators</title>
      <link>http://jyu213.github.io/blog/2017/06/18/es7-decorators/</link>
      <pubDate>Sun, 18 Jun 2017 22:10:05 +0800</pubDate>
      
      <guid>http://jyu213.github.io/blog/2017/06/18/es7-decorators/</guid>
      <description>

&lt;p&gt;Decorators 的概念来源于 Python，可以称为&lt;strong&gt;装饰器&lt;/strong&gt;。简单的理解其实它就是一个 &lt;code&gt;wrapper&lt;/code&gt;，&lt;strong&gt;对目标函数或对象进行修改并返回&lt;/strong&gt;。如果从 Java 的角度的话，可以看作是一个 &lt;code&gt;filter&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;它只是一种语法糖，本质上是对函数的变换。先来看看经典的日志系统吧。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Person {
  @log
  getFullName(firstname, lastname) {
    return `${firstname}${lastname}`
  }
}

function log(target, key, descriptor){
  const value = descriptor.value
  descriptor.value = (...args) =&amp;gt; {
    console.log(`Calling ${key} with`, args)
    return value.apply(null, arguments)
  }
  return descriptor
}

const person = new Person()
person.getFullName(&#39;LeBron&#39;, &#39;James&#39;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;@&lt;/code&gt; 声明的 &lt;code&gt;@log&lt;/code&gt; 即为 &lt;code&gt;decorator&lt;/code&gt;，它是一个函数，接收三个参数：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;target&lt;/code&gt;，需要定义属性的对象&lt;/li&gt;
&lt;li&gt;&lt;code&gt;key&lt;/code&gt;，属性名&lt;/li&gt;
&lt;li&gt;&lt;code&gt;descriptor&lt;/code&gt;， 属性描述符，同 &lt;code&gt;Object.defineProperty&lt;/code&gt; 的 &lt;code&gt;decorator&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;发现了么，其实 &lt;code&gt;decorators&lt;/code&gt; 底层用的也是 &lt;code&gt;Object.defineProperty&lt;/code&gt; 的属性来写的。&lt;/p&gt;

&lt;p&gt;如果单纯通过外面包的一层函数来实现的话，会是怎么样的？其实也挺简单的。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function log(target){
  console.log(target.name, typeof target, arguments)
  return (...args) =&amp;gt; {
   console.log(`Calling ${target.name} with`, args)
    target.call(this, [](#).slice.call(arguments))
  }
}

class Person{
  getFullName(firstname, lastname) {
    // …
  }
}
Person.prototype.getFullName = log(Person.prototype.getFullName)
// …
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;实际项目开发中，我们可以通过使用 &lt;code&gt;babel-plugin-syntax-decorators&lt;/code&gt; 或 &lt;code&gt;babel-plugin-transform-decorators-legacy&lt;/code&gt; 来转码。让我们来看看 babel 中的实现方式。以下只是一些伪代码。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
  // descriptor 赋值逻辑以及默认属性
  Object[&#39;keys&#39;](#)(descriptor).forEach(function (key) {
    desc[key](#) = descriptor[key](#);
  });
  desc.enumerable = !!desc.enumerable;
  desc.configurable = !!desc.configurable;

  desc = decorators.slice().reverse().reduce(function (desc, decorator) {
    return decorator(target, property, desc) || desc;
  }, desc);

  if (desc.initializer === void 0) {
    Object[&#39;defineProperty&#39;](#)(target, property, desc);
    desc = null;
  }

  return desc;
}

let Person = (_class = class Person {
  getFullName(firstname, lastname) {
    return `${ firstname }${ lastname }`;
  }
}, (_applyDecoratedDescriptor(_class.prototype, &#39;getFullName&#39;, [log](#), Object.getOwnPropertyDescriptor(_class.prototype, &#39;getFullName&#39;), _class.prototype)), _class);

&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;作用-结尾&#34;&gt;作用 &amp;amp; 结尾&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;用于函数或类的修饰&lt;/li&gt;
&lt;li&gt;由于用的 Object.defineProperty 特性，所以 descriptor 还可以对对象属性层级的操作&lt;/li&gt;
&lt;li&gt;实现 &lt;code&gt;mixin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;用于工厂函数&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;几个有趣的库，对 decorator 做了一些加强。有兴趣的同学可以翻翻。
* &lt;a href=&#34;https://github.com/jayphelps/core-decorators.js&#34;&gt;core-decorators.js&lt;/a&gt;
* &lt;a href=&#34;https://github.com/akira-cn/core-wrappers&#34;&gt;core-wrappers&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>四个调节颜色的 CSS 滤镜</title>
      <link>http://jyu213.github.io/blog/2017/06/09/%E5%9B%9B%E4%B8%AA%E8%B0%83%E8%8A%82%E9%A2%9C%E8%89%B2%E7%9A%84-css-%E6%BB%A4%E9%95%9C/</link>
      <pubDate>Fri, 09 Jun 2017 01:05:16 +0800</pubDate>
      
      <guid>http://jyu213.github.io/blog/2017/06/09/%E5%9B%9B%E4%B8%AA%E8%B0%83%E8%8A%82%E9%A2%9C%E8%89%B2%E7%9A%84-css-%E6%BB%A4%E9%95%9C/</guid>
      <description>

&lt;blockquote&gt;
&lt;p&gt;本文为译文，原文地址： &lt;a href=&#34;http://vanseodesign.com/css/4-css-filters-for-adjusting-color/&#34;&gt;http://vanseodesign.com/css/4-css-filters-for-adjusting-color/&lt;/a&gt; ，作者，@Steven Bradley&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;SVG 提供了一种非破坏性的方式来改变图像或图形的某些颜色属性。不幸的是，其中的一些变化比其它的更麻烦。CSS 滤镜允许你无损的改变颜色的一些性质，比 SVG 简单。&lt;/p&gt;

&lt;p&gt;最近几周我一直在谈论 CSS 滤镜作为 SVG 滤镜的替代品。首先我提供了一个&lt;a href=&#34;http://vanseodesign.com/css/css-filters-introduction/&#34;&gt;介绍&lt;/a&gt;和展示 &lt;code&gt;blur()&lt;/code&gt; 滤镜函数的示例，然后我浏览了 &lt;a href=&#34;镜函数，并分别提供了示例。
http://vanseodesign.com/css/drop-shadow-filter/&#34;&gt;&lt;code&gt;url()&lt;/code&gt; 和 &lt;code&gt;grop-shadow() &lt;/code&gt;&lt;/a&gt; 滤镜函数，并分别提供了示例。&lt;/p&gt;

&lt;p&gt;今天我想介绍四个 CSS 滤镜函数，所有这些都是 SVG 滤镜原语 &lt;code&gt;feColorMatrix&lt;/code&gt; 的不同类型和值的映射。&lt;/p&gt;

&lt;h2 id=&#34;fecolormatrix-滤镜原语-filter-primitive&#34;&gt;feColorMatrix 滤镜原语（Filter Primitive）&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;feColorMatrix&lt;/code&gt; 滤镜原语可以用于更改元素&lt;a href=&#34;http://vanseodesign.com/web-design/hue-saturation-and-lightness/&#34;&gt;颜色的一些基本属性&lt;/a&gt;。顾名思义，原语使用矩形来添加不同的滤镜效果。&lt;/p&gt;

&lt;p&gt;存在四种不同的 CSS &lt;code&gt;filter-function&lt;/code&gt; 来达到 &lt;code&gt;feColorMatrix&lt;/code&gt; 的效果。这是一个例子，其中单个 SVG 原语可以比任何一个 CSS 滤镜功能做得更多。&lt;/p&gt;

&lt;p&gt;这是四种 CSS 滤镜：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;grayscale()&lt;/li&gt;
&lt;li&gt;hue-rotate()&lt;/li&gt;
&lt;li&gt;saturate()&lt;/li&gt;
&lt;li&gt;sepia()&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;让我们在下图中做一些具体的实践。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://www.vanseodesign.com/blog/wp-content/uploads/2013/09/strawberry-fields.jpg&#34; alt=&#34;img1&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;grayscale-函数&#34;&gt;grayscale() 函数&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;grayscale()&lt;/code&gt; &lt;code&gt;filter-function&lt;/code&gt; 功能将图像转换为灰度。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;grayscale() = grayscale( [ &amp;lt;number&amp;gt; | &amp;lt;percentage&amp;gt; ] )
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;你可以通过提供 0.0 到 1.0 之间的百分比或数字来确定转换图像的比例。100%（或 1.0）是完全转换为灰度，0% （或 0.0）则没有任何转换。0.0 和 1.0 或 0% 和 100% 直接的值是线性的乘数效应。负值是不被允许的。&lt;/p&gt;

&lt;p&gt;在第一个例子中，我使用 &lt;code&gt;filter-function&lt;/code&gt; 中的值 1 将 100% 的灰度应用到上图中。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;.strawberry {
 filter: grayscale(1);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;原始图像包含很多灰色，但我认为你可以看到滤镜的效果，因为现在所有的颜色都已被删除。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://www.vanseodesign.com/blog/wp-content/uploads/2013/09/strawberry-fields.jpg&#34; alt=&#34;img2&#34; style=&#34;filter: grayscale(1);&#34;&gt;&lt;/p&gt;

&lt;p&gt;为了比较矩阵和 &lt;code&gt;filter-function&lt;/code&gt;，公平起见，通过将 &lt;code&gt;type&lt;/code&gt; 属性设置为 &lt;code&gt;saturate&lt;/code&gt; 来使 &lt;code&gt;feColorMatrix&lt;/code&gt; 更轻松地删除颜色。看如下部分代码：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;filter id=&amp;quot;grayscale&amp;quot;&amp;gt;
 &amp;lt;feColorMatrix type=&amp;quot;matrix&amp;quot;
    values=&amp;quot;(0.2126 + 0.7874 * [1 - amount]) (0.7152 - 0.7152 * [1 - amount]) (0.0722 - 0.0722 * [1 - amount]) 0 0
            (0.2126 - 0.2126 * [1 - amount]) (0.7152 + 0.2848 * [1 - amount]) (0.0722 - 0.0722 * [1 - amount]) 0 0
            (0.2126 - 0.2126 * [1 - amount]) (0.7152 - 0.7152 * [1 - amount]) (0.0722 + 0.9278 * [1 - amount]) 0 0 0 0 0 1 0&amp;quot;/&amp;gt;
&amp;lt;/filter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;不过，这绝对是 CSS &lt;code&gt;filter-function&lt;/code&gt; 功能更容易使用的情况。我知道使用这个特定的矩阵唯一的原因是我在网上发现一个例子，不需要搜索 &lt;code&gt;filter-function&lt;/code&gt; 的值为 1。&lt;/p&gt;

&lt;h2 id=&#34;hue-rotate-函数&#34;&gt;hue-rotate() 函数&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;hue-rotate() filter-function&lt;/code&gt; 将元素中每个像素的色调改变为你指定的数量。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;hue-rotate() = hue-rotate( &amp;lt;angle&amp;gt; )
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;角度设置为度数，你需要将单位指定为 &lt;code&gt;deg&lt;/code&gt;。 0deg 的角度使得元素不变， 和 360deg(720deg, 1080deg, 1440p等)的任意倍数一致。&lt;/p&gt;

&lt;p&gt;这个例子中我设置了角度为 255deg。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;.strawberry {
 filter: hue-rotate(225deg);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;该值将红色和黄色的花朵变成含有更多粉色，紫色和蓝色的花朵。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://www.vanseodesign.com/blog/wp-content/uploads/2013/09/strawberry-fields.jpg&#34; alt=&#34;img3&#34; style=&#34;filter: hue-rotate(225deg);&#34;&gt;&lt;/p&gt;

&lt;p&gt;以下是 SVG &lt;code&gt;filter&lt;/code&gt; 的对比。CSS 依旧更简单。不过这种情况并不多。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;filter id=&amp;quot;hue-rotate&amp;quot;&amp;gt;
 &amp;lt;feColorMatrix type=&amp;quot;hueRotate&amp;quot; values=&amp;quot;225&amp;quot;/&amp;gt;
&amp;lt;/filter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;saturate-函数&#34;&gt;saturate() 函数&lt;/h2&gt;

&lt;p&gt;CSS 还提供了一个 &lt;code&gt;saturate() filter-function&lt;/code&gt;，你可以使用它来更改元素饱和度。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;saturate() = saturate( [ &amp;lt;number&amp;gt; | &amp;lt;percentage&amp;gt; ] )
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;
和&lt;/code&gt;grayscale` 函数一样，该值定义了转让的比例。0% （或 0.0） 导致完全饱和度的元素，100%（或 1.0） 使元素保持不变。之间的值是线性的乘数效应。&lt;/p&gt;

&lt;p&gt;这里我设置了 50%。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;.strawberry {
 filter: saturate(0.5);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;返回图片如下。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://www.vanseodesign.com/blog/wp-content/uploads/2013/09/strawberry-fields.jpg&#34; alt=&#34;img4&#34; style=&#34;filter: saturate(0.5);&#34;&gt;&lt;/p&gt;

&lt;p&gt;不允许使用负值，但是你可以提供大于 100% 或 1.0 的值。使得元素超饱和、再次使用 900% 饱和度的图像（ &lt;code&gt;filter:saturate(9);&lt;/code&gt;）。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://www.vanseodesign.com/blog/wp-content/uploads/2013/09/strawberry-fields.jpg&#34; alt=&#34;img5&#34; style=&#34;filter: saturate(9);&#34;&gt;&lt;/p&gt;

&lt;p&gt;如同 &lt;code&gt;saturate()&lt;/code&gt;，相应的 SVG &lt;code&gt;filter&lt;/code&gt; 是比较简单的。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;filter id=&amp;quot;saturate&amp;quot;&amp;gt;
 &amp;lt;feColorMatrix type=&amp;quot;saturate&amp;quot; values=&amp;quot;0.5&amp;quot;/&amp;gt;
&amp;lt;/filter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;我之前提到，你可以通过将 &lt;code&gt;type&lt;/code&gt; 属性设置为 &lt;code&gt;saturate&lt;/code&gt;，来使 &lt;code&gt;feColorMatrix&lt;/code&gt; 更轻松地创建灰度图像。你只需要将值设置为 0，使得图像完全饱和，这与将其设置为 100% 灰度产生。&lt;/p&gt;

&lt;h2 id=&#34;sepia-函数&#34;&gt;sepia() 函数&lt;/h2&gt;

&lt;p&gt;最后还有 &lt;code&gt;sepia() filter-function&lt;/code&gt; 将图像转换为深褐色。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sepia() = sepia( [ &amp;lt;number&amp;gt; | &amp;lt;percentage&amp;gt; ] )
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;现在应该很熟悉，但是值定义了转换的比例。100%（1.0）是完全深褐色，而 0%（0.0）则保持图像不变。期间的值是效果间的线性乘数效应。&lt;/p&gt;

&lt;p&gt;不允许使用负值，但是你可以提供大于 100% 或 1.0 的值，但不会添加效果。&lt;/p&gt;

&lt;p&gt;这里我设置为 75%。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;.strawberry {
 filter: sepia(75%);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;图片如下：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://www.vanseodesign.com/blog/wp-content/uploads/2013/09/strawberry-fields.jpg&#34; alt=&#34;img6&#34; style=&#34;filter: sepia(75%);&#34;&gt;&lt;/p&gt;

&lt;p&gt;对于没有 &lt;code&gt;sepia&lt;/code&gt;  类型的 &lt;code&gt;feColorMatrix&lt;/code&gt;，所有想要获得与使用另一个矩阵的深褐色效果。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;filter id=&amp;quot;sepia&amp;quot;&amp;gt;
 &amp;lt;feColorMatrix type=&amp;quot;matrix&amp;quot;
    values=&amp;quot;(0.393 + 0.607 * [1 - amount]) (0.769 - 0.769 * [1 - amount]) (0.189 - 0.189 * [1 - amount]) 0 0
            (0.349 - 0.349 * [1 - amount]) (0.686 + 0.314 * [1 - amount]) (0.168 - 0.168 * [1 - amount]) 0 0
            (0.272 - 0.272 * [1 - amount]) (0.534 - 0.534 * [1 - amount]) (0.131 + 0.869 * [1 - amount]) 0 0 0 0 0 1 0&amp;quot;/&amp;gt;
&amp;lt;/filter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;我认为你同意 CSS 滤镜功能是这两个选项，即使 SVG 在更灵活配置。&lt;/p&gt;

&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;

&lt;p&gt;这四个 CSS 过滤器功能都是 滤镜原语 &lt;code&gt;feColorMatrix&lt;/code&gt; 的不同类型和值的映射。其中两个代替复杂的矩阵，而另外两个替换一个特定类型的原语。&lt;/p&gt;

&lt;p&gt;我希望您同意，所有这四个过滤功能都足够容易理解和使用。我怀疑你会很难与他们合作，或弄清楚用来调整图像和图形的值。&lt;/p&gt;

&lt;p&gt;下一周，我将通过查看四个更多的&lt;a href=&#34;http://vanseodesign.com/web-design/svg-filter-primitives-fecomponenttransfer/&#34;&gt;滤镜原语&lt;/a&gt;创建的效果。与今天四个功能一样，我相你会下周的功能通常与原语更若以使用。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>【译】CSS 网格的春天</title>
      <link>http://jyu213.github.io/blog/2017/05/10/%E8%AF%91css-%E7%BD%91%E6%A0%BC%E7%9A%84%E6%98%A5%E5%A4%A9/</link>
      <pubDate>Wed, 10 May 2017 22:34:58 +0800</pubDate>
      
      <guid>http://jyu213.github.io/blog/2017/05/10/%E8%AF%91css-%E7%BD%91%E6%A0%BC%E7%9A%84%E6%98%A5%E5%A4%A9/</guid>
      <description>

&lt;blockquote&gt;
&lt;p&gt;本文为译文，原文地址： &lt;a href=&#34;http://jonibologna.com/spring-into-css-grid，作者，@jonitrythall&#34;&gt;http://jonibologna.com/spring-into-css-grid，作者，@jonitrythall&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;CSS 网格(Grid)最近一直受到很多的关注，我终于在过去的一个周末腾出时间来了解它的基本工作原理。道路很曲折，前途很美好（说真的，这是改变生活的东西），但是我在创建示例并分享的同时，整理了一些笔记。&lt;/p&gt;

&lt;p&gt;这篇文章不是只看看这个布局功能有多强大，而是希望它在这混乱中把威胁因素移除，或者进入 CSS 网格。&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://codepen.io/jonitrythall/full/xdOrrq/&#34;&gt;点击这里查看完整的 Demo&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;制定一个计划&#34;&gt;制定一个计划&lt;/h3&gt;

&lt;p&gt;和学习任何网络新事物一样，我立即打开 &lt;code&gt;Adobe Illustrator&lt;/code&gt;，感受自然，网格和紫色带来的灵感，我开始绘制一个基本的户外场景，然后开始尝试用 CSS 网格来实现。&lt;/p&gt;

&lt;p&gt;下图为我的最终搞：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://jonibologna.com/content/images/2017/04/scene-01.png&#34; alt=&#34;images&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;标记&#34;&gt;标记&lt;/h3&gt;

&lt;p&gt;标记由一个 &lt;code&gt;class&lt;/code&gt; 名为 &lt;code&gt;contain&lt;/code&gt; 的 &lt;code&gt;div&lt;/code&gt; 主容器以及十二个 &lt;code&gt;class&lt;/code&gt; 名为 &lt;code&gt;spring&lt;/code&gt; 的子集 &lt;code&gt;div&lt;/code&gt; 组成。HTML 和 CSS 代码片段如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;div class=&amp;quot;contain&amp;quot;&amp;gt;
  &amp;lt;div class=&amp;quot;spring&amp;quot;&amp;gt;
    &amp;lt;img src=&amp;quot;https://s3-us-west-2.amazonaws.com/s.cdpn.io/80625/sun.svg&amp;quot; alt=&amp;quot;Sun&amp;quot; width=&amp;quot;15%&amp;quot; /&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;spring&amp;quot;&amp;gt;
    &amp;lt;img src=&amp;quot;https://s3-us-west-2.amazonaws.com/s.cdpn.io/80625/cloud_copy.svg&amp;quot; alt=&amp;quot;Cloud&amp;quot; width=&amp;quot;30%&amp;quot; /&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;spring&amp;quot;&amp;gt;
    &amp;lt;img src=&amp;quot;https://s3-us-west-2.amazonaws.com/s.cdpn.io/80625/cloud_copy.svg&amp;quot; alt=&amp;quot;Cloud&amp;quot; width=&amp;quot;30%&amp;quot; /&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;spring&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;https://s3-us-west-2.amazonaws.com/s.cdpn.io/80625/rain.svg&amp;quot; alt=&amp;quot;Rain&amp;quot; width=&amp;quot;60%&amp;quot; /&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;spring&amp;quot;&amp;gt;
    &amp;lt;img src=&amp;quot;https://s3-us-west-2.amazonaws.com/s.cdpn.io/80625/rain.svg&amp;quot; alt=&amp;quot;Rain&amp;quot; width=&amp;quot;60%&amp;quot; /&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;spring&amp;quot;&amp;gt;
    &amp;lt;img src=&amp;quot;https://s3-us-west-2.amazonaws.com/s.cdpn.io/80625/rain.svg&amp;quot; alt=&amp;quot;Rain&amp;quot; width=&amp;quot;27%&amp;quot; /&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;spring&amp;quot;&amp;gt;
    &amp;lt;img src=&amp;quot;https://s3-us-west-2.amazonaws.com/s.cdpn.io/80625/dragonfly.svg&amp;quot; alt=&amp;quot;Dragonfly&amp;quot; width=&amp;quot;30%&amp;quot; /&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;spring&amp;quot;&amp;gt;
    &amp;lt;img src=&amp;quot;https://s3-us-west-2.amazonaws.com/s.cdpn.io/80625/butterfly.svg&amp;quot; alt=&amp;quot;Butterfly&amp;quot; width=&amp;quot;30%&amp;quot; /&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;spring&amp;quot;&amp;gt;
    &amp;lt;img src=&amp;quot;https://s3-us-west-2.amazonaws.com/s.cdpn.io/80625/dragonfly.svg&amp;quot; alt=&amp;quot;Dragonfly&amp;quot; width=&amp;quot;30%&amp;quot; /&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;spring&amp;quot;&amp;gt;
    &amp;lt;img src=&amp;quot;https://s3-us-west-2.amazonaws.com/s.cdpn.io/80625/butterfly.svg&amp;quot; alt=&amp;quot;Butterfly&amp;quot; width=&amp;quot;30%&amp;quot;/&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;spring&amp;quot;&amp;gt;
    &amp;lt;img src=&amp;quot;https://s3-us-west-2.amazonaws.com/s.cdpn.io/80625/flower1.svg&amp;quot; alt=&amp;quot;First flower&amp;quot; /&amp;gt;
    &amp;lt;img src=&amp;quot;https://s3-us-west-2.amazonaws.com/s.cdpn.io/80625/flower2.svg&amp;quot; alt=&amp;quot;Second flower&amp;quot; /&amp;gt;
    &amp;lt;img src=&amp;quot;https://s3-us-west-2.amazonaws.com/s.cdpn.io/80625/flower3.svg&amp;quot; alt=&amp;quot;Third flower&amp;quot; /&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;spring&amp;quot;&amp;gt;
    &amp;lt;img src=&amp;quot;https://s3-us-west-2.amazonaws.com/s.cdpn.io/80625/flowers2.svg&amp;quot; alt=&amp;quot;Fourth flower&amp;quot; /&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-sass&#34;&gt;$orange: #FB9C6F;

body {
  border: 2px solid $orange;
}

.contain {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(3, 2fr) 1fr 4fr;
  grid-gap: 2px;
  background-color: $orange;
}

.spring {
  padding: 2em;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #FFF;
}

// Sun
.spring:nth-child(1) {
  grid-column: 1 / 5;
}

// Cloud 1
.spring:nth-child(2) {
  grid-column: 1 / 3;
}

// Cloud 2
.spring:nth-child(3) {
  grid-column: 3 / 5;
}

// Rain 1
.spring:nth-child(4) {
  grid-column: 1 / 2;
}

// Rain 2
.spring:nth-child(5) {
  grid-column: 2 / 3;
}

// Rain 3
.spring:nth-child(6) {
  grid-column: 3 / 5;
}

// Flowers 1
.spring:nth-child(11) {
  grid-column: 1 / 4;
  justify-content: space-around;
}

// Flowers 2
.spring:nth-child(12) {
  grid-column: 4 / 5;
}

// Just simplifying for smaller window
@media (max-width: 550px) {
  .contain {
    display: block;
  }

  .spring:nth-child(3),
  .spring:nth-child(5),
  .spring:nth-child(6),
  .spring:nth-child(7),
  .spring:nth-child(8),
  .spring:nth-child(11) {
    display: none;
  }

  img {
    width: 30%;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;在实现网格之前，布局是标准的状态，所有的图像堆叠在一起。如下图：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://jonibologna.com/content/images/2017/04/Screen-Shot-2017-04-23-at-12-27-03-PM.png&#34; alt=&#34;images&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;columns&#34;&gt;columns&lt;/h3&gt;

&lt;p&gt;使用网格时首先需要在 CSS 网格容器中声明它：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-css&#34;&gt;.contain {
    display: grid;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;注意：这里也有 &lt;code&gt;inline-grid&lt;/code&gt; 和 &lt;code&gt;subgrid&lt;/code&gt; 作为选项。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;这里将立即设置容器内所有的子元素为网格项。&lt;/p&gt;

&lt;p&gt;初始网格基于使用 &lt;code&gt;grid-template-columns&lt;/code&gt; 属性设置的四个相同大小的列。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-css&#34;&gt;.contain {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;repeat&lt;/code&gt; 函数允许缩短 &lt;code&gt;1fr 1fr 1fr 1fr&lt;/code&gt; 的写法。&lt;/p&gt;

&lt;h3 id=&#34;fr-单位&#34;&gt;&lt;code&gt;fr&lt;/code&gt; 单位&lt;/h3&gt;

&lt;p&gt;网格属性可以接受多个不同的单位值，本例中只使用了 &lt;code&gt;fr&lt;/code&gt;。这个单位是超级聪明和灵活的，因为它将可用空间划分为分数，所以 &lt;code&gt;1fr 1fr 1fr 1fr&lt;/code&gt; 将生成四个相同大小的列。&lt;/p&gt;

&lt;h3 id=&#34;网格间距&#34;&gt;网格间距&lt;/h3&gt;

&lt;p&gt;网格间距由每个项目的 &lt;code&gt;2px&lt;/code&gt; 橙色间距表示。间隙显示主容器的背景颜色，为橙色，外边框是 &lt;code&gt;body&lt;/code&gt; 本身。每个网格包含一个白色背景的图像。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://jonibologna.com/content/images/2017/04/Screen-Shot-2017-04-23-at-12-01-19-PM.png&#34; alt=&#34;images&#34; /&gt;&lt;/p&gt;

&lt;p&gt;示例使用缩写 &lt;code&gt;grid-gap&lt;/code&gt; 来匹配 &lt;code&gt;grid-column-gap&lt;/code&gt; 和 &lt;code&gt;grid-row-gap&lt;/code&gt;。该属性接受单个共享值或者两个不同的值，第一个参数表示行，第二个表示列。&lt;/p&gt;

&lt;h3 id=&#34;从列起点和终点来排列项目&#34;&gt;从列起点和终点来排列项目&lt;/h3&gt;

&lt;p&gt;一旦在主容器上设置基本列，容器中的每个子元素 &lt;code&gt;div&lt;/code&gt; 都可以单独进一步设计，已实现以下网格：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://jonibologna.com/content/images/2017/04/Screen-Shot-2017-04-23-at-1-02-31-PM.png&#34; alt=&#34;images&#34; /&gt;&lt;/p&gt;

&lt;p&gt;这是通过 &lt;code&gt;grid-column-start&lt;/code&gt; 和 &lt;code&gt;grid-column-end&lt;/code&gt; 属性或 &lt;code&gt;grid-column&lt;/code&gt; 简写来指定元素的起点和终点来完成的。&lt;/p&gt;

&lt;p&gt;例如，每个后代元素 &lt;code&gt;div&lt;/code&gt; 起点和终点定义如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-css&#34;&gt;.spring:nth-child(4) {
  grid-column: 1 / 2;
}

.spring:nth-child(5) {
  grid-column: 2 / 3;
}

.spring:nth-child(6) {
  grid-column: 3 / 5;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;第四列项目（第一个雨图像容器）的 &lt;code&gt;grid-column: 1 / 2 ;&lt;/code&gt; 指示它在第一垂直网格线开始并在第二列结束，而第六项（第三个云图像容器）被设置为在第三垂直网格线开始并在第五列结束，使其成为其它的两倍。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://jonibologna.com/content/images/2017/04/Screen-Shot-2017-04-23-at-2-30-25-PM.png&#34; alt=&#34;images&#34; /&gt;&lt;/p&gt;

&lt;p&gt;最初这可能有点棘手，因为垂直线超过了实际网格列单元的个数。&lt;/p&gt;

&lt;p&gt;太阳图像能够通过从第一垂直网线开始并在最后一行终止，即第五行，跨越所有四个可用单元格，从而占据全宽。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-css&#34;&gt;.spring:nth-child(1) {
  grid-column: 1 / 5;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&#34;http://jonibologna.com/content/images/2017/04/Screen-Shot-2017-04-24-at-8-50-24-AM.png&#34; alt=&#34;images&#34; /&gt;&lt;/p&gt;

&lt;p&gt;没有必要对蜻蜓图像和蝴蝶图像做任何事情，因为所需的布局与主容器 &lt;code&gt;.contain&lt;/code&gt; &lt;code&gt;div&lt;/code&gt; 上的列声明一致。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://jonibologna.com/content/images/2017/04/Screen-Shot-2017-04-23-at-12-13-05-PM.png&#34; alt=&#34;images&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;rows&#34;&gt;rows&lt;/h3&gt;

&lt;p&gt;回到容器元素设置行，这是我来演示这个奇怪风景的最后一步。尽管初始列由相等的间距组成，但是行具有更多的变化。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://jonibologna.com/content/images/2017/04/Screen-Shot-2017-04-23-at-12-57-19-PM.png&#34; alt=&#34;images&#34; /&gt;&lt;/p&gt;

&lt;p&gt;前三行是最小行的两倍，而最大行是最小行的四倍，如下所示： &lt;code&gt;grid-template-rows: repeat(3, 2fr) 1fr 4fr;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;这个设计对于行的需求是相当轻的，这就是行样式所需的程度，但是行有自己的一组属性，有些甚至可以与列属性组合来创建速记法，保持 CSS 的简洁。&lt;/p&gt;

&lt;h3 id=&#34;flexbox&#34;&gt;Flexbox&lt;/h3&gt;

&lt;p&gt;谈及 flexbox（并且最近创建了一个&lt;a href=&#34;https://gum.co/YdWw&#34;&gt;印刷视觉指南&lt;/a&gt;），我只想说，在这个示例中，&lt;code&gt;flexbox&lt;/code&gt; 用于将图像在网格中居中，而网格和 &lt;code&gt;flexbox&lt;/code&gt; 实际上可以一起使用。&lt;/p&gt;

&lt;p&gt;使用如下，使得每张图片都在项目中居中：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-css&#34;&gt;.spring {
    display: flex;
    justify-content: center;
    align-items: center;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;div&lt;/code&gt; 包含三个独立的花图像，&lt;code&gt;flexbox&lt;/code&gt; 也水平划分它们。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://jonibologna.com/content/images/2017/04/Screen-Shot-2017-04-23-at-12-15-43-PM.png&#34; alt=&#34;images&#34; /&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-css&#34;&gt;.spring:nth-child(11) {
    display: flex;
    justify-content: space-around;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;Robin Rendle&lt;/code&gt; 最近在 &lt;code&gt;CSS-Tricks&lt;/code&gt; 上写了有关这个主题的一个&lt;a href=&#34;https://css-tricks.com/css-grid-replace-flexbox/&#34;&gt;很好的总结&lt;/a&gt;。&lt;/p&gt;

&lt;h3 id=&#34;浏览器支持&#34;&gt;浏览器支持&lt;/h3&gt;

&lt;p&gt;目前浏览器支持状况：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://jonibologna.com/content/images/2017/04/Screen-Shot-2017-04-23-at-1-24-17-PM.png&#34; alt=&#34;images&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;资源&#34;&gt;资源&lt;/h3&gt;

&lt;p&gt;这里有一些比较好的扩展阅读：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://css-tricks.com/getting-started-css-grid/&#34;&gt;Getting Started with CSS Grid&lt;/a&gt;
&lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout&#34;&gt;Basic CSS Grid Concepts on MDN&lt;/a&gt;
&lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout&#34;&gt;CSS Grid Layout on MDN&lt;/a&gt;
&lt;a href=&#34;https://www.w3.org/TR/css3-grid-layout/&#34;&gt;The spec&lt;/a&gt;
&lt;a href=&#34;http://cssgridgarden.com/&#34;&gt;CSS Grid Garden&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;结尾&#34;&gt;结尾&lt;/h3&gt;

&lt;p&gt;要了解 CSS Grid 的功能，还需要学习更多的东西，我迫不及待地写更多的内容，但希望这篇文章可以作为一个有趣的起点。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>GTD 学习笔记</title>
      <link>http://jyu213.github.io/blog/2017/04/18/gtd-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Tue, 18 Apr 2017 01:52:13 +0800</pubDate>
      
      <guid>http://jyu213.github.io/blog/2017/04/18/gtd-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</guid>
      <description>

&lt;blockquote&gt;
&lt;p&gt;起由是由于最近事情比较多而且散，常常忙的焦头烂额还一头雾水。想起了之前同事推荐的软件 OmniFocus，从而花了周末的时间简单学习了下关于 GTD 的一些知识。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;概念&#34;&gt;概念&lt;/h3&gt;

&lt;p&gt;GTD，Getting Things Done。是目前比较流行的一套时间管理方案。来自艾伦的同名书籍。其主要思想就是把你脑中的事情全都移出收集到一个统一的地方，然后进行管理分配后，一件一件的事情去做。最后再进行定期的回顾。最主要的是保证一个时间段只做一件事情，从而来达到高效的目的。&lt;/p&gt;

&lt;p&gt;GTD 中可以鉴戒的地方有很多。不过所有的概念理论肯定不适合每一个人，所以还需要依据自己的行为模式不断的实践打磨，找到一套属于自己的管理体系。自我升级，也是一件有趣的事情。目前正在尝试，期待后面会有一些新的想法。&lt;/p&gt;

&lt;h3 id=&#34;核心原则&#34;&gt;核心原则&lt;/h3&gt;

&lt;p&gt;GTD 的核心原则主要是&lt;strong&gt;收集&lt;/strong&gt;，&lt;strong&gt;处理&lt;/strong&gt;，&lt;strong&gt;组织&lt;/strong&gt;，&lt;strong&gt;执行&lt;/strong&gt;，&lt;strong&gt;回顾&lt;/strong&gt;。&lt;/p&gt;

&lt;h4 id=&#34;收集&#34;&gt;收集&lt;/h4&gt;

&lt;p&gt;是及时的把任何你需要做的，想到的事情都记录到收集箱（inbox）中。在这个阶段可以不用管是否有价值，因为后续还会有专门一个流程用于整理处理收集箱。记录的形式可以是纸质的或者是电子的，你喜欢就好。关键是&lt;strong&gt;及时&lt;/strong&gt;，不要拖着等到忘记了，我们需要的是无负荷的头脑。这样的好处是你可以将大脑中的一些无关信息清空，专心做事。后续只需要对着收集箱来处理即可。&lt;/p&gt;

&lt;h4 id=&#34;处理&#34;&gt;处理&lt;/h4&gt;

&lt;p&gt;将你收集箱中的信息快速进行处理。建议每天清理一次。处理的方法是从上往下逐条进行，不放回收集箱。操作中有一个重要原则，&lt;strong&gt;两分钟原则&lt;/strong&gt;。任何事情如果少于两分钟，就马上执行。其它的，可以委托他人或者延期（及放入一个专门的处理箱中），或者给设定一个专门的情景，或者放入后期所需执行的日程表中，无用的信息就果断的删除。&lt;/p&gt;

&lt;h4 id=&#34;组织&#34;&gt;组织&lt;/h4&gt;

&lt;p&gt;这是一个很重要的一步。对于上述中不能立即执行的，需要规划好&lt;strong&gt;下一步行动&lt;/strong&gt;（action）。把任务切割成能做的一条一条。可以按情境（context）分类。那些不能一步执行完成的可以归属为一个项目，把需要等待他人才能继续进行的设置为等待，可能在以后需要做的设置为将来状态。总而言之，就是把之前收集到的任务全部整理归类好，便于后续执行。&lt;/p&gt;

&lt;p&gt;这里可能还需要统筹规划下之前的收录是否有遗漏，项目中是否需要拆分等等事情。&lt;/p&gt;

&lt;p&gt;这里我还特地去搜索了下为何按情境来分类，感觉还是不太适应。举例来说，有很多内容是需要在特定的环境下才能处理的，比如办公场所，家里，无网络状态等等。大概看了下自己，估计 90% 以上都是同一个情境的，意义不大。个人还是喜欢按四象限法则的重要程度来划分会多一点。&lt;/p&gt;

&lt;h4 id=&#34;执行&#34;&gt;执行&lt;/h4&gt;

&lt;p&gt;这个就完全没有压力了。按着排好的任务一条一条往下做就好了。如果碰对紧急的统统塞进收集箱中，重要的，先保存工作场景，去处理，后续再回来。&lt;/p&gt;

&lt;h4 id=&#34;回顾&#34;&gt;回顾&lt;/h4&gt;

&lt;p&gt;这个也很重要的。自己在这方面一直做的不好，常常有种碌碌无为怀疑人生的错觉。通过回顾来了解项目的计划及进度，并做适当的调整。最终服务于长期目标。建议每天小结，每周一完整总结。&lt;/p&gt;

&lt;h3 id=&#34;工具&#34;&gt;工具&lt;/h3&gt;

&lt;p&gt;适合 GTD 的工具实在太多了。这里不罗列了。需要注意的是不要花太多精力在选择工具上，到头来适得其反。&lt;/p&gt;

&lt;h3 id=&#34;结语&#34;&gt;结语&lt;/h3&gt;

&lt;p&gt;好了，让我们来回顾一下 GTD 做了啥。把要做的事情都记录下来，集中处理你的需求，是立即完成还是归到下一步行动。然后保持及时的更新与回顾。就这么简单。&lt;/p&gt;

&lt;p&gt;GTD 的其中一个精髓是&lt;strong&gt;立即就做&lt;/strong&gt;。把那些大项目切割成一块块，然后我们按部就班的一步步执行下来就可以了。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>CSS 模块化组织之道</title>
      <link>http://jyu213.github.io/blog/2017/04/01/css-%E6%A8%A1%E5%9D%97%E5%8C%96%E7%BB%84%E7%BB%87%E4%B9%8B%E9%81%93/</link>
      <pubDate>Sat, 01 Apr 2017 00:00:00 +0000</pubDate>
      
      <guid>http://jyu213.github.io/blog/2017/04/01/css-%E6%A8%A1%E5%9D%97%E5%8C%96%E7%BB%84%E7%BB%87%E4%B9%8B%E9%81%93/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;前几天还在问朋友，CSS 近期有没有推出啥比较火热的，答，除了 &lt;code&gt;Grid&lt;/code&gt; 好像没啥新东西。CSS 确实好像没有 JS 社区那么火热了。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;由于 CSS 自身语言的特点，操作起来非常容易，但是等到项目到达一定程度的时候，想要优雅的管理 CSS，却也不见得那么容易。&lt;/p&gt;

&lt;p&gt;大家平常在开发 CSS 的过程中， 肯定遇到过下面的一些情况：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;全局命名空间容易冲突&lt;/li&gt;
&lt;li&gt;文件依赖管理的混乱&lt;/li&gt;
&lt;li&gt;层级嵌套太深&lt;/li&gt;
&lt;li&gt;样式被重置&lt;/li&gt;
&lt;li&gt;大量重复、冗余、无用的代码&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;好的 CSS 设计应该具有&lt;strong&gt;可读性&lt;/strong&gt;，&lt;strong&gt;维护性&lt;/strong&gt;，&lt;strong&gt;扩展性&lt;/strong&gt;和&lt;strong&gt;复用性&lt;/strong&gt;。这几条其实也不用特地的去解释，在软件开发设计中并不陌生。大体来说，就是设计 CSS 的时候，我们需要考虑书写的条理是否清晰，后续修改内容是否低成本，新增内容又是否会打破现有逻辑。而在组织 CSS 的时候，尽量地多考虑下抽象与解耦，可以依据现有的内容，快速创建新的模块。&lt;/p&gt;

&lt;p&gt;而现在对于 CSS 模块化的解决方案其实也有很多，比如 &lt;code&gt;OOCSS&lt;/code&gt;，&lt;code&gt;SMACSS&lt;/code&gt;，&lt;code&gt;CSS Modules&lt;/code&gt; 以及 &lt;code&gt;BEM&lt;/code&gt; 的命名规则。在这里，我也不一一介绍这些概念具体是什么了，有兴趣的同学可以自己去研究下，相关的文章已经太多了。&lt;/p&gt;

&lt;p&gt;在如此多的选择之中，甚至可以说是混乱，我觉得最重要的是，各个团队应该依据各自的业务情况选择合适的方案，并做好团队中的&lt;strong&gt;约定&lt;/strong&gt;。大家遵循同一套约定与规范，在合理解决问题的同时也避免出现使用混乱的情况。&lt;/p&gt;

&lt;p&gt;下面来谈谈我自己平时项目中的一些解决方案。这也是平时开发经验和借鉴现有方案的组合。&lt;/p&gt;

&lt;p&gt;闲话扯在前面的是，目前方案中推荐使用预处理器等方式。虽然即使不用也能满足绝大多数场景，但是有更优雅而便捷的方式何乐而不为呢。&lt;/p&gt;

&lt;p&gt;首先，目录划分。将 CSS 分为两类，通用模块和业务模块，可以适当地分为多个小文件。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;通用模块中存放公共部分，同一类别独自一文件，可以是表示结构的，也可以是表示主题的，唯独表示页面具体逻辑的部分，不能放在该目录下。&lt;/li&gt;
&lt;li&gt;业务模块则指具体页面对应的 CSS 文件。一个页面单独对应一个 CSS 文件。通过 &lt;code&gt;@import&lt;/code&gt; 引入相关的通用模块子文件及需要更细粒度拆分的 CSS 文件。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;如下图所示，&lt;code&gt;common&lt;/code&gt; 中存在的为共用部分文件，而 &lt;code&gt;page&lt;/code&gt; 下则具体对应到指定的页面。&lt;code&gt;Demo/style.css&lt;/code&gt; 为对应 &lt;code&gt;Demo&lt;/code&gt; 页面中的 CSS 文件。其中 &lt;code&gt;style.css&lt;/code&gt; 可能还 &lt;code&gt;@import&lt;/code&gt; 了 &lt;code&gt;common/form.css&lt;/code&gt;，&lt;code&gt;common/btn.css&lt;/code&gt; 以及 &lt;code&gt;Demo/css&lt;/code&gt; 目录下的文件。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    ├── common
    │   ├── btn.css
    │   ├── common.css
    │   ├── form.css
    │   └── layout.css
    └── page
        └── Demo
            ├── css
            │   ├── list.css
            │   └── search.css
            └── style.css
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;其次，在命名方式上，主要以原子类 + BEM 的方式来命名。
这里的原子类，不是像 &lt;code&gt;mr10&lt;/code&gt;， &lt;code&gt;pull-right&lt;/code&gt; 这类方式，而是带有固有前缀的命名方式。好处是可以通过命名来快速识别所属位置及功能。比如以 &lt;code&gt;ly-&lt;/code&gt; 前缀来表示和页面布局相关结构，如两栏三栏。再比如 &lt;code&gt;pos-mr10&lt;/code&gt;，&lt;code&gt;pos-fl&lt;/code&gt; ，&lt;code&gt;sty-fiz12&lt;/code&gt;等等。这个可能目前需要团队内约定。&lt;/p&gt;

&lt;p&gt;至于具体到达一个组件级别的时候，直接推荐使用 BEM 方式来维护。BEM 真心强大，虽然初识乱花渐欲迷人眼。BEM 后续再单独拆出来讲吧。&lt;/p&gt;

&lt;p&gt;来看一些代码的片段加强理解。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-css&#34;&gt;$orange: #fe7800;

@function Mpercentage($value){
    @return percentage($value/640);
}

// btn.css
.btn-full{
    display: inline-block;
    width: 100%; height: 48px; line-height: 48px;
    text-align: center; font-size: 1.8rem;
}
.btn-inline{
    display: inline-block;
    padding: 0 Mpercentage(60);
    height: 30px; line-height: 30px;
}
.btn-purple{
    color: #fff;
    background: #9a78c8;
}
.btn-white{
    color: #666;
    background: #fff;
}

// login.css
.login-form{
    font-size: 1.4rem;

    &amp;amp;__item{
        position: relative;
        margin-bottom: Mpercentage(20);
    }
    &amp;amp;__item_btn{
        margin-top: Mpercentage(30);
    }
    &amp;amp;__item_tips{
        line-height: 35px; font-size: 1.3rem;
        color: #666;
    }
    &amp;amp;__input{
        display: block;
        padding: 0 3%;
        width: 93%; height: 43px; line-height: 43px;
        font-size: 1.5rem;
        border: 1px solid #dadada;

        &amp;amp;:focus{
            border-color: #baacdf;
        }
        &amp;amp;.form-error{
            border-color: $orange;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;最后，通过函数、组件模块的抽离来实现页面的快速重组。这里其实蛮多都依赖到预处理器的特性了，从而使得 CSS 可以变得更加灵活。&lt;/p&gt;

&lt;p&gt;至此，主要概括起来就是通过文件与命名来解决冲突问题，通过预处理器来解决维护扩展问题。&lt;/p&gt;

&lt;p&gt;那么问题来了，你发现了上述中几个不能满足的场景了么？&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>挖一挖 submodule</title>
      <link>http://jyu213.github.io/blog/2016/07/02/%E6%8C%96%E4%B8%80%E6%8C%96-submodule/</link>
      <pubDate>Sat, 02 Jul 2016 14:26:44 +0800</pubDate>
      
      <guid>http://jyu213.github.io/blog/2016/07/02/%E6%8C%96%E4%B8%80%E6%8C%96-submodule/</guid>
      <description>

&lt;p&gt;在很长的一段时间内，对&lt;code&gt;submodule&lt;/code&gt;的概念含糊不清。特别是 &lt;code&gt;submodule&lt;/code&gt; 和 &lt;code&gt;subtree&lt;/code&gt; 这两个的区别。今天正好有时间来理一理。&lt;/p&gt;

&lt;h3 id=&#34;子模块-submodule&#34;&gt;子模块（submodule）&lt;/h3&gt;

&lt;p&gt;为了解决项目中的依赖问题。使得更加方便的维护与管理。子模块允许你将一个 Git         仓库作为另外一个 Git 仓库的子目录，从而保持相对独立的提交记录。&lt;/p&gt;

&lt;p&gt;子模块有点类似与一个软链。你记录他们当前确切所处的提交，但是不能记录一个子模块的 &lt;code&gt;master&lt;/code&gt; 或者其它符号的引用。在 &lt;code&gt;git&lt;/code&gt; 的存储信息中，&lt;code&gt;submodule&lt;/code&gt; 的属于 &lt;code&gt;160000&lt;/code&gt; 模式，这在Git中是一个特殊模式，基本意思是你将一个提交记录为一个目录项而不是子目录或者文件。&lt;/p&gt;

&lt;h4 id=&#34;用法&#34;&gt;用法&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;submodule&lt;/code&gt; 的使用还是挺方便的。&lt;code&gt;.gitmodules&lt;/code&gt; 文件保存着项目 URL 与已经拉取的本地目录之间的映射。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git submodule add&lt;/code&gt; 来增加新模块，&lt;code&gt;git submodule init&lt;/code&gt; 用于初始化，&lt;code&gt;git submodule update&lt;/code&gt; 用于更新，就是删除的时候不太方便。
而另外一个更新维护子模块的时候也有些繁琐，也常常会出一些坑。&lt;/p&gt;

&lt;h3 id=&#34;挖坑说明&#34;&gt;挖坑说明&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;当你 &lt;code&gt;pull master&lt;/code&gt; 之后，如果 &lt;code&gt;submodule&lt;/code&gt; 有变更，都需要记得&lt;code&gt;submodule update&lt;/code&gt;一下，不然又会提交旧的信息回去了。这本质上，都是因为它在主&lt;code&gt;master&lt;/code&gt;上都是已 &lt;code&gt;link&lt;/code&gt; 的方式存在。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;submodule&lt;/code&gt; 的时候也有点费劲的其实。当你进入 &lt;code&gt;submodule&lt;/code&gt; 的目录，其实不会切到任何分支，&lt;code&gt;HEAD&lt;/code&gt; 处于游离的状态，所以在改动之前需要 &lt;code&gt;checkout master&lt;/code&gt;，再来改动。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;subtree&#34;&gt;subtree&lt;/h3&gt;

&lt;p&gt;上面讲了这个多，其实官方推荐使用 &lt;code&gt;subtree&lt;/code&gt; 来代替 &lt;code&gt;submodule&lt;/code&gt;。两者的区分在于，&lt;code&gt;submodule&lt;/code&gt;是把一个 &lt;code&gt;commit&lt;/code&gt; 嵌入到当前项目的子目录中，只相当于一个 &lt;code&gt;Link&lt;/code&gt;，而 &lt;code&gt;subtree&lt;/code&gt; 是合并子项目到当前项目的子目录中，是一个完整项目的拷贝。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;subtree&lt;/code&gt; 除了命令长一点外，还是有挺多优点的。比如&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clone 的时候不需要 &lt;code&gt;init&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;没有类似的 &lt;code&gt;.gitmodule&lt;/code&gt; 文件&lt;/li&gt;
&lt;li&gt;管理上更加方便一些&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;用法-1&#34;&gt;用法&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;subtree&lt;/code&gt; 的使用相对复杂一些。这个依旧省略了各种操作的说明。具体翻看 API。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;关联：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git remote add -f &amp;lt;子仓库名&amp;gt; &amp;lt;子仓库地址&amp;gt;
git subtree add --prefix=&amp;lt;子目录名&amp;gt; &amp;lt;子仓库名&amp;gt; &amp;lt;分支&amp;gt; --squash
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;更新&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git fetch &amp;lt;远程仓库名&amp;gt; &amp;lt;分支&amp;gt;
git subtree pull --prefix=&amp;lt;子目录名&amp;gt; &amp;lt;远程分支&amp;gt; &amp;lt;分支&amp;gt; --squash
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;推送&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git subtree push --prefix=ai ai master
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;参考文献&#34;&gt;参考文献&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97&#34;&gt;Git 工具 - 子模块&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://git-scm.com/book/zh/v1/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A0%91%E5%90%88%E5%B9%B6&#34;&gt;Git 工具 - 子树合并&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://stackoverflow.com/questions/31769820/differences-between-git-submodule-and-subtree&#34;&gt;Difference between git submodule and subtree&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://alistra.ghost.io/2014/11/30/git-subtree-a-better-alternative-to-git-submodule/&#34;&gt;git subtree - a better alternative to git submodule&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>CSS哲学伪命题</title>
      <link>http://jyu213.github.io/blog/2016/02/24/css%E5%93%B2%E5%AD%A6%E4%BC%AA%E5%91%BD%E9%A2%98.html</link>
      <pubDate>Wed, 24 Feb 2016 00:43:23 +0800</pubDate>
      
      <guid>http://jyu213.github.io/blog/2016/02/24/css%E5%93%B2%E5%AD%A6%E4%BC%AA%E5%91%BD%E9%A2%98.html</guid>
      <description>

&lt;p&gt;标题党。这篇文章断断续续的修改过好几次，也没有满意，本来是想总结一下我这些零散的 CSS 知识结构，可能由于知识体系不全面，总是没能把知识点串联成一个通顺的内容。贴出来权当大家一起讨论下“前世今生”。文章后续可能会不定时更新。&lt;/p&gt;

&lt;p&gt;CSS 作为 Web 的基础部分，极其容易上手。但是 CSS 并不算的上是一门编程语言，在语言能力上略显薄弱，往往导致整体的维护性变差。但是这并没有使得大家停止对 CSS 的探索，从命名规范，目录架构，预处理器(如&lt;code&gt;SASS&lt;/code&gt;)，后处理器（&lt;code&gt;PostCSS&lt;/code&gt;），模块化等等的方向上，努力把 CSS 变得更好。&lt;/p&gt;

&lt;h3 id=&#34;关于自我历程&#34;&gt;关于自我历程&lt;/h3&gt;

&lt;p&gt;其实我自己并没有系统的学习过 CSS（虽然我现在也不知道如何系统的学习），看了几个视频，扫了下中文版的 API，然后就开始了切图生涯，很多的知识点也都是后来一些零散的博客中了解到的。这过程中，的的确确踩过不少的坑，有的填了，有的继续祸害着项目里其它的同学。也导致我在很长的时段时间里都是走在一个混乱无序的 CSS 书写当中。&lt;/p&gt;

&lt;p&gt;最早遇到的大概的是命名的问题了吧，因为本身积累的词汇量就少，动不动就没单词可用了。那个时候好像也就是网上列出一大堆像&lt;code&gt;menu&lt;/code&gt;， &lt;code&gt;siderbar&lt;/code&gt;之类的“命名大全”来模仿。再到后来接触到了 &lt;code&gt;Bootstrap&lt;/code&gt; 这种比较系统的框架（里面有好多可以值得借鉴的地方），而后又看到一些按类别划分文件，再配有特有的前缀的管理方式(那个时候还并不知道 &lt;code&gt;SMACSS&lt;/code&gt; 的名词)，还有一些原子化，把功能和样式分离等等的。在 &lt;code&gt;SASS&lt;/code&gt; 兴起的时候其实挺兴奋的，因为终于感觉有了点编程的能力，当然了，对变量，嵌套，&lt;code&gt;mixins&lt;/code&gt;等等的使用，很大程度上提高了编程效率。在后来同事的分享中，又了解了 BEM 的命名方式（初看很乱，了解后有一种豁然开然的感觉，细细回想起来，也就是大家约定一套共用的命名规范）。以及通过 &lt;code&gt;PostCSS&lt;/code&gt; 去实现 CSS 中一些自动处理的任务。在 React/ES6/Webpack 出现后，使得很大一部分程度上，CSS 写在 JS 中的方式也开始在特定的场合中频频出现。&lt;/p&gt;

&lt;p&gt;以上，通通出现过我的项目中，在项目切换维护的时候，那感觉，心如刀割。并不是说上面涉及到的知识点有对错的问题，只是在一个团队中，如果没有一些统一的架构和约定，往往到项目的后期会变得越来越不稳定。这不禁又让我想起了 CSS 的学习曲线（像PHP？又来黑了），样式大家都能写，能愉快的维护，又是另一个层次了。&lt;/p&gt;

&lt;p&gt;个人觉得 CSS 中有两个比较重要的点，&lt;strong&gt;语义化&lt;/strong&gt;和&lt;strong&gt;可维护性&lt;/strong&gt;，而最终都是为了提高开发的效率。&lt;/p&gt;

&lt;p&gt;语义化很大一部分程度上是为了阅读需要，简易明了。建议团队内还是要尽量的保持风格一致。其它的，可以看一下&lt;a href=&#34;http://www.tychio.net/tech/2015/03/14/thinking-in-semantic-css.html&#34;&gt;CSS语义思维&lt;/a&gt;的内容，这里不展开讲了。&lt;/p&gt;

&lt;p&gt;可维护性真的是一个很虚的概念，但是涉及到了多方面的各个点。比如，该怎么保持项目的简单性，灵活性，而同时又有足够的扩展能力？又比如如何抽取模块，是以功能划分还是以样式结构？如何重用样式？如何防止样式被覆盖，避免冗余代码等等。&lt;/p&gt;

&lt;p&gt;除了一次性的单页面这种外，一般项目类型的，都建议在开始的时候就搭好底层，统一一下整体风格与使用习惯，保持良好组织结构，命名规范，不然越往后面，可能会遇到更大的问题。&lt;/p&gt;

&lt;p&gt;比如，对文件做一个层次划分&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;基础框架（reset，iconfont，栅格）&lt;/li&gt;
&lt;li&gt;通用模块（原子，统一规范的模块）&lt;/li&gt;
&lt;li&gt;页面样式（继承通用模块）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;采用类似 &lt;code&gt;BEM/SUIT&lt;/code&gt; 等等的命名方式等等。&lt;/p&gt;

&lt;h3 id=&#34;现有的技术选择&#34;&gt;现有的技术选择&lt;/h3&gt;

&lt;p&gt;其实我们在平时应该或多或少的接触过一些 &lt;code&gt;SASS&lt;/code&gt;, &lt;code&gt;Compass&lt;/code&gt;, &lt;code&gt;BEM&lt;/code&gt;, &lt;code&gt;SMACSS&lt;/code&gt;, &lt;code&gt;OOCSS&lt;/code&gt; 的概念与设计模式。当然并没有一种解决方案是绝对的，合适当前的项目就可以了。&lt;/p&gt;

&lt;h4 id=&#34;bem&#34;&gt;BEM&lt;/h4&gt;

&lt;p&gt;用于解决项目命名规则问题。BEM 通过已&lt;code&gt;block(块)&lt;/code&gt;，&lt;code&gt;element(元素)&lt;/code&gt;，&lt;code&gt;modifier(修饰符)&lt;/code&gt; 的概念，使用连接符串联父级块作为前缀，来实现功能模块命名的唯一性。有兴趣的同学可以看一下 &lt;a href=&#34;http://www.w3cplus.com/css/the-history-of-the-bem-methodology.html&#34;&gt;BEM的进化史&lt;/a&gt;。发现一句话并不太好表述清楚，想要具体了解的同学可以移步&lt;a href=&#34;https://en.bem.info/&#34;&gt;官网&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BEM&lt;/code&gt; 这种唯一性以及元素间的平级展开，往往在稍微复杂一点的项目里，就会把名字命名的很长很长。目前也有很多是在 &lt;code&gt;BEM&lt;/code&gt; 的基础上衍生出来的一些方式(如 &lt;code&gt;SUIT&lt;/code&gt;)。&lt;/p&gt;

&lt;h4 id=&#34;oocss-object-oriented-css&#34;&gt;OOCSS （Object Oriented CSS）&lt;/h4&gt;

&lt;p&gt;面向对象 CSS。是一种已面向对象的维护方式去管理组织 CSS 代码。其哲学理念是模块化，功能单一性，关注点分离。&lt;/p&gt;

&lt;p&gt;OOCSS 中有两个重要的原则&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;结构和外观分离。样式尽量独立，和 DOM 无关&lt;/li&gt;
&lt;li&gt;容器和内容分离。CSS 只关注内容&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;OOCSS&lt;/code&gt; 与 &lt;code&gt;SASS&lt;/code&gt; 结合是一个不错的选择，充分强大。&lt;/p&gt;

&lt;h4 id=&#34;smacss-scalable-and-modular-architecture-for-css&#34;&gt;SMACSS(Scalable and Modular Architecture for CSS)&lt;/h4&gt;

&lt;p&gt;可扩展和模块化 CSS。
把 CSS 样式划分为若干个不同类别的文件，如基础，布局，模块，主题等等。在加上一些特有前缀的组合。&lt;/p&gt;

&lt;h4 id=&#34;acss-atomic-css&#34;&gt;ACSS (Atomic CSS)&lt;/h4&gt;

&lt;p&gt;原子化 CSS。遵循关注点分离原则。&lt;/p&gt;

&lt;h3 id=&#34;css-模块化&#34;&gt;CSS 模块化&lt;/h3&gt;

&lt;p&gt;随着 &lt;code&gt;React&lt;/code&gt; 的迅速引爆，其它关于 CSS 的另一种使用方式也在兴起。将样式在 JS 中定义。借助 &lt;code&gt;require/import&lt;/code&gt; 而解决了 CSS 中的命名空间的问题，使得单文件变得简单清晰。而通过组合，也可以实现快速的重复利用。甚至有些 CSS 可以单独与组件去绑定。&lt;/p&gt;

&lt;p&gt;以及其它的一些方式。上述的方式，是比较让我眼前一亮的感觉。&lt;/p&gt;

&lt;h3 id=&#34;未来走向&#34;&gt;未来走向&lt;/h3&gt;

&lt;p&gt;待补充&amp;hellip;&lt;/p&gt;

&lt;h3 id=&#34;扩展阅读&#34;&gt;扩展阅读&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://glenmaddern.com/articles/css-modules&#34;&gt;CSS模块&lt;/a&gt;&lt;a href=&#34;http://www.w3cplus.com/css/css-modules.html&#34;&gt;(中文翻译版)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://aliceui.org/docs/rule.html&#34;&gt;CSS 规范和最佳实践&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.w3cplus.com/css/the-history-of-the-bem-methodology.html&#34;&gt;BEM 进化史&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.zhihu.com/question/21943416&#34;&gt;如何理解 CSS 类名语义化&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.w3cplus.com/css/css-layers.html&#34;&gt;CSS 分层&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Rollup 试炼之路</title>
      <link>http://jyu213.github.io/blog/2016/01/14/rollup-%E8%AF%95%E7%82%BC%E4%B9%8B%E8%B7%AF/</link>
      <pubDate>Thu, 14 Jan 2016 00:00:00 +0000</pubDate>
      
      <guid>http://jyu213.github.io/blog/2016/01/14/rollup-%E8%AF%95%E7%82%BC%E4%B9%8B%E8%B7%AF/</guid>
      <description>

&lt;p&gt;最近看到挺多次 Rollup 这个词，再也架不住好奇，简单的学习实践了一下。&lt;a href=&#34;https://github.com/jyu213/rollup-demo&#34;&gt;完整项目库地址请戳&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;PS: ES6 对应 ES2015，请忽略这些细节。&lt;/p&gt;

&lt;h3 id=&#34;什么是-rollup&#34;&gt;什么是 Rollup&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/rollup/rollup&#34;&gt;Rollup Github 地址&lt;/a&gt;。根据官网的解释，Rollup 是下一代 ES6 模块化工具。ES6 之后，模块化的写法将更加的趋势化，我们会将以前的文件切割成多个的细小模块。那么如何来高效的组织管理这些文件，又有了很多不同的方案。现有的模块化打包已经有如
&lt;code&gt;Browserify&lt;/code&gt; 和 &lt;code&gt;Webpack&lt;/code&gt; ，那为啥还需要一个新的呢？&lt;/p&gt;

&lt;h3 id=&#34;优势在哪&#34;&gt;优势在哪&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;可以生成 AMD，CMD，UMD 甚至 ES6 模块文件。&lt;/li&gt;
&lt;li&gt;Tree-shaking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;tree-shaking&lt;/code&gt;(有知道中文怎么翻译的同学欢迎留言告知一下)，大致意思就是打包的时候会移除未使用到的 ES6 &lt;code&gt;exports&lt;/code&gt;模块。想要更深入的了解 &lt;code&gt;tree-shaking&lt;/code&gt; 的话，可以看下博士的这篇文章&lt;a href=&#34;http://www.2ality.com/2015/12/webpack-tree-shaking.html&#34;&gt;Tree-shaking with webpack 2 and Babel 6&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;话题转回来，Rollup 正是使用了 ES6 的模块特性，所以会使打包后的文件体积更小。如果是 CommonJS 的则需要先通过插件转为 ES6 后处理。&lt;/p&gt;

&lt;p&gt;对了，值得多说一句的是，Rollup 打包后的代码没有 &lt;code&gt;require&lt;/code&gt;，&lt;code&gt;import&lt;/code&gt;的，而是直接插入到文件中。&lt;/p&gt;

&lt;h3 id=&#34;如何引用&#34;&gt;如何引用&lt;/h3&gt;

&lt;p&gt;Rollup 支持 CLI 和 JS API 方式，同时提供了一些插件如解决压缩 babel 转换等问题。(PS: 此处讲解采用 API 的方式)&lt;/p&gt;

&lt;p&gt;首先在项目根目录创建 &lt;code&gt;rollup.js&lt;/code&gt; 文件，安装 &lt;code&gt;npm&lt;/code&gt; 的相关依赖&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;var rollup = require(&#39;rollup&#39;);
var babel = require(&#39;rollup-plugin-babel&#39;);
var uglify = require(&#39;rollup-plugin-uglify&#39;);

rollup.rollup({
    entry: &#39;src/index.js&#39;,
    plugins: [
        babel({
            exclude: &#39;node_modules/**&#39;,
            presets: [ &amp;quot;es2015-rollup&amp;quot; ]
        }),
        uglify()
    ]
}).then(function(bundle) {
    bundle.write({
        // output format - &#39;amd&#39;, &#39;cjs&#39;, &#39;es6&#39;, &#39;iife&#39;, &#39;umd&#39;
        format: &#39;umd&#39;,
        moduleName: &#39;dqSystem&#39;,
        sourceMap: true,
        dest: &#39;dqSystem.js&#39;
    });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;rollup&lt;/code&gt; 方法可以配置一些入口文件，依赖插件等，返回的是 &lt;code&gt;bundle&lt;/code&gt; 的 &lt;code&gt;Promise&lt;/code&gt; 方法。&lt;code&gt;bundle&lt;/code&gt; 方法中可以配置文件相关参数，同时也可以生成多份版本文件。具体的 API &lt;a href=&#34;https://github.com/rollup/rollup/wiki/JavaScript-API&#34;&gt;参考官网&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;使用 &lt;code&gt;node rollup.js&lt;/code&gt; 执行打包。另外 Rollup 好像还不支持 &lt;code&gt;watch&lt;/code&gt; 的配置，我采用了 npm-watch 的方式跳过了。&lt;/p&gt;

&lt;h3 id=&#34;采过的坑&#34;&gt;采过的坑&lt;/h3&gt;

&lt;p&gt;试用时间不长，且内容比较简单，可能没碰到一些奇怪的点&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rollup.js 中可以 &lt;code&gt;catch&lt;/code&gt; 下 &lt;code&gt;error&lt;/code&gt; 方便调试错误&lt;/li&gt;
&lt;li&gt;UMD/IIFE 模式中需要&lt;code&gt;moduleName&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Rollup 的模块引用只支持 ES6 Module，其他的需要采用 &lt;code&gt;npm&lt;/code&gt; 和 &lt;code&gt;commonjs&lt;/code&gt; 的插件去解决&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;自己yy下&#34;&gt;自己YY下&lt;/h3&gt;

&lt;p&gt;不知道拿 Rollup 和 webpack 相比合不合适。我个人还是挺喜欢 webpack 的打包方式的，关键是功能强大，不过相比，配置也巨复杂。而 Rollup 的配置就简单很多了。实验的项目文件不大，所以没看出来两者在压缩体积上是否有明显的差异。Rollup 的&lt;code&gt;tree-shaking&lt;/code&gt;也将会在 webpack2 中支持。所以好像并没有什么一定非它不可的感觉。&lt;/p&gt;

&lt;p&gt;套用朋友说的一句话，“任何产品的生命周期都得看社区的活跃程度”。从 github 的 fock 人数上，还是持有很大的保留意见的，所有我个人可能会在一些小型或者快速项目中做尝试而已。&lt;/p&gt;

&lt;h3 id=&#34;参考文章&#34;&gt;参考文章&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/rollup/rollup&#34;&gt;Rollup Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.2ality.com/2015/12/webpack-tree-shaking.html&#34;&gt;Tree-shaking with webpack 2 and Babel 6&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>ES6 - 字符串模板</title>
      <link>http://jyu213.github.io/blog/2015/12/14/es6---%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%A8%A1%E6%9D%BF/</link>
      <pubDate>Mon, 14 Dec 2015 00:00:00 +0000</pubDate>
      
      <guid>http://jyu213.github.io/blog/2015/12/14/es6---%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%A8%A1%E6%9D%BF/</guid>
      <description>

&lt;h2 id=&#34;es6-字符串模板&#34;&gt;ES6 - 字符串模板&lt;/h2&gt;

&lt;h3 id=&#34;写在前面&#34;&gt;写在前面&lt;/h3&gt;

&lt;p&gt;关于 ES6, 也终于在 2015 年的 7 月 18 号尘埃落定了。虽然说各大浏览器还没有全面的支持，不过这并不妨碍我们一颗想要撸一把的心。在后端，可以使用 Node.js(0.12+)或 io.js, 前端的话，也可以使用&lt;a href=&#34;http://babeljs.io/&#34;&gt;Babel&lt;/a&gt; 或&lt;a href=&#34;https://github.com/google/traceur-compiler#what-is-traceur&#34;&gt;Traceur&lt;/a&gt; 进行语法预转义成 ES5使用 。&lt;/p&gt;

&lt;p&gt;关于该系列（不知道能不能成为一个系列，总是各种懒），会没有规律的挑选一些内容来学习。欢迎大家积极纠错，留言探讨。&lt;/p&gt;

&lt;h3 id=&#34;模板字符串-template-strings&#34;&gt;模板字符串(template strings)&lt;/h3&gt;

&lt;p&gt;ES6 中引进的一种新型的字符串字面量语法 - 模板字符串。书面上来解释，模板字符串是一种能在字符串文本中内嵌表示式的字符串字面量。简单来讲，就是增加了变量功能的字符串。&lt;/p&gt;

&lt;p&gt;先来看一下以前我们对字符串的使用：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    ```
    /**
     * Before ES6 字符串拼接
     */
    var name = &#39;丁香医生&#39;;
    var desc = &#39;丁香医生是面向大众的科普性健康类网站&#39;;
    var html = function(name, desc){
        var tpl = &#39;公司名：&#39; + name + &#39;\n&#39;+
                &#39;简介：&#39;+ desc;
        return tpl;
    }
    ```
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;而现在：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    ```
    var html = `公司名：${name}
        简介：${desc}`;
    ```
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;很简洁吧。
引一段 MDN 对于模板字符串的定义：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    模板字符串使用反引号 (` `) 来代替普通字符串中的用双引号和单引号。模板字符串可以包含特定语法(${expression})的占位符。占位符中的表达式和周围的文本会一起传递给一个默认函数，该函数负责将所有的部分连接起来。
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;而占位符&lt;code&gt;${}&lt;/code&gt;，可以是任意的 js 表达式（函数或者运算），甚至是另一个模板字符串，会将其计算的结果作为字符串输出。如果模板中需要使用&lt;code&gt;$,{&lt;/code&gt;等字符串，则需要进行转义。&lt;/p&gt;

&lt;p&gt;看个例子就明白了。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    ```
    var x = 1;
    var y = 2;
    `${ x } + ${ y } = ${ x + y}`  // &amp;quot;1 + 2 = 3&amp;quot;
    ```
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;不同于普通字符串，模板字符串还可以多行书写，模板字符串中所有的空格，新行，缩进都会原样的输出在生成的字符串中。&lt;/p&gt;

&lt;p&gt;而单纯的模板字符串还存在着很多的局限性。如：
* 不能自动转义特殊的字符串。（这样很容易引起注入攻击）
* 不能很好的和国际化库配合（即不会格式化特定语言的数字，日期，文字等）
* 没有内建循环语法，（甚至连条件语句都不支持， 只可以使用模板套构的方法）&lt;/p&gt;

&lt;h3 id=&#34;标签模板-tagged-template&#34;&gt;标签模板(tagged template)&lt;/h3&gt;

&lt;p&gt;为此，引出了标签模板的概念。标签模板则是在反引号前面引入一个标签（tag）。该标签是一个函数，用于处于定制化模板字符串后返回值。就拿上面对特殊字符串举例。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    ```
    /**
     * HTML 标签转义
     * @param {Array.&amp;lt;DOMString&amp;gt;} templateData 字符串类型的tokens
     * @param {...} ..vals 表达式占位符的运算结果tokens
     *
     */
    function SaferHTML(templateData) {
      var s = templateData[0];
      for (var i = 1; i &amp;lt; arguments.length; i++) {
        var arg = String(arguments[i]);
        // Escape special characters in the substitution.
        s += arg.replace(/&amp;amp;/g, &amp;quot;&amp;amp;amp;&amp;quot;)
                .replace(/&amp;lt;/g, &amp;quot;&amp;amp;lt;&amp;quot;)
                .replace(/&amp;gt;/g, &amp;quot;&amp;amp;gt;&amp;quot;);
        // Don&#39;t escape special characters in the template.
        s += templateData[i];
      }
      return s;
    }
    // 调用
    var html = SaferHTML`&amp;lt;p&amp;gt;这是关于字符串模板的介绍&amp;lt;/p&amp;gt;`;
    ```
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;标签函数会接收多个参数。
* 第一个参数是包含了字符串字面量(即那些没有变量替换的值)的数组
* 后面的参数是已经替换后的变量值&lt;/p&gt;

&lt;p&gt;改一下例子1&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    ```
    var name = &#39;丁香医生&#39;;
    var desc = &#39;丁香医生是面向大众的科普性健康类网站&#39;;
    tag`公司名：${name}简介：${desc}`
    ```
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;tag 的参数则分别为 [&amp;lsquo;公司名：&amp;rsquo;,&amp;lsquo;简介：&amp;rsquo;], &amp;lsquo;丁香医生&amp;rsquo;, &amp;lsquo;丁香医生是面向大众的科普性健康类网站&amp;rsquo;。&lt;/p&gt;

&lt;p&gt;有了此类方法，就大大的增加了控制的权利。如上面说的国际化库甚至循环语句。&lt;/p&gt;

&lt;h3 id=&#34;浏览器兼容性&#34;&gt;浏览器兼容性&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;服务器端， io.js 支持&lt;/li&gt;
&lt;li&gt;浏览器端， FF34+ , chrome 41+&lt;/li&gt;
&lt;li&gt;移动端 IOS 8, Android 4.4&lt;/li&gt;
&lt;li&gt;IE Tech Preview&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;扩展阅读&#34;&gt;扩展阅读&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://es6.ruanyifeng.com/#docs/string&#34;&gt;ECMAScript 6 入门&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://developers.google.com/web/updates/2015/01/ES6-Template-Strings&#34;&gt;Getting Literal With ES6 Template Strings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.2ality.com/2015/01/template-strings-html.html&#34;&gt;HTML templating with ES6 template strings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/template_strings&#34;&gt;模板字符串 - MDN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://segmentfault.com/a/1190000002950341&#34;&gt;ES6 Features系列：Template Strings &amp;amp; Tagged Template Strings&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>ES6 - 解构赋值</title>
      <link>http://jyu213.github.io/blog/2015/12/14/es6---%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC/</link>
      <pubDate>Mon, 14 Dec 2015 00:00:00 +0000</pubDate>
      
      <guid>http://jyu213.github.io/blog/2015/12/14/es6---%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC/</guid>
      <description>

&lt;p&gt;在解释什么是解构赋值前，我们先来看一下， ES5 中对变量的声明和赋值。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;var str = &#39;hello word&#39;;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;左边一个变量名，右边可以是字符串，数组或对象。&lt;/p&gt;

&lt;p&gt;ES6 中增加了一种更为便捷的赋值方式。称为 &lt;strong&gt;Destructuring&lt;/strong&gt; 。好像大家普遍翻译为解构。解构赋值允许我们将数组或对象的属性赋予给任何变量，该变量的定义语法与数组字面量或对象字面量很相似。举个例子可以直观的说明。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;let [speak, name] = [&#39;hello&#39;, &#39;destructuring&#39;];
console.log( speak + &#39; &#39; + name ); // hello destructuring
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;数组的解构赋值&#34;&gt;数组的解构赋值&lt;/h3&gt;

&lt;p&gt;用更加直白的话来描述就是，等号两边保持相同的形式（数组对应数组，对象对应对象），则左边的变量就会被赋予对应的值。如果对应的右边值缺失，缺失部分变量值为 &lt;code&gt;undefined&lt;/code&gt; ,如果右边值多余，依旧能够正常解构。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;// ES6 中
let arr = [1,2,3,4,5];
let [el1, el2] = [arr];
// 或者
let [el1, el2] = [1,2,3,4,5];
// el1 =&amp;gt; 1, el2 =&amp;gt; 2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;解构赋值也是可嵌套的：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;let value = [1, 2, [3, 4, 5]];
let [el1, el2, [el3, el4]] = value;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;同样可以通过简单地在指定位置省略变量来忽略数组中的某个元素：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;let value = [1, 2, 3, 4, 5];
let [el1, , el3, , el5] = value;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;更进一步，默认值同样也可以被指定：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;let [firstName = &amp;quot;John&amp;quot;, lastName = &amp;quot;Doe&amp;quot;] = [];
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;ES6中，提供了一种将右侧多余的值以数组的形式赋值给左侧变量的语法——“rest“模式：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;let [head, ...tail] = [1, 2, 3, 4];
console.log(tail);  // [2, 3, 4]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;当默认值不存在，变量值就等于 &lt;code&gt;undefined&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;let [missing] = [];
console.log(missing);  // undefined
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里的数组，指的是部署了 &lt;code&gt;[Iterator](http://www.2ality.com/2015/02/es6-iteration.html)&lt;/code&gt; 接口的数据结构。&lt;/p&gt;

&lt;h3 id=&#34;对象的解构赋值&#34;&gt;对象的解构赋值&lt;/h3&gt;

&lt;p&gt;和数组的用法相类似，一个主要的不同点是，对象是无次序排列的，所以变量必须和属性名相同。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;let person = {firstName: &amp;quot;John&amp;quot;, lastName: &amp;quot;Doe&amp;quot;};
let {firstName, lastName} = person;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;解构另一个特性是，变量 keys 可以使用&lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names&#34;&gt;计算后的属性名&lt;/a&gt;，但是如果你对这容易混淆的话，不建议使用。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;let person = {firstName: &amp;quot;John&amp;quot;, lastName: &amp;quot;Doe&amp;quot;};
let {firstName: name, lastName} = person;
// `name`变量将会被声明为 `person.firstName` 的值
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;函数参数的解构赋值&#34;&gt;函数参数的解构赋值&lt;/h3&gt;

&lt;p&gt;函数的参数也可以解构赋值。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;function add({x: 0, y: 0}){
    return x+y;
}
add({1,2}); // 3
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;null-和-undefined&#34;&gt;null 和 undefined&lt;/h3&gt;

&lt;p&gt;当尝试解构 &lt;code&gt;null&lt;/code&gt; 和 &lt;code&gt;undefined&lt;/code&gt; 的时候会报错。这是因为使用对象赋值模式时，被解构的值必需能够转换成一个对象（object）。大多数的类型都可以转换为一个对象，但null和undefined却并不能被转换。&lt;/p&gt;

&lt;h3 id=&#34;其它&#34;&gt;其它&lt;/h3&gt;

&lt;p&gt;解构赋值的好处有很多，比如&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;两个值的交换&lt;/li&gt;
&lt;li&gt;函数参数默认值&lt;/li&gt;
&lt;li&gt;函数返回值&lt;/li&gt;
&lt;li&gt;正则匹配的返回值&lt;/li&gt;
&lt;li&gt;快速处理 JSON 数据&lt;/li&gt;
&lt;li&gt;遍历Map结构&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ES6 的解构赋值给 JS 的书写带来了很大的便利性，同时也提高了代码的可读性。但是也需要注意一些问题，避免适得其反。
* 关于圆括号的问题，欢迎翻看&lt;a href=&#34;http://es6.ruanyifeng.com/#docs/destructuring#圆括号问题&#34;&gt;阮一峰老师的博客&lt;/a&gt;
* 解构的嵌套尽量不要太深
* 函数有多个返回值时，尽量使用对象解构而不用数组解构，避免出现顺序对应问题
* 已声明过的变量不能用于解构&lt;/p&gt;

&lt;h3 id=&#34;浏览器支持&#34;&gt;浏览器支持&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;http://kangax.github.io/compat-table/es6/#destructuring&#34;&gt;http://kangax.github.io/compat-table/es6/#destructuring&lt;/a&gt;
不完全统计：
* IE NO
* FF 38+ (大部分)
* CH/OP NO
* Webkit
* SF 9+, 8部分
* IOS8 部分&lt;/p&gt;

&lt;p&gt;PS: 整理的时候发现以前还保留着这样一份文章，无新，基本参考下述文章内容。仅供学习。&lt;/p&gt;

&lt;h3 id=&#34;参考文章&#34;&gt;参考文章&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://es6.ruanyifeng.com/#docs/destructuring&#34;&gt;变量的解构赋值 - 阮一峰&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://hacks.mozilla.org/2015/05/es6-in-depth-destructuring/&#34;&gt;ES6 In Depth: Destructuring&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://strongloop.com/strongblog/getting-started-with-javascript-es6-destructuring/&#34;&gt;Getting Started with JavaScript ES6 Destructuring&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>跨域那些事</title>
      <link>http://jyu213.github.io/blog/2014/11/30/%E8%B7%A8%E5%9F%9F%E9%82%A3%E4%BA%9B%E4%BA%8B/</link>
      <pubDate>Sun, 30 Nov 2014 00:00:00 +0000</pubDate>
      
      <guid>http://jyu213.github.io/blog/2014/11/30/%E8%B7%A8%E5%9F%9F%E9%82%A3%E4%BA%9B%E4%BA%8B/</guid>
      <description>

&lt;h3 id=&#34;同源策略&#34;&gt;同源策略&lt;/h3&gt;

&lt;p&gt;javascript 语言在设计之初为了安全考虑，不允许调用其它页面的对象。 跨域是由 javascript 语言安全限制中的同源策略造成的。
&lt;strong&gt;同源策略&lt;/strong&gt;指的是，一段脚本只能读取来自同一来源的窗口和文档的属性，(同一来源指的是&lt;strong&gt;域名&lt;/strong&gt;、&lt;strong&gt;协议&lt;/strong&gt;和&lt;strong&gt;端口号&lt;/strong&gt;的组合)
简单来讲，即不允许同一域名下的不同端口号，不同协议（http,https），不用子域名（www.dxy.cn 和 app.dxy.cn）及域名和域名对应的 ip 也不允许。&lt;/p&gt;

&lt;h3 id=&#34;解决跨域的原理&#34;&gt;解决跨域的原理&lt;/h3&gt;

&lt;p&gt;HTML 中，静态资源是没有跨域限制的。在 HTML DOM 中，script 标签是可以跨域访问服务器上的数据的。所以我们可以手动插入 script 标签等方法来伪造。 不过，有个限制是，服务器返回 内容不能单纯为一个 json 字符串，可定变量或函数实现，如: &lt;code&gt;var json = {&amp;quot;type&amp;quot;:&amp;quot;json&amp;quot;}&lt;/code&gt; 或 &lt;code&gt;json({&amp;quot;type&amp;quot;:&amp;quot;json&amp;quot;})&lt;/code&gt;。jsonp 即采用后者形式。&lt;/p&gt;

&lt;h3 id=&#34;解决方案&#34;&gt;解决方案&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;手动插入&lt;code&gt;script&lt;/code&gt;标签的形式。&lt;/li&gt;
&lt;li&gt;jsonp
&amp;hellip;
它能对老的浏览器也保持支持。 但是，只支持 get 不支持 post 等其它类型的 HTTP 请求。&lt;/li&gt;

&lt;li&gt;&lt;p&gt;跨域资源共享（CORS）
使用自定义的 HTTP 头部让浏览器与服务器进行沟通，从而决定请求的成功或者失败。
服务器端对于 CORS 的支持，主要通过 &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; 进行&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var xhr = new XMLHttpRequest();
xhr.open(&#39;get&#39;, &#39;/xx&#39;, true);
xhr.send();
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;iframe + domain
对于主域相同而子域不同，则可以只用 document.domain 来实现跨域。&lt;/p&gt;

&lt;p&gt;e.g. 在 &lt;code&gt;http://a.com/test.html&lt;/code&gt; 和 &lt;code&gt;http://sub.a.com/test2.html&lt;/code&gt; 中分别加上 &lt;code&gt;document.domain = a.com&lt;/code&gt;，然后 test.html 页面中创建 iframe 来控制iframe的内容文档。&lt;/p&gt;

&lt;p&gt;注意的是：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;domain 指向的是主域。 （如 a.com ， www.a.com 其实是二级域名）&lt;/li&gt;
&lt;li&gt;document.domain 需设置为自身或更高一级的父域&lt;/li&gt;
&lt;li&gt;浏览器限制2 为，不同域的框架之间是不能进行 js 的交互的(可取到 window对象，但取不到 window 对象的属性和方法,PS: html5中的 postMessage 例外)。&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;window.name
&lt;code&gt;window.name&lt;/code&gt; 值在不同页面（包括不同域下）加载后依旧存在(当然关闭窗口后就销毁了)。注意的是，window.name 由大小限制，一般为2M。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;HTML5 window.postMessage&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;隐藏 form, target 指向一个隐藏的 iframe&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>DPI 和 PPI</title>
      <link>http://jyu213.github.io/blog/2014/09/08/dpi-%E5%92%8C-ppi/</link>
      <pubDate>Mon, 08 Sep 2014 00:00:00 +0000</pubDate>
      
      <guid>http://jyu213.github.io/blog/2014/09/08/dpi-%E5%92%8C-ppi/</guid>
      <description>

&lt;p&gt;本文所涉及的内容在网上已有很多介绍。可相互借鉴。笔者仅为整理知识体系所用。&lt;/p&gt;

&lt;h3 id=&#34;ppi-pixel-per-inch&#34;&gt;PPI（Pixel Per Inch）&lt;/h3&gt;

&lt;p&gt;图像分辨率所使用的单位。在图像中每英寸所表达的像素数目。&lt;/p&gt;

&lt;h3 id=&#34;dpi-dot-per-inch&#34;&gt;DPI（Dot Per Inch）&lt;/h3&gt;

&lt;p&gt;打印分辨率使用的单位。每英寸所表达的打印点数。&lt;/p&gt;

&lt;h3 id=&#34;像素-pixel&#34;&gt;像素（Pixel）&lt;/h3&gt;

&lt;p&gt;一种用来计算数码影像的单位。&lt;/p&gt;

&lt;h3 id=&#34;分辨率&#34;&gt;分辨率&lt;/h3&gt;

&lt;p&gt;单位长度中，所表达或撷取的像素数目。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DPI用来表示输出设备的输出精度，如打印机，显示器&lt;/li&gt;
&lt;li&gt;DPI表示的是 像点/英寸（每英寸长度上有多少个打印点或像点）&lt;/li&gt;
&lt;li&gt;PPI用来表示输入设备的输入精度，如扫描仪，数码相机&lt;/li&gt;
&lt;li&gt;PPI表示的是　像素/英寸（每英寸长度上有多少个像素）&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;参考资料&#34;&gt;参考资料&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://sebastien-gabriel.com/designers-guide-to-dpi/home&#34;&gt;Designer&amp;rsquo;s guide to DPI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.zhihu.com/question/21220154&#34;&gt;DPI、PPI、DP、PX 的详细计算方法 - 知乎&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>主流CSS image比较</title>
      <link>http://jyu213.github.io/blog/2014/08/29/%E4%B8%BB%E6%B5%81css-image%E6%AF%94%E8%BE%83/</link>
      <pubDate>Fri, 29 Aug 2014 00:00:00 +0000</pubDate>
      
      <guid>http://jyu213.github.io/blog/2014/08/29/%E4%B8%BB%E6%B5%81css-image%E6%AF%94%E8%BE%83/</guid>
      <description>

&lt;p&gt;在还原设计图的时候，难免会碰到一些样式图片的引用。如何来对这些图片做优化呢？本文简单的梳理了一下目前几种比较常用的使用方式。
注：
1. 有更好的方法的话，欢迎补充。
2. 下文未对性能问题做真实的测试，请保持一颗好奇的心，并告诉我们）&lt;/p&gt;

&lt;h3 id=&#34;css-sprite&#34;&gt;CSS Sprite&lt;/h3&gt;

&lt;p&gt;这是目前使用比较多的方式。也是我个人认为相对最优的一种解决方式。当然，这里的最优指的是特定环境。比如移动客户端，就不一定要这么干。CSS Sprite 是将页面中所使用到的小图片整合到一张大图上去。大家都知道，客户端向服务器发送请求是很有代价的，特别是在移动端，所以，sprite 的提出是为了减少 http 请求数，从而加快页面加载速度。&lt;/p&gt;

&lt;h4 id=&#34;使用方式&#34;&gt;使用方式&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;先将小图片整合到一张大图上&lt;/li&gt;
&lt;li&gt;css 引入背景图片&lt;/li&gt;
&lt;li&gt;然后依据图标的位置使用 background-position 进行定位&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;使用技巧&#34;&gt;使用技巧&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;切图的时候就构思拼接好图片（不然后期抓心挠肺的，当然，善用工具的出门右转）&lt;/li&gt;
&lt;li&gt;排序有序，便于后期维护(个人建议图标从上到下排列)。有利于 background-position 定位&lt;/li&gt;
&lt;li&gt;定位时避免使用 right, bottom 等（后期图片尺寸变化后就不一定了好不）&lt;/li&gt;
&lt;li&gt;合理预留空白位置（空太多文件变大，太小引起图标重叠）&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;优点&#34;&gt;优点&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;减少 http 请求。（这个是最大的优点）&lt;/li&gt;
&lt;li&gt;对你存在的图片一目了然（不知道这个算不算，如改进版3.0拿到的图哪些图标是之前已存在不需要重新切了的）&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;缺点&#34;&gt;缺点&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;图片合并定位费时费力（谁用谁知道啊）&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;其它&#34;&gt;其它&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;github 上有个 &lt;a href=&#34;https://github.com/Ensighten/grunt-spritesmith&#34;&gt;grunt 合并 sprite&lt;/a&gt; 的组件，可以看看&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;image-data-uri&#34;&gt;image data URI&lt;/h3&gt;

&lt;p&gt;即将图片资源转换为 base64 字符串格式嵌到页面或样式中。这样连图片的请求链接都省了。
如：&lt;/p&gt;

&lt;h4 id=&#34;使用方式-1&#34;&gt;使用方式&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;    /** 数据格式 **/
    data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAE1JREFUKJHV0MEOwCAIA9DW7MP983pymUaweluv8IAABJFUJdWonqEeD0/IwwHK8QatsYlGfIhezM9WOc8jSQAoTvMqTzY1u+Z6449gA9r24D4iZ6wwAAAAAElFTkSuQmCC

    /** 样式引用 **/
    .icon{
      width: 30px; height: 30px;
      background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAE1JREFUKJHV0MEOwCAIA9DW7MP983pymUaweluv8IAABJFUJdWonqEeD0/IwwHK8QatsYlGfIhezM9WOc8jSQAoTvMqTzY1u+Z6449gA9r24D4iZ6wwAAAAAElFTkSuQmCC);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;标签语法&#34;&gt;标签语法：&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;data : 取得数据协议&lt;/li&gt;
&lt;li&gt;image/png : 取得数据的协议名称（注意这里也图片资源也可以使用字体等）&lt;/li&gt;
&lt;li&gt;base64 : 数据编码方式&lt;/li&gt;
&lt;li&gt;iVBOR&amp;hellip; : 编码后数据&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&#34;http://baike.baidu.com/view/469071.htm&#34;&gt;Base64编码&lt;/a&gt; 自行百度科普吧。&lt;/p&gt;

&lt;h4 id=&#34;优点-1&#34;&gt;优点&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;减少 HTTP 请求&lt;/li&gt;
&lt;li&gt;避免某些文件跨域&lt;/li&gt;
&lt;li&gt;无图片缓存等问题(但是一般 css 也是有缓存的好不好)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;缺点-1&#34;&gt;缺点&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;兼容性 （ IE6,7 不兼容, 可以使用 MHTML 来解决 ）&lt;/li&gt;
&lt;li&gt;浏览器不会缓存该图片（这里是否是这样我存有疑惑，因为好像看上去也是第一次加载的时候慢）&lt;/li&gt;
&lt;li&gt;增加 css 文件大小&lt;/li&gt;
&lt;li&gt;编码成本及维护(展示不直观，目前需手动转换，我暂时不知道自动替换之类的插件)&lt;/li&gt;
&lt;li&gt;之前有看到过篇测评说性能上比 sprite 微弱一些，一时间找不到链接&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;综合起来，data URI可以使用在
* 图片尺寸很小，使用一条 http 请求有点浪费，如渐变背景框
* 图片在全站大规模使用，且很少被更新的，如 loading 图&lt;/p&gt;

&lt;h4 id=&#34;在线转换工具&#34;&gt;在线转换工具&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.pjhome.net/web/html5/encodeDataUrl.htm&#34;&gt;Encode Data URL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://websemantics.co.uk/online_tools/image_to_data_uri_convertor/&#34;&gt;image to data URI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&#34;更新&#34;&gt;更新&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/medium/sus&#34;&gt;github 资源 sus 可转换 data URI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;参考资料&#34;&gt;参考资料&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/data_URIs&#34;&gt;MDN - data URIs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;icon-fonts&#34;&gt;icon fonts&lt;/h3&gt;

&lt;p&gt;由于移动端设备拥有不同分辨率，PPI 等引起的问题， 常常需要针对不同屏幕分辨率来调整优化，如使用 &lt;code&gt;@2x&lt;/code&gt; 图片， &lt;code&gt;max-width&lt;/code&gt; 限制等。
采用 css @font-face 用来显示 icon 也不失为一种好办法。
因为 icon fonts (字体)是矢量图形，所以不受分辨率的影响，同时可以做到完美缩放；当然，也可使用在 WEB 端。&lt;/p&gt;

&lt;h4 id=&#34;优点-2&#34;&gt;优点&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;文件小&lt;/li&gt;
&lt;li&gt;加载性能好&lt;/li&gt;
&lt;li&gt;支持 css 样式&lt;/li&gt;
&lt;li&gt;IE6/7 下也支持&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;缺点-2&#34;&gt;缺点&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;样式限制，使用扁平化风格&lt;/li&gt;
&lt;li&gt;移动端还存在不兼容问题 (&lt;a href=&#34;https://docs.google.com/spreadsheet/ccc?key=0Ag5_yGvxpINRdHFYeUJPNnZMWUZKR2ItMEpRTXZPdUE#gid=0&#34;&gt;兼容表，作者不详&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;少量移动设备和 icon fonts 字符编码冲突&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.zjgsq.com/1523.html&#34;&gt;FF和 IE9 下跨域问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.cnblogs.com/demix/archive/2009/11/28/1612715.html&#34;&gt;性能问题&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;使用方法&#34;&gt;使用方法&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;制作字体文件

&lt;ul&gt;
&lt;li&gt;可以利用字体工具手动制作&lt;/li&gt;
&lt;li&gt;也可以利用在线工具自动生成&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;在 css 中引用，如下&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;引入字体文件&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    @font-face {font-family: &#39;iconfont&#39;;
        src: url(&#39;iconfont.eot&#39;); /* IE9*/
        src: url(&#39;iconfont.eot?#iefix&#39;) format(&#39;embedded-opentype&#39;), /* IE6-IE8 */
        url(&#39;iconfont.woff&#39;) format(&#39;woff&#39;), /* chrome、firefox */
        url(&#39;iconfont.ttf&#39;) format(&#39;truetype&#39;), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
        url(&#39;iconfont.svg#uxiconfont&#39;) format(&#39;svg&#39;); /* iOS 4.1- */
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;再定义一个 icon-* 通配我们所有图标的共有 CSS 样式，&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    [class^=&amp;quot;icon-&amp;quot;], [class*=&amp;quot; icon-&amp;quot;] {
      display: inline-block;
      speak: none
      font-family: &amp;quot;iconfont&amp;quot;;
      font-size: 16px;
      line-height: 1;
      font-style: normal;
      /** 字体图标出现锯齿的问题： */
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;最后是利用 :before 来注入每个 icon 对应的字体编码&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    .icon-bell:before {
      content: &amp;quot;\003432&amp;quot;;
    }
    .icon-search:before {
      content: &amp;quot;\003433&amp;quot;;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;资源推荐&#34;&gt;资源推荐&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.iconfont.cn/&#34;&gt;阿里巴巴矢量图标库&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://icomoon.io/&#34;&gt;icnMoon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://fortawesome.github.io/Font-Awesome/&#34;&gt;font awesome&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;参考资料-1&#34;&gt;参考资料&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.infoq.com/cn/articles/icons-fonts-as-your-responsive-strategy&#34;&gt;icon fonts 的探析及应用&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;其它一些想法&#34;&gt;其它一些想法&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;SVG绘图&lt;/li&gt;
&lt;li&gt;HTML5 离线文件&lt;/li&gt;
&lt;li&gt;localStorage 存储&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
  </channel>
</rss>
