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

第9~12期（2013-07-03）

奇舞周刊（9~12期）

第9期

1. Clown Car技术，解决响应式设计中图片自适应的问题

2. LESS/Sass/CoffeeScript编译工具推荐 – Koala

3. CSS架构

4. 修改document.domain的注意事项
由JK专门为本刊所写

5. JavaScript的装载和执行
本文主要介绍了一下Javascript异步入页面的一些技术和方法。属于科普性文章。很受教。

6. 深入脚本加载的浑水
关于脚本加载的另外一篇深入的文章

7. 避免JavaScript重复工作
对平时写JavaScript代码的一些优化建议，包括避免重复的元素集合，重复的条件判断，重复的对象创建。值得注意

8. JS异步编程：Callbacks, Listeners, Control Flow Libs and Promises
介绍JS异步编程四剑客Callbacks, Listeners, Control Flow Libraries and Promises

第10期

1. reset or Normalize
Normalize.css 是一个可以定制的CSS文件，它让不同的浏览器在渲染网页元素的时候形式更统一。而reset的问题是会产生很长的继承链。官方介绍的它的几个优点是：（1）保留有用的默认样式，也不像reset一样消除浏览器的默认样式（2）对更广的元素提高标准化的样式（就是增加了HTML5标签的支持）后面的3点就是V2版本的一些改进。另外，上期提到的pure也使用了它。

2. 7
用CSS实现的IOS的那个7

3. IE10 的特殊样式
条件注释对IE10不管用，那如果来做对IE10的hack,当然还是有其他办法，欲知详情，请仔细阅读

4. 为什么需要响应式的图片
一句话，图片大小减少了72%

5. 深入理解Express.js
揭开Express背后的秘密，才能更好地驾驭它

6. 基于 Web 的交互式数据可视化
D3，很不错的web可视化JS库，对数据可视化感兴趣的同学一定不要错过哦

7. web worker多线程研究
月影原创，本刊收录

8. 关于V8对于array处理的一个有趣的讨论
能够从中对平时写JS代码的性能有一定的帮助，记住100000和数组是否是连续的两个条件

9. 纯用CSS按需加载图片
有趣的想法，作者乐在其中。能够从中体会到什么才是真正的兴趣与实践相结合。

10. Pinterest的渲染性能案例研究
深入的探讨了如何提高网站或者web app的渲染性能，这可是事关用户体验的事

11. 有效的解决gmail的内存问题
JS的自动垃圾回收机制也不能有效的解决内存的问题。JS app遭受着与原生app一样的内存管理上的困扰，比如泄漏，溢出等。大型应用gmail也难逃魔掌。本文介绍gmail的小组成员如何利用chrome的开发者工具来解决这些问题，仔细阅读，面对自己的小应用程序的时候，就能游刃有余。

12. Web开发牛人访谈：你们都在用什么？
web牛人们平时开发用的工具，发现sublime真的很受欢迎哦

第11期

1. CSS布局的未来
全新的布局方式

2. Caption Hover Effects
使用CSS3实现实现很炫的图片标题hover效果。

3. Apple Mac Pro page deconstructed
看过新版Mac Pro页面的同学一定会对其动画效果有深刻印象。本文揭秘了效果背后的HTML、CSS代码，让你明白它们是如何实现的。

4. Making Infield Form Labels Suck Less
介绍了几种很好的placeholder效果。文章的链接中有每种placeholder效果的实现方法。

5. Making Infield Form Labels Suck Less II
《Making Infield Form Labels Suck Less》的姊妹篇。有placeholder详细的实现方案。

6. Native JavaScript Equivalents of jQuery Methods: CSS and Animation
为了兼容古老的浏览器，我们会使用jQuery等脚本库，但是现代浏览器已经提供了API来实现相同的功能。本文介绍了jQuery中CSS相关的方法对应的浏览器API。

7. Adventures in Jank Busting: Parallax, performance, and the new Flickr Home Page
Flickr改版的案例分享，内容涉及性能优化、视差滚动和硬件加速等。文章还介绍了他们使用调试工具进行优化的方法。

8. A Couple of Best Practices for Tablet-Friendly Design
本文总结了为平板做网站时的最佳实践。

9. 那些年，我们踩过的“坑”
为Android开发网站，你一定会踩到很多坑。这篇文章列出了一些，推荐大家阅读一下，以后遇到相同问题时知道该怎么解决。

10. 当前 WEB APP 开发的最佳实践
前人总结，推荐给需要学习的同学

11. 从Android界面开发谈起
由浅入深地介绍android界面开发

12. 浅析 Cordova for iOS
虽然题目是浅析，实际上文章详细的分析了JS如何与object-c进行通信的，对用利用phonegap进行IOS开发的同学很有帮助

第12期

1. How Behance went responsive with Sass and Require.js
本文是设计师的网站Behance的一个案例分享，介绍了他们使用SASS和Require.js开发复杂的响应式页面的过程。此外，本文还包含了手机设备上的性能优化和改版的经验。

2. 异步编程：When.js快速上手
针对入门者写的when.js异步编程介绍。

3. eval() isn’t evil, just misunderstood
重新审视eval，一个被误解的函数。

4. 未知高度多行文本垂直居中
文字垂直居中方案

5. Creating iOS 7 effects with CSS3: translucency and transparency
凤凰涅磐的 iOS 7，不容错过的CSS震撼！

6. Static Memory Javascript with Object Pools
本文介绍了Javascript中的垃圾回收对性能的影响以及使用对象池来管理内存的使用。关于Web应用的内存管理，也可以参考一下GMail的经验。

7. Web Fonts and the Critical Path
WebFont能极大丰富网页上字体的使用，至少对于英文字体是这样。但是WebFont有严重的性能问题，在某些浏览器下等字体下载完成后才开始渲染使用它的文字。这篇文章提供了一些方法来解决性能的问题。

8. 正则表达式30分钟入门教程
正则表达式入门。可以作为参考手册。

9. [译]当Node.js遇上WebMatrix 2
WebMatrix 2是一个强大的构建Web应用程序的开发工具

10. Internet Explorer 11 preview
Internet Explorer 11预览版发布了。新版的IE浏览器修改了UserAgent字符串，加强了对HTML5、CSS3及ES6的支持。新增对WebGL和SPDY的支持。

Clown Car技术，解决响应式设计中图片自适应的问题

Adaptive images are the current hot topic in conversations about adaptive and responsive Web design. Why? Because no one likes any of the solutions thus far. New elements and attributes are being discussed as a solution for what is, for most of us, a big headache: to provide every user with one image optimized for their display size and resolution, without wasting time, memory or bandwidth with a client-side solution.

We have foreground and background images. We have large and small displays. We have regular and high-resolution displays. We have high-bandwidth and low-bandwidth connections. We have portrait and landscape orientations.

Some people waste bandwidth (and memory) by sending high-resolution images to all devices. Others send regular-resolution images to all devices, with the images looking less crisp on high-resolution displays.

What we really want to do is find the holy grail: the one solution that sends the image with the most appropriate size and resolution based on the browser and device making the request that can also be made accessible.

The “clown car” technique is the closest thing we’ve got to a holy grail: leveraging well-supported media queries, the SVG format and the <object> element to serve responsive images with a single request. The solution isn’t perfect yet, but it’s getting close.

Background Images And Media Queries

We’ve solved adaptive background images. Media queries make it simple to tailor the size and resolution of images to a device’s pixel ratio, viewport size and even screen orientation.

By using media queries with our background image styles, we can ensure that only the images that are needed are downloaded from the server. We can limit downloads to the assets that are most appropriate, saving bandwidth, memory and HTTP requests.

Unfortunately, there has been no solution for foreground images — until now. The technology has been available for a long time. The clown car technique is just a new technique that leverages existing technology.

Proposed Solutions With New Technology

New Elements and Attributes

With inline or “content” images, getting the browser to download and display only the appropriate foreground image is a bit more difficult. Most people believe that there is no mechanism for the <img> tag to cause an image of the right size and resolution to be downloaded. To that end, polyfills have been created and services have been established.

The <picture> element — which leverages the semantics of the HTML5 <video> element, with its support of media queries to swap in different source files — was proposed:

<picture alt="responsive image">
<source src="large.jpg" media="(min-width:1600px),
(min-resolution: 136dpi) and (min-width:800px)">
<source src="medium.jpg" media="(min-width:800px),
(min-resolution: 136dpi) and (min-width:400px)">
<source src="small.jpg">
<!-- fallback -->
<img src="small.jpg" alt="responsive image">
</picture>

Another method, using a srcset attribute on the <img> element, has also been proposed. The above <picture> element would be written as this:

<img
alt="responsive image"
src="small.jpg"
srcset="large.jpg 1600w,
large.jpg 800w 1.95x,
medium.jpg 800w,
medium.jpg 400w 1.95x">

Both solutions have benefits and drawbacks. Picking one is hard — but we don’t have to anymore. The two solutions have been joined into what’s called “Florian’s Compromise.” However, the traction isn’t quite there yet.

Google has proposed client hints as part of HTTP headers, to enable the right image to be served server-side.

SVG as an Out-of-the-Box Solution

Many people don’t realize that we already have the technology to create and serve responsive images.

SVG has supported media queries for a long time, and browsers have supported SVG for… well, long enough, too. Most browsers support media queries in SVG (you can test your own browser). When it comes to responsive images, the only browsers in the mobile space that don’t support SVG are old versions of the Android browser (Android support for SVG began with Android 3.0).

We can leverage browser support for SVG and SVG support for both media queries and raster images to create responsive images, using media queries in SVG to serve up the right image.

My original experiment should theoretically work, and it does work in Internet Explorer (IE) 10 and Opera. When you mark up the HTML, you add a single call to an SVG file.

<img src="awesomefile.svg" alt="responsive image">

Now, isn’t that code simple?

SVGs support raster images included with the <image> element and with the CSS background-image property. In our responsive SVG, we would include all of the images that we might need to serve and then show only the appropriate image based on media queries.

Download a Single Raster Image

My first attempt at SVG used <image> with media queries, hiding them with display: none.

While the SVG works perfectly in terms of responsiveness, it has several problems. Unfortunately, setting display: none on an <image> in SVG, similar to <img> in HTML, does not prevent the resource from being downloaded. If you open the <image> SVG in your browser, all four PNGs will be retrieved from the server, making four HTTP requests, wasting bandwidth and memory.

We know from CSS background images that downloading only the images that are needed is indeed possible. Similarly, to prevent the SVG from downloading all of the included images, we would use CSS background images instead of foreground images in our SVG file:

<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 300 329" preserveAspectRatio="xMidYMid meet">

<title>Clown Car Technique</title>

<style>
svg {
background-size: 100% 100%;
background-repeat: no-repeat;
}

@media screen and (max-width: 400px) {
svg {
background-image: url(images/small.png");
}
}

@media screen and (min-width: 401px) and (max-width: 700px) {
svg {
background-image: url(images/medium.png);
}
}

@media screen and (min-width: 701px) and (max-width: 1000px) {
svg {
background-image: url(images/big.png);
}
}

@media screen and (min-width: 1001px) {
svg {
background-image: url(images/huge.png);
}
}
</style>
</svg>

The above can be included directly as an inline <svg>, or embedded with the <img> src  attribute or <object> data attribute.

If you’re familiar with media queries and CSS, most of the code above should make sense. The clown car technique uses the same media queries that you would use elsewhere on your adaptive website.

To preserve the aspect ratio of the containing element and ensure that is scales uniformly, we include the viewbox and preserveAspectRatio attributes.

The value of the viewbox attribute is a list of four space- or comma-separated numbers: min-x, min-y, width and height. By defining the width and height of our viewbox, we define the aspect ratio of the SVG image. The values we set for the preserveAspectRatio attribute — 300 × 329 — preserve the aspect ratio defined in viewbox.

Issues with including the above include 1) Chrome and Safari not maintaining the aspect ratio when <svg> is included inline: instead, defaulting the <svg> to 100% width and height. A bug has been submitted. 2) Webkit and Firefox not allowing the inclusion of raster images or scripts in SVGs embedded via the <img> element, and 3) No SVG support in IE <=8 and Android <=2.3.3.

When you open the SVG file with just background images defined, the raster image will take up the entire viewport. While the <image> version might look better as a standalone file because it is maintaining its aspect ratio and the background-image version is filling up the viewport, when you include the SVG as a separate document pulled into the HTML, the aspect ratio is preserved by default.  The background-size of contain, cover or 100% all work: choose the one that works best for your requirements.

The CSS background-image property solves the HTTP request problem. Open the SVG file with just PNG background images (or the JPEG version ) and look at the “Network” tab in your developer tools, and you’ll see that the SVG has made only two HTTP requests, rather than five. If your monitor is large, then the browser would have downloaded a small SVG file (676 bytes) and huge.png or huge.jpg.

Our first problem — that all of the different sizes of images are downloaded, even those that aren’t needed — has been resolved. This background-image version downloads only the image required, thereby addressing the concerns about multiple HTTP requests and wasted bandwidth.

The magic happens when we include SVG in a flexible layout. You’ll notice that the first time you resize the image, the browser might flicker white as it requests the next required PNG — because it doesn’t automatically download all assets. Rather, it downloads only the asset it needs. Simply declare either the width or the height of the container (<img>, <svg> or <object>) with CSS within your layout media queries, and the SVG will only pull in the single raster image it needs.

We still have the SVG file itself, which requires an HTTP request when not embedded inline with <svg>. We’ll solve that issue third.

Content Security Issues

In Opera or in Windows 9 or 10, open the HTML file containing an SVG raster image that is linked to with the <img> tag. Note in the “Resources” panel of the developer tools that only one JPEG or PNG is being downloaded. Resize your browser. Note that the <img> is responsive. Additional JPEGs or PNGs (we could also have used GIF or WebP) are downloaded only when needed.

If you opened the HTML file containing an SVG raster image in Firefox or WebKit, you would likely have seen no image. The SVG works in all modern browsers, but the <img> that calls in an SVG pulling in raster images works only in Opera and IE 9+. We’ll first cover how it works in IE and Opera, then we’ll cover the issues with WebKit and Firefox.

The code is simple:

<img src="awesomefile.svg" alt="responsive image">

When you include the SVG in your HTML <img> with a flexible width, such as 70% of the viewport, then as you grow and shrink the container by changing the window’s size or the CSS, the image will respond accordingly.

The width media query in the SVG is based on the parent element in which the SVG is contained — the <img>, in this case — not the viewport’s width.

As the window grows and shrinks, the image displayed by the SVG changes. In the SVG file, the images are defined as being 100% of the height and width of the parent, which, in the case above, when we opened the SVG directly, was the viewport. Now, the container is the <img> element. Because we included the viewbox and preserveAspectRatio attributes, as long as at least one length is defined, the SVG will grow or shrink to fit that length, maintaining the declared aspect ratio in the SVG, whatever the image’s size.

These foreground images work perfectly in Opera and IE 9+ (the versions found on mobile devices). In Chrome and Safari, if you open the SVG file first, thereby caching it, then the HTML file that contains the foreground SVG image might work as well.

While we saw earlier that the browser can indeed render the SVG, if the SVG is included in our document via the <img> tag, then this particular type of SVG will fail to render.

Why? To prevent cross-domain scripting attacks, some browsers have content security policies in place to keep SVG from importing media or scripts, in case they’re malicious in nature.

Blocking SVGs from importing scripts and images does make sense: To prevent cross-domain scripting attacks, you don’t want a file to pull potentially malicious content. So, SVG is supported, but in the case of WebKit and FireFox, it is just being prevented from pulling in external raster images. I’ve submitted a Chrome bug report to get the ban on importing raster images in SVG lifted.

In Firefox, the responsive SVG also works on its own. Firefox fully supports SVG. However, for security reasons, Firefox blocks the importing of external raster images, even if those images are on the same domain. The rationale is that allowing visitors to upload images and then displaying those images and scripts as part of an SVG constitutes a security risk. I would argue that if a website uses unsecured user-generated content, they’re already doing it wrong.

For right now, this simple line…

<img src="awesomefile.svg" alt="responsive image">

… is blocked in some browsers and, therefore, isn’t a viable solution.

All browsers support SVG media queries. They all support SVG as foreground or content images. They all support SVG as background images. The support just isn’t identical because of browser security policies.

All browsers do support the <object> tag. Without changing browser security policies, <img> alone won’t work yet. We can leverage the <object> tag.

With the <object> Tag

The <object> element allows an external resource to be treated as an image. It can take care of the browser security drawbacks we see with <img>, disallowing the importing of images or scripts into an <img> file. The <object> element allows both.

The code isn’t that much more complex:

<object data="awesomefile.svg" type="image/svg+xml"></object>

By default, the <object> will be as wide as the parent element. However, as with images, we can declare a width or height with the width or height attribute or with the CSS width or height property. For the clown car technique to maintain the declared aspect ratio, simply declare just one length value.

Because of the viewbox and preserveAspectRatio declarations in our SVG file, the <object> will by default maintain the declared aspect ratio. You can overwrite this with HTML or CSS attributes.

As noted earlier, the media queries in the SVG match the SVG’s container, not the viewport. The matched media queries in the SVG file will reflect the parent of the <object> tag, rather than the viewport.

If you look at an SVG being pulled in as the <object> data, you’ll see that it works in all browsers that support SVG.

With the <svg> Tag

Instead of including an external SVG file, you can also include the svg as inline content with the <svg> tag. The benefit is no additional http request for an external .svg file.

Unfortunately, Chrome and Safari render the SVG as a full screen block display element and appear to not support the preserveAspectRatio attribute when included this way (they do support preserveAspectRatio when the SVG is included via the <object> tag).

The other drawback is that, unlike  <object>, we can’t include fallback content for browsers that don’t support SVG. Instead we would need to include background-image, with height and width on the <svg> for browsers that don’t support SVG.

Fallback for IE

The <object> element is supported in all browsers, even mobile browsers. But this technique works only if the browser supports SVG as well. Therefore, it doesn’t work in IE 8 and below or in Android 2.3 and below. There is a fallback for these older browsers. Also, we are making two HTTP requests to pull in the correct image — one for the SVG file and one for the raster image that we want to show — there is a solution for this, too.

What makes <object> more interesting than <img> or  <svg> is that it is a non-empty element that can include fallback content when a browser fails to support the <object>’s data type. If you want, you can include an <img> tag nested in <object> for browsers that don’t support the SVG.

For IE 8 and below, we’ll include our medium-sized raster image because they’re generally displayed on monitors at a normal DPI:

<object data="awesomefile.svg" type="image/svg+xml">
<img src="medium.png" alt="responsive image">
</object>

Unfortunately, content nested within <object> is downloaded even when the object is rendered and the nested content is not needed or rendered. This adds a download of the medium-sized image whether or not it is needed.

To handle this issue, we can use conditional comments for IE.

<object data="awesomefile.svg" type="image/svg+xml">
<!--[if lte IE 8]>
<img src="medium.png" alt="Fallback for IE">
<![endif]-->
</object>

A Single HTTP Request

We’ve narrowed the SVG to download a single raster image. The <object> method  downloads both the raster  image and the SVG file. We have two HTTP requests instead of one. To prevent additional HTTP requests, we can create an SVG data URI, instead of calling in an external SVG file.

<object data="data:image/svg+xml,<svg viewBox='0 0 300 329' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg'><title>Clown Car Technique</title><style>svg{background-size:100% 100%;background-repeat:no-repeat;}@media screen and (max-width: 400px){svg{background-image:url(images/small.png);}}@media screen and (min-width: 401px) and (max-width:700px){svg{ background-image:url(images/medium.png);}}@media screen and (min-width: 701px) and (max-width:1000px){svg{background-image:url(images/big.png);}}@media screen and (min-width:1001px){svg{background-image:url(images/huge.png);}}</style></svg>" type="image/svg+xml">
<!--[if lte IE 8]>
<img src="images/medium.png" alt="Fallback for IE">
<![endif]-->
</object>

The code above looks messy, but it’s simply data:image/svg+xml, followed by the contents of the SVG file, minified. It is the same code we would include had we used the content <svg>, but this method supports the preserveAspectRatio attribute of the SVG.

It works in all browsers that support SVG, except IE. While this is frustrating, it’s actually because Microsoft is trying to follow the specification to the letter. The specification states that the data URI must be escaped. So, to make all browsers, including IE 9 and 10, support the data URI, we escape it:

<object data="data:image/svg+xml,%3Csvg%20viewBox='0%200%20300%20329'%20preserveAspectRatio='xMidYMid%20meet'%20xmlns='http://www.w3.org/2000/svg'%3E%3Ctitle%3EClown%20Car%20Technique%3C/title%3E%3Cstyle%3Esvg%7Bbackground-size:100%25%20100%25;background-repeat:no-repeat;%7D@media%20screen%20and%20(max-width:400px)%7Bsvg%7Bbackground-image:url(images/small.png);%7D%7D@media%20screen%20and%20(min-width:401px)%7Bsvg%7Bbackground-image:url(images/medium.png);%7D%7D@media%20screen%20and%20(min-width:701px)%7Bsvg%7Bbackground-image:url(images/big.png);%7D%7D@media%20screen%20and%20(min-width:1001px)%7Bsvg%7Bbackground-image:url(images/huge.png);%7D%7D%3C/style%3E%3C/svg%3E"
type="image/svg+xml">
<!--[if lte IE 8]>
<img src="images/medium.png" alt="Fallback for IE">
<![endif]-->
</object>

The markup is ugly, but it works!

Open up our first page and our second page, and then open up the developer tools to inspect the HTTP requests. You’ll notice two HTTP requests: the HTML file, and the PNG that the SVG pulls in. The inspector will show an entry for the SVG file as well. But notice that no HTTP request is being made: the status of the SVG is “success,” and the size over the network is 0 bytes, with the size of the data URI SVG coming in at under 600 bytes.

Landscape Vs. Portrait

Generally, content images are either landscape or portrait: faces are portrait, groups of people, products and sunsets are landscape. Some people object strongly to the clown car technique because they believe that images don’t change according to orientation. That isn’t necessarily true.

The magic of this technique is that the rendered image changes based on the size of the container. You could set your landscape foreground image to 33% or 240 pixels or whatever else, and your portrait object’s width to 25% or 180 pixels or whatever else. The object’s size is determined by the CSS for your HTML. The raster image served is based on the media queries that match the object’s size.

The aspect ratio remains the same, but you can control which raster image is served by changing the proportions of the SVG container, matching the media queries in the HTML’s CSS with the media queries in the SVG’s CSS.

If you do prefer to serve landscape foreground images when in landscape mode and portrait when in portrait mode, don’t use the preserveAspectRatio attribute. Instead, declare absolute heights and widths in your CSS for each breakpoint design size.

Other Benefits

Another benefit of the clown car technique is that all of the logic remains in the SVG file. Similar to how we separate content from presentation from behavior, this method enables us to separate image logic from content. The <img> or <object> element is part of the content, but the logic that makes it all work can be made separate from the content layer: The logic is in the SVG image, instead of polluting the CSS and HTML. This benefit may make some choose the non-data-URI version of the <object> method, in-spite of the extra http request, because it is so easy and clean.

The technique enables us to neatly organize our images, separating behavior from presentation from content from images. I envision the structure of responsive image files to be something like this:

images/
clowns/
small.png
medium.png
large.png
svg.svg
cars/
small.png
medium.png
large.png
svg.svg
techniques/
small.png
medium.png
large.png
svg.svg

All of our assets for a single image live in a single separate directory. The image file names are consistent, while the folder names vary. We can have responsive foreground images without littering our HTML with extra unused code, thus making image management and updating a breeze.

Drawbacks Of The Clown Car Technique

We’ve covered the pros of the technique. The technique is still nascent, so I haven’t figured out all of the problems. I am working on solutions to some of the issues that have been found, and I assume new issues will arise.

I am mostly concerned with the ways in which images that arise from the clown car technique fail to behave like regular PNGs, JPEGs and GIFs. The main issues I have noticed are loading order, fallback for Android 2.3.3 and below, accessibility, and the ability to right-click on the image.

Page Layout

According to John Wilkins, the clown car technique requires the CSS layout to fully render before images start to load. I have not had a chance to compare the loading of regular foreground images versus the <object> element with SVG pulling in raster images, so I cannot comment on the impact of this issue yet.

Android 2.3 and Below

Android 2.3 and below does not support SVG. I have found three possible solutions, which I have yet to flesh out.

<SVG> with background-image

We can use <svg> as inline content instead of <object>. While  IE 8 and below and Android 2.3 and below do not support SVG, with CSS these browsers can give <svg> layout with height and width, and then declare the raster image as the background-image value.

As our goal is to create responsive foreground images without the use of CSS background images, this backward-compatibility hack doesn’t suit our purposes. If this is our solution, why not just use CSS background images instead of the Clown Car Technique for all browsers and devices?

Conditional Comments

The first is to include conditional comments to include a medium-sized fallback for IE 8 and below, and a small-sized fallback for all browsers that ignore conditional comments (including IE 10):

<!--[if lte IE 8]>
<img src="images/medium.png" alt="Fallback for IE">
<![endif]-->
<!--[if !IE]> -->
<img src="images/small.png" alt="fallback"/>
<!-- <![endif]-->

This fallback will show the small PNG to all Android phones. Unfortunately, all browsers other than IE 9 and below will download small.png, even though the image will not be shown. In trying to solve for old Android, we are downloading the small PNG to most devices unnecessarily.

JavaScript Feature Detection

The other solution is feature detection with JavaScript — i.e. test for SVG support. Include a .no-svg class in the <html> element if the browser doesn’t support SVG. Using a WebKit-prefixed media query to exclude non-WebKit browsers, targeting as follows:

.no-svg object[type*="svg"] {
width: 300px;
height: 329px;
background-image: url(small.png);
}

The properties above add dimensions and a background image to the <object> object. Again, I haven’t tested this yet, and it’s not accessible, which brings us to the next topic.

Accessibility

The benefit of <img> is that a simple alt attribute can make it accessible. The <object> element does not have an alt attribute. Ideas to make clown car images accessible include the following:

- Add a <title> and <desc> to the SVG file.

- Add ARIA role="img" and other ARIA attributes, such as aria-label and aria-labeled-by.

- Include tab-index="0" to enable the <object> to gain focus without changing tab order.

- Add alt attributes to the fallback images.

- Add alternative text between the opening and closing <object> tags.

Mac OS X’s Universal Access’s VoiceOver reads the content of the SVG’s <title> and value of the   aria-label attribute on the <object> when the <object> includes tabindex="0".  Testing of the accessibility testing page still needs to be done with actual screen readers.

Right-Click to Save

When you right-click on an image in a desktop browser, you’ll get a menu enabling you to save the image. On some phones, a lingering touch on an image will prompt a save. This does not work with <object> or with background images, which is what our SVG is made of.

This “drawback” might be a feature for people who are wary of their images being stolen. In the brief time that I have contemplated this issue, I have yet to come up with a native way to resolve this issue. It is likely resolvable with JavaScript.

If the inability to right-click to save is your main argument against this technique, then recall that while users can right-click on WebP images in browsers that support WebP (only Chrome and Opera), they can’t do much with those images because native applications don’t support this new format. But this needn’t prevent us from moving forward with these bandwidth-saving techniques and features.

Why “Clown Car”?

With help from Christopher Schmitt and Amie Gregory, I’ve named this technique “clown car” because it includes many large images (the clowns) in a single tiny SVG image file (the car).

We need to use the non-semantic <object> element as we encourage browser vendors to support raster images in SVG as an <img> source either via CORS or CSP.

The clown car technique is a solution we can use now. Detractors argue that <picture> and/or srcset are the answer without convincing me that the clown car technique isn’t the right answer. Some argue that the lack of support in Android is its downfall, forgetting that Android 2.3.3 and IE 8 don’t support <picture> or srcset either.

I believe the <object> element can be made accessible. While the lack of semantics is a drawback, I will be satisfied using this technique once accessibility is assured. Testing accessibility is my next priority. While I would like to see this element work with the simpler and more semantic <img> tag, once the accessibility issue is resolved, this technique will be production-ready.

(al)

原文链接：http://coding.smashingmagazine.com/2013/06/02/clown-car-technique-solving-for-adaptive-images-in-responsive-web-design/ （本内容由互联网资料整理而成）

LESS/Sass/CoffeeScript编译工具推荐 – Koala

越来越多的同学开始使用less/sass等预处理器的方式来编写CSS与JavaScript，很大程度上提高了工作效果，但编译文件是个繁琐的事情，使用命令行的方式操作起来很累，目前也已经有一些图形工具，比如mac下的codekit, windows下有winLess、simpless等。Codekit是一个很棒的工具，它是一个商业的软件且只有Mac版本。而windows下现有的工具都比较简陋，无法满足我们日常开发需求。
今天向大家推荐一个新工具Koala，功能齐全，跨平台运行，同时还是一个开源软件。

Koala是什么？

koala是一个前端预处理器语言图形编译工具，目前已支持Less、Sass、Compass、CoffeeScript。

下载地址：http://koala-app.com/index-zh.html

功能特性：

- 多语言支持：支持less、sass、coffeescript、compass framework；

- 实时编译：监听文件，当文件改变时自动执行编译，这一切都在后台运行，无需人工操作；

- 编译选项：支持自定义设置各个语言的编译选项；

- Import文件监听：关联import文件，如import文件改变，源文件将自动进行编译。

- 代码压缩：less & sass支持编译后自动压缩代码；

- 错误提示：在编译时如果遇到语法的错误，koala将在右下角弹出错误信息，方便开发者定位代码错误位置；

- 跨平台：windows、linux、mac 完美运行；

如何使用：

使用技巧：

切换为中文语言：打开设置窗口，system – locales选择为中文，重启后生效。

设置全局编译选项：在设置窗口中勾选各个编译选项后，新增加的文件将应用该设置。

批量处理功能：文件列表可进行多文件选择，选中后打开右键，可批量设置输出目录与批量编译文件。

如果你在使用过程中遇到问题，可在github上向作者反馈：https://github.com/oklai/koala/issues/new

截图：

作者: ethan
web前端工程师

如果你喜欢本文，欢迎 订阅本站 以获得本站最新内容。

原文链接：http://www.qianduan.net/front-weapon-recommendation-koala-less-sass-coffeescript-compiler-tools.html （本内容由互联网资料整理而成）

CSS架构

特别声明：此篇文章由D姐根据Philip Walton的英文文章原名《CSS Architecture》进行翻译，整个译文带有我们自己的理解与思想，如果译得不好或不对之处还请同行朋友指点。如需转载此译文，需注明英文出处：http://engineering.appfolio.com/2012/11/16/css-architecture/以及作者相关信息

作者：Philip Walton

译者：D姐

对于许多web开发者，认为擅长css就是能把一个视觉设计图用代码完美的复现出来。你不使用table，而且很自信，自己可以使用尽可能少的图片。如果你确实很棒，就会使用最新最伟大的技术例如Media Queries，Ttransform和Transition。一个好的css开发人员确实是会这些，但是很少在评估一个人的水平时会将css作为完全独立的一面被提及。

有趣的是，我们通常不这样评判其他语言。一个Rails开发者不会因为他写的代码规范就认为他是一个好的开发者。因为这是最基本的。当然它必须是满足规范，除此以外还要考虑其他方面:代码是否有可读性？他是否容易修改或是拓展？他是否跟程序的其他部分解耦合？他是否可以扩展？

当评估代码其他部分时这些问题是自然的，所以css也不应该例外。如今的web应用程序比以往大很多，一个考虑不周的css架构足以阻碍web程序的发展。是时候像评价应用程序其他部分一样的方式评价css。他不是一个事后的产生的想法或不仅仅是设计师的问题。

优秀的CSS全局架构

在css社区，达成最佳实践的一个通用共识是非常难的。从纯粹Hacker News讨论和开发者反映到css lint判断CSS代码是否标准。很明显，许多人都不清楚，甚至css作者都认为自己的代码是可行还是不可行

所以不是制定我自己设定的最佳实践理由，我认为我们应该首先定义我们的目标。如果我们能达成一致的目标，我们就能识别不好的css代码，不是因为他打破了我们对于什么是好的css代码的设想，而是因为他确实阻碍了css的开发过程。

我认为好的css架构目标不应该有别于所有好的软件开发目标。我想要我的css是可预见的、可重用的、可维护的和可扩展的。

CSS的可预见

可预见性的css意味着你的规则行为正如你所想，当你添加或更新一条规则，他不应该影响你网站上不想要受影响的部分。对于一个小型网站很少的修改，并不是很重要。但是对于一个有着几十或几百个页面的大型网站，可预见性的css就是一种必要。

CSS的可复用性

Css规范应该是足够抽象的和耦合的，这样你可以根据现有代码部分很快创建出新的组件，而不需要重新编写你已经处理过的样式和问题。

CSS的可维护性

当你的网站需要添加、更新或重新安排一些新的组件和特性，这样做不应该重构现有的css。给页面添加x组件不应该破坏已经存在的组件Y。

CSS的可扩展性

随着你的网站的规模和复杂程度的增长，它往往需要更多的开发人员来维护。可扩展的css意味着可以轻松的由有一个人或一个大型的技术团队管理你的网站。他也意味着你的网站的css架构容易掌握不需要很陡的学习曲线，仅仅因为你是如今唯一接触css的开发人员，但是并不意味着永远是这种情况。

常见的坏习惯

在我们寻找通往好的css架构的目标道路之前，我认为审视常见的不好习惯可以有助我们更好的实现目标。往往只有通过不断的重复出错，我们才能开始走上正确的道路。

下面的例子都是我曾经写过的具有通用性的代码，虽然实现了效果，但是每一个都曾是一个让人头疼的事情。尽管我有良好的意愿，并承诺这次会与众不同，但是这些模式总是让我陷入麻烦中。

基于父类修改组件

几乎所有的网站都会一个特定的视觉元素看起来跟每个元素完全一样，而且当遇到这种一次性情况，几乎每个新的css开发人员(甚至是有经验的开发人员)按照同样的方式处理它。你找出这个特定的父元素（或是你创建一个），而且你为他们写一个全新的规则处理他。

.widget {
background: yellow;
border: 1px solid black;
color: black;
width: 50%;
}

#sidebar .widget {
width: 200px;
}

body.homepage .widget {
background: white;
}

起初这看起来可能是很优秀的代码，但是让我们仔细看，这些都是为实现目标而写。

首先，这个例子中的小结构没有可预见性。创建了好几个这样的结构的开发者希望他是特定的外观，然而当把他用在侧栏或是主页，他将看起来不同，尽管结构是完全一样。

他的复用性扩展性也不是很好。当把他用在主页或是被要求用在其他页面会发生什么？不得不添加新的规则。

最后，他不是很容易维护，因为一旦这个结构重新设计了，那么他必须修改css中的好几个地方,不符合前面提出的CSS架构的要求，需要一个接一个的来修改。

想象一下，如果这种代码被用在其他语言。你本来用一个类定义，然后在代码的其他部分引入这个类定义，为了其他的用途改变他，这直接违背了软件开发过程中打开/关闭的原则。

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

在本文的后面,我们将看看如何不依赖父选择器修改组件。

过于复杂的选择器

有时一篇文章使得在互联网里展现css选择器的力量，并声称你可以给整个网站定义样式而不需要使用任何类名或是id。

尽管技术上是可行的，随着开发css的深入，我越来越远离复杂选择器。选择器越复杂，他跟html的结合越紧密。依赖于html标签和关系选择器虽然使你的html看起来很干净，但是它使你的css很糟糕。

#main-nav ul li ul li div { }
#content article h1:first-child { }
#sidebar > div > h3 + p { }

所有以上例子就是逻辑。第一个可能是一个下拉菜单样式，第二个是说文章的主要标题跟其他h1元素看起来不一样，最后一个例子好像是给侧栏部分的第一个段落添加一些额外的间距。

如果这个html永远不会改变，这个理由也许可以作为他的一个优点，但是假设html永远不会改变是多么不现实的事情。过于复杂的选择器可以令人印象深刻，他们可以使html摆脱所有表现的钩子，但是他们却很少能帮助我们实现良好的css结构的目标。

上面的例子并不是所有的都可以复用。因为选择器指向一个非常特别的标签位置，怎么能够让另一个有着不同结构的组件重用那些样式呢?以第一个例子(下拉菜单)作为例子，如果在其他页面需要添加一个看上去类似的下来菜单，但是他里面没有#main-nav的元素，你要做什么？你将不得不重新创建一整套样式。

如果html结构需要改变这些选择器也是不可预测的。想象一下一个开发人员想要把第三个例子中的div改成html5的section标签，那么整个规则就破坏了。

最后，因为这些选择器只有当html保持不变才能工作，所以他们的定义是不可维护的也是不可扩展的。

在大型的应用程序中你不得不做出权衡和妥协。复杂选择器的脆弱性是在维护你的html干净命名中起到很微小的作用。

过于通用的类名

当创建可重用的设计组件时，一种很常见的情况，就是用组件类名的里面包含组件子元素的类名表示范围，例如

<div class="widget">
<h3 class="title">...</h3>
<div class="contents">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
In condimentum justo et est dapibus sit amet euismod ligula ornare.
Vivamus elementum accumsan dignissim.
<button class="action">Click Me!</button>
</div>
</div>

.widget {}
.widget .title {}
.widget .contents {}
.widget .action {}

这个想法是.title, .contents, 和 .action类名的子元素定义安全的样式，不用担心会影响其他那些具有相同类名的元素样式。这是真的，但是这并不能防止其他同类名的样式会影响这个组件的样式。

在一个大型项目很可能有个像.title的类名被用到另一个环境中或甚至他本身，如果这种情况发生的话，这个widget’s title会突然看起来跟预期的不一样。

过于通用的类名会导致非常不可预知的css。

定制过多的规则

有时候，你做了一个视觉组件需要他距离你的网站某个部分左边上边分别有20px的偏移:

.widget {
position: absolute;
top: 20px;
left: 20px;
background-color: red;
font-size: 1.5em;
text-transform: uppercase;
}

一段时间后你需要在不同的地方使用这个完全一样的组件，然而以上的css代码不起作用，因为在不同的环境中不能复用。

问题是，你让这个选择器做了太多的事情。你在同一个规则中既定义的外观，又定义了布局和定位。外观是可以复用的，但是布局和定位是不能复用的。因为你把他们都混在一起使用，所以整个规则就都不能复用了。

然而这个起初看起来可能无害，但是他往往导致懂行的css开发人员复制和粘帖。如果一个新团队成员想要做一个看起来类似的组件，如一个.infobox。他们可能通过尝试开始用那个类名。但是因为一个新的infobox以一种不想要的方式定位，而不起作用。那么他们可能会做什么？以我的经验，多数新的开发人员不会破坏复用部分的规则。相反他们只是简单复制需要的代码行，然后把他粘帖到一个新的选择器里，这就造成了不必要的重复代码。

分析原因

上述所有糟糕的实践有一个类似的地方，他们给css添加太多的负担。

这似乎是一个奇怪的问题，毕竟一个样式表，他难道不应该承担大多数（如果不是全部样式）的样式吗?这个不是我们想要的吗？

这个简单问题的回答是yes，但是，像往常一样，事情并不总是那么简单，将内容与表现分离是件好事，但是不能因为仅仅你的css代码跟你的html代码分离，就意味着你的内容与你的表现分离了。换句话说，从你的html中分离出来的所有表现代码，并不能满足这个目标，如果为了工作要求你的css跟html有个密切的联系。

此外，html很少仅仅是内容，他多是用来表示结构的。而且通常这种结构是由没有意义的容器元素组成，不同于容许css隔离某组特定元素。甚至没有表现的类名，这仍然把表现混到html中，但是这是否就是有必要将表现跟内容混合呢？

我相信，介于html和css的目前状况，有必要也是明智的把html和css混合一起作为一个表现层。内容层仍旧可以通过模版和局部模版抽象出来。

解决方案

如果你的html和css准备一起作为一个web应用程序的表现层，那么他们需要一种方式来促进良好css架构的所有原则的形成。

我发现最好的办法，是css包含尽可能少的html结构。Css应该定义如何设置一个视觉元素的外观(为的是跟html有最小化的耦合度)这些元素应该看上去如他定义的一样，而不管他出现在html中的什么地方。如果一个特定的组件需要在不同的情况下看上去不同，那他应该称为不同的东西，这就是html的职责了。

作为一个例子，css可能通过.button类名定义一个按钮组件。如果某个html元素想要看起来像个按钮，他应该使用那个类名。如果在某种情况，这个按钮需要看起来不同(可能大点或全屏)，然后css需要定义看上去好像用一个新的类名，html包含这个新类名使用新外观。

Css定义你的组件长什么样，html掌管在页面上用什么元素呈现。知道越少关于html结构的css越好。

在html中明确声明你想要的是什么有很大的意义，他容许其他开发人员在看到标签就清楚的知道这个元素是长什么样。这样的意图是很明显的。没有这种实践是不可能分辨一个元素的外观是否有误，这样就造成了团队之间的混乱。

通常反对在html标签里写多个类名，认为那样做是多余的。一个css规则可能作用于一个组件中的1千个实例。那么仅仅是为了在标签里显示声明，他确实值得把这些类名写1千次吗？

虽然这个问题显然是有效的，但也可能误导人。这意味着要么你在css中用父类选择器，要么你手动在html中写1000次类名，但是很明显还有其他的解决途径。Rails或其他框架的表现层抽象，在保持html中显示效果，同时又避免将同一个类名重复写了一遍又一遍的实践中，有了丰富的经验。

最佳实战

在一次又一次犯上面的错误，并付出了一定代价之后，我总结出了如下的一些建议。尽管不是很全面的，但是我的经验表明坚持这些原则是能帮助你更好的实现好的css架构的目标

有意的

确保你的选择器不给不想要的元素添加样式的最好办法是不给他们机会。类似于#main-nav ul li ul li div这样的选择器，可能当你的标签过段时间修改的时候很容易最终运用到不必要的元素上。另一方面，像.Subnav这样的选择器就绝对不可能意外的运用到一个不必要的元素上。把样式直接加在你想要有样式的元素上的最好的方式，就是保持你的css是可预测的:

/* Grenade */
#main-nav ul li ul { }

/* Sniper Rifle */
.subnav { }

给出上面两个例子，第一个像一个手榴弹，第二个像一个狙击步枪。手榴弹也许今天工作的很好，但是你无法知道一个无辜平民是否移动到爆炸的范围里。

分担你的忧愁

我已经提到过一个组织良好的组件层，能帮助降低在css中的对于html结构的耦合度。此外，你的css组件本身应该是模块化的。组件应该知道如何定义他自己的样式并把工作做好，但是不应该让他们负责他们的布局或是定位，也不应该让他们过多假设如何与周围元素设置间隔。

通常，组件应该定义他们的外观如何，而不定义他们的布局或定位如何。所以当你在一条规则里面同时看到background，color，font，还有position，width，height，margin时，你就要小心咯。

布局和定位应该要么由一个分离的布局类或是一个分离的容器元素处理（记住，为了高效地分离内容和表现，经常必不可少的将内容和他的容器分离）。

空间类名称

我们已经检查了为什么父类选择器不能100%高效的阻止样式的交叉污染。一个更好的办法是给类名本身应用命名空间。如果你r的元素是可视组件的一员，那么他的每一个子元素类都应该用组件的基类名作为他的命名空间

/* High risk of style cross-contamination */
.widget { }
.widget .title { }

/* Low risk of style cross-contamination */
.widget { }
.widget-title { }

你的类名有命名空间，可以保持你的组件独立和模块化。它减少了现有类之间的冲突，降低了特殊性对子元素样式的要求。

扩展组件与修改类

当一个现有组件需要在一定的环境里看起来有点不同，创建一个修改类扩展他:

/* Bad */
.widget { }
#sidebar .widget { }

/* Good */
.widget { }
.widget-sidebar { }

我们已经看到基于其中之一的父元素修改组件的缺点，但是需要重申一点：修改类可以应用到任何地方。基于本地的可以覆盖只用于特殊地方的样式。修改类也可以如你所需复用多次。最后，修改类可以在html里面准确的表达开发人员的意图。另一方面，基于本地对于一个开发人员只通过html是完全不可见的，这样大大提高了被忽略的概率。

把你的CSS组织成逻辑结构

Jonathan Snook在他写的一本很棒的书SMACSS中，提出可以把你的css分为4个不同的类别来组织,他们是基础样式，布局样式，模块样式以及状态样式。基础样式是由重置元素规则和元素默认样式组成。布局样式是定位站内元素以及通用布局就像网格系统。模块样式是可以复用的视觉元素，状态样式就是通过javascript涉及到开启或关闭。

在SMACSS体系中，模块(如同我说的组件)在所有的css规则中占据绝大多数，所以我时常认为有必要把他们进一步分解为抽象的模版。

组件是可以独立的视觉元素。模版从另一方面来说是由块组成的。模版本身不能独立应用而且很少描述外观和感觉。相反，他们可以是单一的，可重复的模式，放在一起形成一个组件。

提供一个具体的例子，一个组件可能是一个模态对话框。这个对话框可能头部是站内通用的渐变背景色。并且周围有阴影，右上角也许有一个关闭按钮，他估计是水平垂直居中定位的。这四个模式中的每一个在全站中可能一次次的使用，所以每次你都不必重新编写他们的模式。因为他们全是模版，可以一起组成一个模态对话框组件。

通常我在html中不使用模板类，除非我有个很好的理由。相反，我在组件定义中使用一个包含模版样式的预处理器。下面我将详细讲解这些以及我这么做的合理性。

只用类名作为样式而且只做样式

任何参与过大型项目的人都会遇到一个问题，就是一个html元素有个完全不知道干什么用的类名。你想要删除他，但是你犹豫了，因为他可能有一些你不知道的用途。这样的情况一次次的发生，久而久之，你的html充满了各种不知任何用途类名，只因为团队成员害怕删除它们。

问题是类名在前端开发中通常赋予了太多的责任。他们用来定义html元素样式，作为javascript的钩子，添加到html中用作功能检测和自动化测试等等。

当一个类名在应用程序中的太多地方使用，这是一个问题。那么把她从html中删除就成了一个非常可怕的事情。

然而，随着建立一个约定，这个问题是可以完全避免的。当你在一个html中看到一个类名，应该立刻明白他是用来什么的。我的建议是给所有不用于定义样式的类名加一个前缀。我使用.js作为javascript的钩子，用.supports作为Modernizr 类名。所有仅仅是定义样式的类名没有前缀。

这使得发现没用的类名并删除它们如同在样式表目录搜索一样容易。你甚至可以用javascript将这个过程自动化，通过检查在html中的类名是不是在document.styleSheets对象里面来判断。如果不在document.styleSheets里面的类名，就可以安全的删除了。

一般来说，分离你的内容与你的表现是一个最佳实践，同样重要的还有将你的表现与功能分离。使用定义样式的类名作为javascript钩子，会把你的css与javascript紧紧绑在一起，在某种程度上，在不破坏功能的前提下，更新一些元素的外观是很难的或是不可能的。

命名有逻辑结构的类名

如今很多人写css用连字符作为词的分隔符。但是仅仅连字符是不足以区分不同种类的类名的。

Nicolas Gallagher最近写的关于这个问题的解决方案。我也采用了(只需要轻微的修改)并取得了很大的成功。为了说明需要有如下命名的约定。

/* A component */
.button-group { }

/* A component modifier (modifying .button) */
.button-primary { }

/* A component sub-object (lives within .button) */
.button-icon { }

/* Is this a component class or a layout class? */
.header { }

从上面的类名，不可能知道他们要应用什么类型的规则。这不仅增加开发过程中困扰，也加大用自动化方式测试css和html的难度。一个结构化命名约定可以让你看到一个类名，就准确的知道跟他有关的其他类名，以及他应该出现在html中的哪些地方。命名和测试变得容易可行，这在以前是不可能的。

/* Templates Rules (using Sass placeholders) */
%template-name
%template-name--modifier-name
%template-name__sub-object
%template-name__sub-object--modifier-name

/* Component Rules */
.component-name
.component-name--modifier-name
.component-name__sub-object
.component-name__sub-object--modifier-name

/* Layout Rules */
.l-layout-method
.grid

/* State Rules */
.is-state-type

/* Non-styled JavaScript Hooks */
.js-action-name

重做第一个例子

/* A component */
.button-group { }

/* A component modifier (modifying .button) */
.button--primary { }

/* A component sub-object (lives within .button) */
.button__icon { }

/* A layout class */
.l-header { }

工具

维护一个有效的并且有序的css架构是很困难的，尤其是在一个大型项目中。这里那里一点不好的规则可以像滚雪球一样变成一个难以控制的混乱局面。一旦你的应用程序中的css进入一个特殊领域和有！important王牌的混战中，他几乎不可能重新开始去恢复。关键是从一开始就避免这些问题。

幸运的是，这里有一些工具可以容易的控制你的网站的css架构。

预处理程序

如今谈到css工具就不可避免的要提及预处理程序。所以本文也不例外。但是在我赞美他们的用处之前，我应该说一些他的注意事项。

预处理程序可以帮你更快但不是更好的书写css。最后演变成纯粹的css和同一个规则的应用。如果一个预处理程序可以让你写css更快，那么也可以让你更快的写出糟糕的css。所以在让预处理程序解决你的问题之前，应该理解一下好的css架构就显得尤为重要。

许多所谓的预处理程序的特性实际上对于css架构是很糟糕的。以下是一些我不惜一切代价避免的特性（尽管这些普遍思想应用于所有的预处理程序语言，这些准则特别是在sass中应用）。

1. 代码组织上从不嵌套规则。当输出的css是你想要的

2. 如果你不传参数的话从不使用混入类。没有参数的混入类可以更好的作为模版使用，这样的模版可以扩展

3. 从不在选择器上使用@extend，他不是一个单独的类。从设计角度他没有意义，而且会加大css编译后的体积

4. 从不使用@extend为ui组件在组件修改器，因为你丢失了继承链(这一点)

预处理程序中最好的部分是像@extend和 %placeholder的函数。这两者容许你轻松管理抽象出来的css，而没有增加你的css，或是在html中添加一大串很难管理的基础类名.

因为有时你想在你的html中使用这些类名@extend应该小心使用。例如，当你第一次了解@extend，你可能会在你的所有的修改类里面尝试的使用它，就像这样：

.button {
/* button styles */
}

/* Bad */
.button--primary {
@extend .button;
/* modification styles */
}

这样做的问题是在html中你丢失了继承链。现在用javascript很难选中所有的按钮实例。

作为一般的规则，我从来不扩展ui组件，或是以后我可能想要了解的类型。这是从另一个方面帮助区别模版与组件的方式。模版是一些在你的应用程序逻辑中不需要考虑的目标，所以可以安全的用预处理程序扩展。

下面是他如何使用上面模态例子引用

.modal {
@extend %dialog;
@extend %drop-shadow;
@extend %statically-centered;
/* other modal styles */
}

.modal__close {
@extend %dialog__close;
/* other close button styles */
}

.modal__header {
@extend %background-gradient;
/* other modal header styles */
}

CSS Lint

Nicole Sullivan 和 Nicholas Zakas 创建了 CSS Lint 作为一个工具，用来帮助开发人员在他们的css中检查不好的实践。他们的网站上这样描述：

Css lint指出你的css代码的问题。他有基础语法检查，也应用一组代码规则，查找问题模式或低效率迹象。规则都是可以插入的，所以你可以容易的书写自己的或是省略你不想要的规则

尽管通用规则可能不适用大多数项目，css lint最好的特性是它可以定制成你想要的。这意味着你可以从他们默认的列表里选择你想要的样式，也可以编写自己的样式。

对于任何一个大型团队像css lint这样的工具是必要的，用以确保基本的一致性和符合约定。就像我前面暗示的一样，一个约定的主要原因是像css lint这样的工具所以可以容易的识别破坏他们的规则。

基于上面我提出的约定，书写特定的反模式规则变得很容易。这里有一些我使用的建议

1. 在你的选择器里不容许使用id

2. 在任何由多个部分组成的规则里不要使用类型选择器(如div，span)

3. 在一个选择器里不要使用多于两个关系选择器

4. 不容许任何类名以‘js-’开头

5. 如果经常在布局和定位中使用没有‘l-’前缀的规则出现警告

6. 如果一个类名定义本身，之后作为其他元素的子元素重新定义出现警告

这些明显只是建议，但是可以促进你思考如何在你的项目中执行标准。

HTML校检

早期我建议可以搜索你的html中类名和所有链接的样式表，如果在html中出现的类名，但是在任何一个样式表里面没有定义，就会出警告。我现在在开发一个叫HTML Inspector的工具（我将很快放源）使得这个过程更容易。

Html Inspector遍历你的html代码(像css lint)容许你写自己的规则，当一些约定规则破坏时候抛出错误和警告。我目前使用以下规则：

1. 如果相同的id不止一次出现在一个页面上，就会有警告

2. 不使用任何在任何样式表或是通过的白名单里没有提到的类名(像“js-”前缀的类名)

3. 没有基类名不应该使用modifer类

4. 没有祖先元素包含基类子元素类名不应该使用

5. 普通的旧div或是span元素，没有附加类，不应该用于html

总结

Css并不只是视觉设计。不要仅仅因为你在写css就扔掉编程中的最佳实践。像面向对象，dry概念，开闭原则，关注点分离等等，仍然适用于css。

底线是任何可以组织你的代码的东西，确保你判断你的方法是否有效帮助你开发容易，长期更易维护。

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

如需转载烦请注明出处：

英文原文：http://engineering.appfolio.com/2012/11/16/css-architecture

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

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

修改document.domain的注意事项

有时候，需要修改document.domain。

典型的情形：http://a.xxx.com/A.htm 的主页面有一个<iframe src="http://b.xxx.com/B.htm"></iframe>，两个页面的js如何进行交互？
实现跨域交互的方式有很多，其中这种跨子域的交互，最简单方式就是通过设置document.domain：只需要在A.htm与B.htm里都加上这一句document.domain = 'xxx.com'，两个页面就有了互信的基础，而能无碍的交互。
示例：http://www.wagang.net/jk/document_domain/A.htm
这种实现跨域的方式很简单，并且主流浏览器都支持（IE6+、Firefox、Chrome等）不过，更改document.domain，会有一系列的副作用，为后续的工作留下隐患。

本文收集列举这些注意事项，以供参考。

1. 如果修改了document.domain，则在某些机器上的IE678里，获取location.href有权限异常。
例：

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JK</title>
<script>
document.domain='wagang.net';
</script>
</head>
<body >
IE678下，有时获取location.href时有异常：<input type=button value='alert(location.href);' onclick="alert(window.location.href);"> 参见：http://bugs.jquery.com/ticket/8138 jquery ticket#8138 <hr>
jQuery中相应的代码：
<pre>
// #8138, IE may throw an exception when accessing
// a field from window.location if document.domain has been set
try {
ajaxLocation = location.href;
} catch( e ) {
// Use the href attribute of an A element
// since IE will modify it given document.location
ajaxLocation = document.createElement( "a" );
ajaxLocation.href = "";
ajaxLocation = ajaxLocation.href;
}
</pre><hr>
也可以用：document.URL来获取：<input type=button value='alert(document.URL);' onclick="alert(document.URL);">

</body>
</html>

2. 如果页面修改了document.domain，则它包含的iframe，必须也设domain，才能进行交互。就算是同域的页面也必须要设。
这个例子里：http://www.wagang.net/jk/document_domain/A2.htm
由于页面设了document.domain，导致它包含的本域页面不能与它交互，因为iframe里的页面没有设置document.domain
3.  设置document.doamin，也会影响到其它跟iframe有关的功能。
典型的功能如：富文本编辑器（因为是iframe来做富文本编辑器的）、ajax的前进后退（因为IE67要用到iframe，参见：IE6与location.hash和Ajax历史记录）
4.  设置document.doamin，导致ie6下无法向一个iframe提交表单。
这一篇文章里列了问题象与解决方案：IE6与location.hash和Ajax历史记录

附：跟跨域相关的几个参考：
QW.XPC ：  利用window.name(IE6、7)和postMessage跨域传输数据
屈屈博客： 也谈跨域数据交互解决方案
三水清博客： 用document.domain+iframe实现Ajax跨子域

原文链接：http://www.cnblogs.com/jkisjk/archive/2013/05/30/change_document_domain.html （本内容由互联网资料整理而成）

JavaScript的装载和执行

一两个月前在淘宝内网里看到一个优化Javascript代码的竞赛，发现有不少的人对Javascript的执行和装载的基础并不懂，所以，从那天起我就想写一篇文章，但一直耽搁了。自上篇《浏览器渲染原理简介》，正好也可以承前启后。

首先，我想说一下Javascript的装载和执行。通常来说，浏览器对于Javascript的运行有两大特性：1）载入后马上执行，2）执行时会阻塞页面后续的内容（包括页面的渲染、其它资源的下载）。于是，如果有多个js文件被引入，那么对于浏览器来说，这些js文件被被串行地载入，并依次执行。

因为javascript可能会来操作HTML文档的DOM树，所以，浏览器一般都不会像并行下载css文件并行下载js文件，因为这是js文件的特殊性造成的。所以，如果你的javascript想操作后面的DOM元素，基本上来说，浏览器都会报错说对象找不到。因为Javascript执行时，后面的HTML被阻塞住了，DOM树时还没有后面的DOM结点。所以程序也就报错了。

传统的方式

所以，当你写在代码中写下如下的代码：

<script type="text/javascript"
src="http://coolshell.cn/asyncjs/alert.js"></script>

基本上来说，head里的 <script>标签会阻塞后续资源的载入以及整个页面的生成。我专门做了一个示例你可以看看：示例一。 注意：我的alert.js中只有一句话：alert(“hello world”) ，这更容易让你看到javascript是自知阻塞的。 所以，你知道为什么有很多网站把javascript放在网页的最后面了。因为，绝大多数的Javascript代码并不需要等

document.write方式

于是，你可能以为document.write()这种方式能够解决不阻塞的方式。你当然会觉得，document.write了<script>标签后就可以执行后面的东西去了，这没错，对于在同一个script标签里的Javascript的代码来说，是这样的，但是对于整个页面来说，这个还是会阻塞。 下面是一段测试代码：

<script type="text/javascript" language="javascript">
function loadjs(script_filename) {
document.write('<' + 'script language="javascript" type="text/javascript"');
document.write(' src="' + script_filename + '">');
document.write('<'+'/script'+'>');
alert("loadjs() exit...");
}

var script = 'http://coolshell.cn/asyncjs/alert.js';

loadjs(script);
alert("loadjs() finished!");
</script>

<script type="text/javascript" language="javascript">
alert("another block");
</script>

你觉得alert的顺序是什么？这里的想关的测试页面：示例二。

script的defer和async属性

IE自从IE6就支持defer标签，如：

<script defer type="text/javascript" src="./alert.js" >
</script>

对于IE来说，这个标签会让IE并行下载js文件，并且把其执行hold到了整个DOM装载完毕（DOMContentLoaded），多个defer的<script>在执行时也会按照其出现的顺序来运行。最重要的是<script>被加上defer后，其不会阻塞后续DOM的的渲染。但是因为这个defer只是IE专用，所以一般用得比较少。

而我们的HTML5也加入了一个异步载入javascript的属性：async，无论你对它赋什么样的值，只要它出现，它就开始异步加载js文件。但是， async的异步加载会有一个比较严重的问题，那就是它踏实地践行着：载入后马上执行这条军规，所以，虽然它并不阻塞页面的渲染，但是你也无法控制他执行的次序和时机。你可以看看这个示例去感受一下。

支持 async标签的浏览器是：Firefox3.6+，Chrome 8.0+，Safari 5.0+，IE 10+，Opera还不支持（来自这里）所以这个方法也不是太好。因为并不是所有的浏览器你都能行。

动态创建DOM方式

这种方式可能是用得最多的了。

function loadjs(script_filename) {
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', script_filename);
script.setAttribute('id', 'coolshell_script_id');

script_id = document.getElementById('coolshell_script_id');
if(script_id){
document.getElementsByTagName('head')[0].removeChild(script_id);
}
document.getElementsByTagName('head')[0].appendChild(script);
}

var script = 'http://coolshell.cn/asyncjs/alert.js';
loadjs(script);

这个方式几乎成了标准的异步载入js文件的方式，这个方式的演示请参看：示例三。这方式还被玩出了JSONP的东东，也就是我可以为script的src指定个后在台的脚本（如PHP），而这个PHP返回一个javascript函数，其参数是一个json的字符串，返回来调用我们的javascript的参数。你可以看一下这个示例：t.js （这个示例是我之前在微博征集的一个异步ajax调用的小例子）

按需异步载入js

上面那个DOM方式的例子解决了异步载入Javascript的问题，但是没有解决我们想让他按我们指定的时机运行的问题。所以，我们只需要把上面那个DOM方式绑到某个事件上来就可以了。

比如：

绑在window.load事件上——示例四

你一定要比较一下示例四和示例三在执行上有什么不同，我在这两个示例中都专门用了个代码高亮的javascript，看看那个代码高亮的的脚本的执行和我的alert.js的执行的情况，你就知道不同了）

window.load = loadjs("http://coolshell.cn/asyncjs/alert.js")

绑在特定的事件上——示例五

<p style="cursor: pointer" onclick="LoadJS()">Click to load alert.js </p>

这个示例很简单了。当你点击某个DOM元素，才会真正载入我们的alert.js。

更多

但是，绑定在事件上这个事似乎又过了一点，因为只有在点击的时候才会去真正的下载。这会太慢了了。好了，到这里，要抛出我们的终极问题——我们想要异步地把js文件下载到用户的本地，但是不执行，仅当在我们想要执行的时候去执行。

要是我们有下面这样的试就好了：

var script = document.createElement("script");
script.noexecute = true;
script.src = "alert.js";
document.body.appendChild(script);

//后面我们可以这么干
script.execute();

可惜的是，这只是一个美丽的梦想，今天我们的Javascript还比较原始，这个JS梦还没有实现呢。

所以，我们的程序员只能使用hack的方式来搞。

有的程序员使用了非标准的script的type来cache javascript。如：

<script type=cache/script src="./alert.js"></script>

因为”cache/script”，这个东西根本就不能被浏览器解析，所以浏览器也就不执能把alert.js当javascript去执行，但是他又要去下载js文件，所以就可以搞定了。可惜的是，webkit严格符从了HTML的标准——对于这种不认识的东西，直接删除，什么也不干。于是，我们的梦又破了。

所以，我们需要再hack一下，就像N多年前玩preload图片那样，我们可以动用object标签，于是我们有下面这样的代码：

function cachejs(script_filename){
var cache = document.createElement('object');
cache.data = script_filename;
cache.id = "coolshell_script_cache_id";
cache.width = 0;
cache.height = 0;
document.body.appendChild(cache);
}

然后，我们在的最后调用一下这个函数。请参看一下相关的示例：示例六

在Chrome下按 Ctrl+Shit+I，切换到network页，你就可以看到下载了alert.js但是没有执行，然后我们再用示例五的方式，因为浏览器端有缓存了，不会再多服务器上下载alert.js了。所以，就能保证执行速度了。

关于这种preload你应该不会陌生了。你还可以使用Ajax的方式，如：

var xhr = new XMLHttpRequest();
xhr.open('GET', 'new.js');
xhr.send('');

我这里不就再多说了。
好了，这是所有的内容了，希望大家看过后能对Javascript的载入和执行，以及相关的技术有个了解。同时，也希望各前端高手不吝赐教！

（全文完）

（转载本站文章请注明作者和出处 酷壳 – CoolShell.cn ，请勿用于任何商业用途）

——=== 访问 酷壳404页面 以支持公益事业 ===——

(没人打分)

Loading ...

原文链接：http://coolshell.cn/articles/9749.html （本内容由互联网资料整理而成）

深入脚本加载的浑水

Introduction

In this article I’m going to teach you how to load some JavaScript in the browser and execute it.

No, wait, come back! I know it sounds mundane and simple, but remember, this is happening in the browser where the theoretically simple becomes a legacy-driven quirk-hole. Knowing these quirks lets you pick the fastest, least disruptive way to load scripts. If you’re on a tight schedule, skip to the quick reference.

For starters, here’s how the spec defines the various ways a script could download and execute:

The WHATWG on script loading

Like all of the WHATWG specs, it initially looks like the aftermath of a cluster bomb in a scrabble factory, but once you’ve read it for the 5th time and wiped the blood from your eyes, it’s actually pretty interesting:

My first script include

<script src="//other-domain.com/1.js"></script>
<script src="2.js"></script>

Ahh, blissful simplicity. Here the browser will download both scripts in parallel and execute them as soon as possible, maintaining their order. “2.js” won’t execute until “1.js” has executed (or failed to do so), “1.js” won’t execute until the previous script or stylesheet has executed, etc etc.

Unfortunately, the browser blocks further rendering of the page while all this is happening. This is due to DOM APIs from “the first age of the web” that allow strings to be appended onto the content the parser is chewing through, such as document.write. Newer browsers will continue to scan or parse the document in the background and trigger downloads for external content it may need (js, images, css etc), but rendering is still blocked.

This is why the great and the good of the performance world recommend putting script elements at the end of your document, as it blocks as little content as possible. Unfortunately it means your script isn’t seen by the browser until it downloads all your HTML, and by that point it’s started downloading other content, such as CSS, images and iframes. Modern browsers are smart enough to give priority to JavaScript over imagery, but we can do better.

Thanks IE! (no, I’m not being sarcastic)

<script src="//other-domain.com/1.js" defer></script>
<script src="2.js" defer></script>

Microsoft recognised these performance issues and introduced “defer” into Internet Explorer 4. This basically says “I promise not to inject stuff into the parser using things like document.write. If I break that promise, you are free to punish me in any way you see fit”. This attribute made it into HTML4 and appeared in other browsers.

In the above example, the browser will download both scripts in parallel and execute them just before DOMContentLoaded fires, maintaining their order.

Like a cluster-bomb in a sheep factory, “defer” became a wooly mess. Between “src” and “defer” attributes, and script tags vs dynamically added scripts, we have 6 patterns of adding a script. Of course, the browsers didn’t agree on the order they should execute. Mozilla wrote a great piece on the problem as it stood back in 2009.

The WHATWG made the behaviour explicit, declaring “defer” to have no effect on scripts that were dynamically added, or lacked “src”. Otherwise, deferred scripts should run after the document had parsed, in the order they were added.

Thanks IE! (ok, now I’m being sarcastic)

It giveth, it taketh away. Unfortunately there’s a nasty bug in IE4-9 that can cause scripts to execute in an unexpected order. Here’s what happens:

1.js

console.log('1');
document.getElementsByTagName('p')[0].innerHTML = 'Changing some content';
console.log('2');

2.js

console.log('3');

Assuming there’s a paragraph on the page, the expected order of logs is [1, 2, 3], although in IE9 and below you get [1, 3, 2]. Particular DOM operations cause IE to pause current script execution and execute other pending scripts before continuing.

However, even in non-buggy implementations, such as IE10 and other browsers, script execution is delayed until the whole document has downloaded and parsed. This can be convenient if you’re going to wait for DOMContentLoaded anyway, but if you want to be really aggressive with performance, you can start adding listeners and bootstrapping sooner…

HTML5 to the rescue

<script src="//other-domain.com/1.js" async></script>
<script src="2.js" async></script>

HTML5 gave us a new attribute, “async”, that assumes you’re not going to use document.write, but doesn’t wait until the document has parsed to execute. The browser will download both scripts in parallel and execute them as soon as possible.

Unfortunately, because they’re going to execute as soon as possible, “2.js” may execute before “1.js”. This is fine if they’re independent, perhaps “1.js” is a tracking script which has nothing to do with “2.js”. But if your “1.js” is a CDN copy of jQuery that “2.js” depends on, your page is going to get coated in errors, like a cluster-bomb in a… I dunno… I’ve got nothing for this one.

I know what we need, a JavaScript library!

The holy grail is having a set of scripts download immediately without blocking rendering and execute as soon as possible in the order they were added. Unfortunately HTML hates you and won’t let you do that.

The problem was tackled by JavaScript in a few flavours. Some required you to make changes to your JavaScript, wrapping it in a callback that the library calls in the correct order (eg RequireJS). Others would use XHR to download in parallel then eval() in the correct order, which didn’t work for scripts on another domain unless they had a CORS header and the browser supported it. Some even used super-magic hacks, like the late LabJS.

The hacks involved tricking the browser into downloading the resource in a way that would trigger an event on completion, but avoid executing it. In LabJS, the script would be added with an incorrect mime type, eg <script type="script/cache" src="...">. Once all scripts had downloaded, they’d be added again with a correct type, hoping the browser would get them straight from the cache and execute them immediately, in order. This depended on convenient but unspecified behaviour and broke when HTML5 declared browsers shouldn’t download scripts with an unrecognised type.

Both of these techniques have a performance problem of their own, you have to wait for the library’s JavaScript to download and parse before any of scripts it manages can begin downloading. Also, how are we going to load the script loader? How are we going to load the script that tells the script loader what to load? Who watches the Watchmen? Why am I naked? These are all difficult questions.

The DOM to the rescue

The answer is actually in the HTML5 spec, although it’s hidden away at the bottom of the script-loading section.

The async IDL attribute controls whether the element will execute asynchronously or not. If the element's "force-async" flag is set, then, on getting, the async IDL attribute must return true, and on setting, the "force-async" flag must first be unset…

Let’s translate that into “Earthling”:

[
'//other-domain.com/1.js',
'2.js'
].forEach(function(src) {
var script = document.createElement('script');
script.src = src;
document.head.appendChild(script);
});

Scripts that are dynamically created and added to the document are async by default, they don’t block rendering and execute as soon as they download, meaning they could come out in the wrong order. However, we can explicitly mark them as not async:

[
'//other-domain.com/1.js',
'2.js'
].forEach(function(src) {
var script = document.createElement('script');
script.src = src;
script.async = false;
document.head.appendChild(script);
});

This gives our scripts a mix of behaviour that can’t be achieved with plain HTML. By being explicitly not async, scripts are added to an execution queue, the same queue they’re added to in our first plain-HTML example. However, by being dynamically created, they’re executed outside of document parsing, so rendering isn’t blocked while they’re downloaded (don’t confuse not-async script loading with sync XHR, which is never a good thing).

The script above should be included inline in the head of pages, queueing script downloads as soon as possible without disrupting progressive rendering, and executes as soon as possible in the order you specified. “2.js” is free to download before “1.js”, but it won’t be executed until “1.js” has either successfully downloaded and executed, or fails to do either. Hurrah! async-download but ordered-execution!

Loading scripts this way is supported by everything that supports the async attribute, with the exception of Safari 5.0 (5.1 is fine). Additionally, all versions of Firefox and Opera are supported as versions that don’t support the async attribute conveniently execute dynamically-added scripts in the order they’re added to the document anyway.

That’s the fastest way to load scripts right? Right?

Well, if you’re dynamically deciding which scripts to load, yes, otherwise, perhaps not. With the example above the browser has to parse and execute script to discover which scripts to download. This hides your scripts from preload scanners. Browsers use these scanners to discover resources on pages you’re likely to visit next, or discover page resources while the parser is blocked by another resource.

We can add discoverability back in by putting this in the head of the document:

<link rel="subresource" href="//other-domain.com/1.js">
<link rel="subresource" href="2.js">

This tells the browser the page needs 1.js and 2.js, and is visible to preloaders. link[rel=subresource] is similar to link[rel=prefetch], but with different semantics. Unfortunately it’s currently only supported in Chrome, and you have to declare which scripts to load twice, once via link elements, and again in your script.

I find this article depressing.

The situation is depressing and you should feel depressed. There’s no non-repetitive yet declarative way to download scripts quickly and asynchronously while controlling the execution order.

With HTTP2/SPDY you can reduce the request overhead to the point where delivering scripts in multiple small individually-cacheable files can be the fastest way. Imagine:

<script src="dependencies.js"></script>
<script src="enhancement-1.js"></script>
<script src="enhancement-2.js"></script>
<script src="enhancement-3.js"></script>
…
<script src="enhancement-10.js"></script>

Each enhancement script deals with a particular page component, but requires utility functions in dependencies.js. Ideally we want to download all asynchronously, then execute the enhancement scripts as soon as possible, in any order, but after dependencies.js. It’s progressive progressive enhancement!

Unfortunately there’s no declarative way to achieve this unless the scripts themselves are modified to track the loading state of dependencies.js. Even async=false doesn’t solve this issue, as execution of enhancement-10.js will block on 1-9. In fact, there’s only one browser that makes this possible without hacks…

IE has an idea!

IE loads scripts differently to other browsers.

var script = document.createElement('script');
script.src = 'whatever.js';

IE starts downloading “whatever.js” now, other browsers don’t start downloading until the script has been added to the document. IE also has an event, “readystatechange”, and property, “readystate”, which tell us the loading progress. This is actually really useful, as it lets us control the loading and executing of scripts independently.

var script = document.createElement('script');

script.onreadystatechange = function() {
if (script.readyState == 'loaded') {
// Our script has download, but hasn't executed.
// It won't execute until we do:
document.body.appendChild(script);
}
};

script.src = 'whatever.js';

We can build complex dependency models by choosing when to add scripts into the document. IE has supported this model since version 6. Pretty interesting, but it still suffers from the same preloader discoverability issue as async=false.

Enough! How should I load scripts?

Ok ok. If you want to load scripts in a way that doesn’t block rendering, doesn’t involve repetition, and has excellent browser support, here’s what I propose:

<script src="//other-domain.com/1.js"></script>
<script src="2.js"></script>

That. At the end of the body element. Yes, being a web developer is much like being King Sisyphus (boom! 100 hipster points for Greek mythology reference!). Limitations in HTML and browsers prevent us doing much better.

I’m hoping JavaScript modules will save us by providing a declarative non-blocking way to load scripts and give control over execution order, although this requires scripts to be written as modules.

Eww, there must be something better we can use now?

Fair enough, for bonus points, if you want to get really aggressive about performance, and don’t mind a bit of complexity and repetition, you can combine a few of the tricks above.

First up, we add the subresource declaration, for preloaders:

<link rel="subresource" href="//other-domain.com/1.js">
<link rel="subresource" href="2.js">

Then, inline in the head of the document, we load our scripts with JavaScript, using async=false, falling back to IE’s readystate-based script loading, falling back to defer.

var scripts = [
'1.js',
'2.js'
];
var src;
var script;
var pendingScripts = [];
var firstScript = document.scripts[0];

// Watch scripts load in IE
function stateChange() {
// Execute as many scripts in order as we can
var pendingScript;
while (pendingScripts[0] && pendingScripts[0].readyState == 'loaded') {
pendingScript = pendingScripts.shift();
// avoid future loading events from this script (eg, if src changes)
pendingScript.onreadystatechange = null;
// can't just appendChild, old IE bug if element isn't closed
firstScript.parentNode.insertBefore(pendingScript, firstScript);
}
}

// loop through our script urls
while (src = scripts.shift()) {
if ('async' in firstScript) { // modern browsers
script = document.createElement('script');
script.async = false;
script.src = src;
document.head.appendChild(script);
}
else if (firstScript.readyState) { // IE<10
// create a script and add it to our todo pile
script = document.createElement('script');
pendingScripts.push(script);
// listen for state changes
script.onreadystatechange = stateChange;
// must set src AFTER adding onreadystatechange listener
// else we’ll miss the loaded event for cached scripts
script.src = src;
}
else { // fall back to defer
document.write('<script src="' + src + '" defer></'+'script>');
}
}

A few tricks and minification later, it’s 362 bytes + your script URLs:

!function(e,t,r){function n(){for(;d[0]&&"loaded"==d[0][f];)c=d.shift(),c[o]=!i.parentNode.insertBefore(c,i)}for(var s,a,c,d=[],i=e.scripts[0],o="onreadystatechange",f="readyState";s=r.shift();)a=e.createElement(t),"async"in i?(a.async=!1,e.head.appendChild(a)):i[f]?(d.push(a),a[o]=n):e.write("<"+t+' src="'+s+'" defer></'+t+">"),a.src=s}(document,"script",[
"//other-domain.com/1.js",
"2.js"
])

Is it worth the extra bytes compared to a simple script include? If you’re already using JavaScript to conditionally load scripts, as the BBC do, you may as well benefit from triggering those downloads earlier. Otherwise, perhaps not, stick with the simple end-of-body method.

Phew, now I know why the WHATWG script loading section is so vast. I need a drink.

Quick reference

Plain script elements

<script src="//other-domain.com/1.js"></script>
<script src="2.js"></script>

Spec says: Download together, execute in order after any pending CSS, block rendering until complete.

Browsers say: Yes sir!

Defer

<script src="//other-domain.com/1.js" defer></script>
<script src="2.js" defer></script>

Spec says: Download together, execute in order just before DOMContentLoaded. Ignore “defer” on scripts without “src”.

IE < 10 says: I might execute 2.js halfway through the execution of 1.js. Isn’t that fun??

The browsers in red say: I have no idea what this “defer” thing is, I’m going to load the scripts as if it weren’t there.

Other browsers say: Ok, but I might not ignore “defer” on scripts without “src”.

Async

<script src="//other-domain.com/1.js" async></script>
<script src="2.js" async></script>

Spec says: Download together, execute in whatever order they download in.

The browsers in red say: What’s ‘async’? I’m going to load the scripts as if it weren’t there.

Other browsers say: Yeah, ok.

Async false

[
'1.js',
'2.js'
].forEach(function(src) {
var script = document.createElement('script');
script.src = src;
script.async = false;
document.head.appendChild(script);
});

Spec says: Download together, execute in order as soon as all download.

Firefox < 3.6, Opera says: I have no idea what this “async” thing is, but it just so happens I execute scripts added via JS in the order they’re added.

Safari 5.0 says: I understand “async”, but don’t understand setting it to “false” with JS. I’ll execute your scripts as soon as they land, in whatever order.

IE < 10 says: No idea about “async”, but there is a workaround using “onreadystatechange”.

Other browsers in red say: I don’t understand this “async” thing, I’ll execute your scripts as soon as they land, in whatever order.

Everything else says: I’m your friend, we’re going to do this by the book.

原文链接：http://www.html5rocks.com/en/tutorials/speed/script-loading/ （本内容由互联网资料整理而成）

避免JavaScript重复工作

I love to scavenge the source code of the web's large sites, looking for patterns to both apply to my coding and to find hacks or techniques I'd not heard of before.  One problem I often find with the coding of large sites is repeated operations.  There are a few different mistakes I see when looking at their code and I want to share those with you so you can speed up your own JavaScript code.

Repeated Element Collection

The most problem I see most often is JavaScript code is repeated element collection.  Selector engines and querySelectorAll have gotten to be very fast but repeated work is always a slower than doing the work once.  Obviously the problem and solution look like:

// :(
$$(".items").addClass("hide");
// ... and later ...
$$(".items").removeClass("hide");

//  :)
var items = $$(".items");
// ... and use to heart's content from here on out!

Scolding developers for repeated element collection is a daily occurrence but this scolding needs to be reinforced.  Of course repeated element collection cannot always be avoided (think sites with AJAX page loads), but in those cases, you will most likely want to use event delegation instead of direct element retrieval and event application.

Repeated Conditionals

Repeated condition calculation is a common case but also a common pattern which can be avoided.  You will see something like this:

var performMiracle = function() {
// If the browser has feature A, use it...
if(features.someFeature) {

}
// ... if not, do another
else {

}
};

It works but it's not the most efficient use of code, and the conditional checks are run upon each call.  Instead, something like this would be better:

var performMiracle = features.someFeature ? function() {
// Plan A stuff
} : function() {
// Plan B stuff
};

Only one conditional and the method or variable is already set to the result of the conditional!

Repeated Object Creation

On repeated operation that goes under the radar is repeated object creation, usually in the form of a regular expression.  Consider the following:

function cleanText(dirty) {
// Get rid of SCRIPT tags
clean = dirty.replace(/

原文链接：http://davidwalsh.name/javascript-optimization （本内容由互联网资料整理而成）

JS异步编程：Callbacks, Listeners, Control Flow Libs and Promises

When it comes to dealing with asynchronous development in JavaScript there are many tool you can use. This post explains four of these tools and what their advantages are. These are Callbacks, Listeners, Control Flow Libraries and Promises.

Example Scenario

To illustrate the use of these four tools, let’s create a simple example scenario.

Let’s say that we want to find some records, then process them and finally return the processed results. Both operations (find and process) are asynchronous.

Photo credit: bitzcelt / Foter / CC BY-NC-ND

Callbacks

Let’s start with callback pattern, this is the most basic and the best known pattern to deal with async programming.

A callback looks like this:

1
2
3

finder([1, 2], function(results) {
..do something
});

In the callback pattern we call a function that will do the asynchronous operation. One of the parameters we pass is a function that will be called when the operation is done.

Setup

In order to illustrate how they work we need a couple of functions that will find and process the records. In the real world these functions will make an AJAX request and return the results, but for now let’s just use timeouts.

1
2
3
4
5
6
7
8
9
10
11
12

function finder(records, cb) {
setTimeout(function () {
records.push(3, 4);
cb(records);
}, 1000);
}
function processor(records, cb) {
setTimeout(function () {
records.push(5, 6);
cb(records);
}, 1000);
}

Using the callbacks

The code that consumes these functions looks like this:

1
2
3
4
5

finder([1, 2], function (records) {
processor(records, function(records) {
console.log(records);
});
});

We call the first function, passing a callback. Inside this callback we call the second function passing another callback.

These nested callbacks can be written more clearly by passing a reference to another function.

1
2
3
4
5
6
7
8
9

function onProcessorDone(records){
console.log(records);
}
function onFinderDone(records) {
processor(records, onProcessorDone);
}
finder([1, 2], onFinderDone);

In both case the console log above with log [1,2,3,4,5,6]

Working example here:

Pros

- They are a very well know pattern, so they are familiar thus easy to understand.

- Very easy to implement in your own libraries / functions.

Cons

- Nested callbacks will form the infamous pyramid of doom as shown above, which can get hard to read when you have multiple nested levels. But this is quite easy to fix by splitting the functions also as shown above.

- You can only pass one callback for a given event, this can be a big limitation in many cases.

Photo credit: Brandon Christopher Warren / Foter / CC BY-NC

Listeners

Listeners are also a well known pattern, mostly made popular by jQuery and other DOM libraries. A Listener might look like this:

1
2
3

finder.on('done', function (event, records) {
..do something
});

We call a function on an object that adds a listener. In that function we pass the name of the event we want to listen to and a callback function. ‘on’ is one of many common name for this function, other common names you will come across are ‘bind’, ‘listen’, ‘addEventListener’, ‘observe’.

Setup

Let’s do some setup for a listener demonstration. Unfortunately the setup needed is a bit more involving than in the callbacks example.

First we need a couple of objects that will do the work of finding and processing the records.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

var finder = {
run: function (records) {
var self = this;
setTimeout(function () {
records.push(3, 4);
self.trigger('done', [records]);
}, 1000);
}
}
var processor = {
run: function (records) {
var self = this;
setTimeout(function () {
records.push(5, 6);
self.trigger('done', [records]);
}, 1000);
}
}

Note that they are calling a method trigger when the work is done, I will add this method to these objects using a mix-in. Again ‘trigger’ is one of the names you will come across, others common names are ‘fire’ and ‘publish’.

We need a mix-in object that has the listener behaviour, in this case I will just lean on jQuery for this:

1
2
3
4
5
6
7
8

var eventable = {
on: function(event, cb) {
$(this).on(event, cb);
},
trigger: function (event, args) {
$(this).trigger(event, args);
}
}

Then apply the behaviour to our finder and processor objects:

1
2

$.extend(finder, eventable);
$.extend(processor, eventable);

Excellent, now our objects can take listeners and trigger events.

Using the listeners

The code that consumes the listeners is simple:

1
2
3
4
5
6
7

finder.on('done', function (event, records) {
processor.run(records);
});
processor.on('done', function (event, records) {
console.log(records);
});
finder.run([1,2]);

Again the console run will output [1,2,3,4,5,6]

Working example here:

Pros

- This is another well understood pattern.

- The big advantage is that you are not limited to one listener per object, you can add as many listeners as you want. E.g.

1
2
3
4
5
6
7

finder
.on('done', function (event, records) {
.. do something
})
.on('done', function (event, records) {
.. do something else
});

Cons

- A bit more difficult to setup than callbacks in your own code, you will probably want to use a library e.g. jQuery, bean.js.

Photo credit: Nod Young / Foter / CC BY-NC-SA

A Flow Control Library

Flow control libraries are also a very nice way to deal with asynchronous code. One I particularly like is Async.js.

Code using Async.js looks like this:

1
2
3
4

async.series([
function(){ ... },
function(){ ... }
]);

Setup (Example 1)

Again we need a couple of functions that will do the work, as in the other examples these functions in the real world will probably make an AjAX request and return the results. For now let’s just use timeouts.

1
2
3
4
5
6
7
8
9
10
11
12

function finder(records, cb) {
setTimeout(function () {
records.push(3, 4);
cb(null, records);
}, 1000);
}
function processor(records, cb) {
setTimeout(function () {
records.push(5, 6);
cb(null, records);
}, 1000);
}

The Node Continuation Passing Style

Note the style used in the callbacks inside the functions above.

The first argument in the callback is null if no error occurs; or the error if one occurs. This is a common pattern in Node.js libraries and Async.js uses this pattern. By using this style the flow between Async.js and the callbacks becomes super simple.

Using Async

The code that will consume these functions looks like this:

1
2
3
4
5
6
7
8
9

async.waterfall([
function(cb){
finder([1, 2], cb);
},
processor,
function(records, cb) {
alert(records);
}
]);

Async.js takes care of calling each function in order after the previous one has finished. Note how we can just pass the ‘processor’ function, this is because we are using the Node continuation style. As you can see this code is quite minimal and easy to understand.

Working example here:

Another setup (Example 2)

Now, when doing front-end development it is unlikely that you will have a library that follows the callback(null, results) signature. So a more realistic example will look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

function finder(records, cb) {
setTimeout(function () {
records.push(3, 4);
cb(records);
}, 500);
}
function processor(records, cb) {
setTimeout(function () {
records.push(5, 6);
cb(records);
}, 500);
}
// using the finder and the processor
async.waterfall([
function(cb){
finder([1, 2], function(records) {
cb(null, records)
});
},
function(records, cb){
processor(records, function(records) {
cb(null, records);
});
},
function(records, cb) {
alert(records);
}
]);

It becomes a lot more convoluted but at least you can see the flow going from top to bottom.

Working example here:

Pros

- Usually code using a control flow library is easier to understand because it follows a natural order (from top to bottom). This is not true with callbacks and listeners.

Cons

- If the signatures of the functions don’t match as in the second example then you can argue that the flow control library offers little in terms of readability.

Photo credit: Helmut Kaczmarek / Foter / CC BY-NC-SA

Promises

Finally we get to our final destination. Promises are a very powerful tool, but they are the least understood.

Code using promises may look like this:

1
2
3
4

finder([1,2])
.then(function(records) {
.. do something
});

This will vary widely depending on the promises library you use, in this case I am using when.js.

Setup

Out finder and processor functions look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

function finder(records){
var deferred = when.defer();
setTimeout(function () {
records.push(3, 4);
deferred.resolve(records);
}, 500);
return deferred.promise;
}
function processor(records) {
var deferred = when.defer();
setTimeout(function () {
records.push(5, 6);
deferred.resolve(records);
}, 500);
return deferred.promise;
}

Each function creates a deferred object and returns a promise. Then it resolves the deferred when the results arrive.

Using the promises

The code that consumes these functions looks like this:

1
2
3
4
5

finder([1,2])
.then(processor)
.then(function(records) {
alert(records);
});

As you can see, it is quite minimal and easy to understand. When used like this, promises bring a lot of clarity to your code as they follow a natural flow. Note how in the first callback we can simply pass the ‘processor’ function. This is because this function returns a promise itself so everything will just flow nicely.

Working example here:

There is a lot to promises:

- they can be passed around as regular objects

- aggregated into bigger promises

- you can add handlers for failed promises

The big benefit of promises

Now if you think that this is all there is to promises you are missing what I consider the biggest advantage. Promises have a neat trick that neither callbacks, listeners or control flows can do. You can add a listener to promise even when it has already been resolved, in this case that listener will trigger immediately, meaning that you don’t have to worry if the event has already happened when you add the listener. This works the same for aggregated promises. Let me show you an example of this:

This is a huge feature for dealing with user interaction in the browser. In complex applications you may not now the order of actions that the user will take, so you can use promises to track use interaction. See this other post if interested.

Pros

- Really powerful, you can aggregate promises, pass them around, or add listeners when already resolved.

Cons

- The least understood of all these tools.

- They can get difficult to track when you have lots of aggregated promises with added listeners along the way.

Conclusion

That’s it! These are in my opinion the four main tools for dealing with asynchronous code. Hopefully I have help you to understand them better and gave you more options for you asynchronous needs.

原文链接：http://sporto.github.io/blog/2012/12/09/callbacks-listeners-promises/ （本内容由互联网资料整理而成）

reset or Normalize

CSS: reset or normalize?

Building for the web can be like building on quicksand. Browsers have tended to do mostly the same thing, but have occasional, maddeningly unpredictable differences. For example, browsers all come with “user agent stylesheets” — a default set of CSS styles, so that a heading looks like a heading etc., even before you style the page[1]. Of course, every browser engine uses a slightly different set of defaults.

One example of this was default list styles, where Internet Explorer and Opera initially[2] indented lists with margin-left: 30pt; in their default browser stylesheets, while Firefox and KHTML went with padding-left: 40px;. If you wanted to change the default indent, specifying ul {padding-left: 0;} would lead to very different results across browsers.

CSS resets[3]

To get a little stability, some developers reset all margins and padding using the universal selector:

* {margin: 0; padding: 0;}

With this at the start of your stylesheet, when you specified a list indent you got what you expected. However, using * meant the default margin and padding were nuked for all elements, which became painful as soon as you added a <form> element.

Tantek Çelik and Eric Meyer started discussing a more targeted way to address user agent style differences in 2004, with the YUI CSS Reset appearing in 2006, and the Meyer Reset in 2007.

The point of a reset is to zero out as much as possible … [and] to serve as a starting point for your own baseline styles — Eric Meyer

Here’s the first rule of Eric’s current (v2.0) CSS Reset:

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
…

This resets several properties on many (but not all) elements back to the equivalent of plain text. Because only appropriate elements are reset, this avoids some of the problems of * {margin: 0; padding: 0;}. We can then define styles for these reset “unstyled” properties, safe in the knowledge we’re building on a stable, cross-browser base. This “unstyled” styling also acts as a reminder to consciously set appropriate styles for these elements.

Problems with CSS resets

CSS resets have been a lifesaver, but especially with the rise of frameworks they are now often used as-is. For example, Eric assumed people would build on the reset styles he proposed, overriding them as appropriate, and version 1 of the Meyer Reset included this rule for a time:

/* remember to define focus styles! */
:focus {
outline: 0;
}

Sadly, not everyone did define focus styles, and Eric has removed this from v2.

Using a reset can also start to feel a little perverse. Resetting browser default styles does force us to deliberate on how each element should appear, helping ensure we use elements for their semantics and not their default styling. But for elements like i and em that’s almost always the browser default style. Other default browser styles, like the text sizes for headings which used to be ridiculously large, have changed to become passable defaults. There’s also the problem of someone wanting to use a reset HTML element after handoff, still with only the “unstyled” reset styles specified.

For me the main issue with resets is inheritance, leading to spam in your browser dev tools. When you’re trying to track down a CSS problem on a deeply nested element in someone else’s code, this does not help:

CSS reset rules repeating due to inheritance

Normalize.css

Nicolas Gallagher and Jonathan Neal have taken a different approach with Normalize.css, “a small CSS file that provides better cross-browser consistency in the default styling of HTML elements”. As with CSS resets it gives us a reliable cross-browser starting point — the main reason for using a reset in the first place — but the two approaches are philosophically different.

CSS resets override user agent styles to return many elements back to an “unstyled” state, a level foundation we can safely build upon. However, we then need to define styles for most elements before we can build with them. Normalize.css instead addresses only the inconsistencies between user agent default styles, choosing the most appropriate default where there are differences. We get a safe cross-browser foundation here too, but one that includes normalized user agent styles as basic building materials ready for use. It’s basically a kind of an idealized, cross-browser version of CSS 2.1’s Default style sheet. For both ways we then need to add our own overriding styles to build the view, but because the browser defaults remain with Normalize.css, in general fewer styles need to be added.

Because the changes in Normalize.css are a lot more targeted, there isn’t an inheritance cascade of overwritten rules in your browser’s developer tools. Here’s a simple <ul>: “unstyled”, with the Meyer Reset, and with Normalize.css versions 1 and 2:

An “unstyled” unordered list element

Applying the Meyer Reset

Applying Normalize.css v1

Applying Normalize.css v2

You can clearly see the difference in philosophy, with the Meyer Reset example appearing as two lines of plain text with no margins, padding or bullets, while the Normalize.css examples are similar to the default styling. The difference in the styles applied to this <ul> are also easy to see.

However, these are not all the styles being applied to the <ul>. For comparison, here’s the same “unstyled” screenshot, but with the user agent styles visible, in Firefox 21 and Opera Next 15:

Mozilla user agent styles

Opera user agent styles

This is the CSS that we’re resetting or normalizing.

Normalize.css version 2 supports modern browsers plus IE 8, whereas version 1 also contains additional support for legacy browsers like IE 6 and 7. These older browsers need more normalization, and this can have minor disadvantages, for example the added vertical margins for the nested list in the Normalize.css v1 screenshot above. This split into two versions is useful if you no longer need to provide old browsers with Grade A support, and also if you want to learn about old browser quirks.

Normalize.css also helps correct some browser bugs, including “display settings for HTML5 elements, correcting font-size for preformatted text, SVG overflow in IE9, and many form-related bugs across browsers and operating systems”. For example, the following CSS fixes WebKit issues with HTML5’s new <input type="search"> element:

/**
* 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
*    (include `-moz` to future-proof).
*/

input[type="search"] {
-webkit-appearance: textfield; /* 1 */
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box; /* 2 */
box-sizing: content-box;
}

Without it, WebKit’s default use of -webkit-appearance: searchfield; for type="search" prevents the styling of font, padding, border, and background properties on OS X and iOS, and gives buggy behavior for the border property on Windows.

An added bonus is Normalize.css is heavily commented and well-documented, helping you learn why each rule is there. This does make it noticeably longer than CSS resets, but when minified and Gzipped even the larger Normalize.css v1 is only 1KB.

Conclusion

While philosophically different to CSS resets like the Meyer Reset, Normalize.css is very much carrying on the same tradition, continuing in the footsteps of Tantek and Eric. You might even already be using it — it’s a core part of HTML5 Boilerplate, Bootstrap, and YUI’s new Pure.

User agent stylesheets are converging, and hopefully one day we won’t need to reset or normalize. There’s even a valid argument for not worrying about small differences between browsers (although being a Snook-level genius helps with that). But for now if you’re using a CSS reset, or nothing at all, give Normalize.css a try on your next project.

Addenda

1. [1] You can see the user agent style sheets for Mozilla, WebKit, and IE. CSS2.1 User Agent Style Sheet Defaults highlights the differences across (older) browsers. These styles also include things like style {display: none;} — try adding style {display: block;} to your CSS and see what happens.

2. [2] Since then, all browsers have migrated to setting list indenting via padding-left or padding-start, with IE7 being the last IE browser to use margin-left for this.

3. [3] For detailed background on the history of CSS resets, read The History of CSS Resets, by Michael Tuck.

My thanks to Eric Meyer and Nicolas Gallagher for their feedback on this article, and for these wonderful tools.

Postscript: While nuking margins and padding on all elements with * {margin: 0; padding: 0;} is gonna be a bad time, there is one universal selector-based reset you should still consider: * {box-sizing: border-box;}. This changes padding and border to being part of an element’s width, rather than additional to it. For more information, check our Paul Irish’s article “box-sizing: border-box FTW”.

原文链接：http://the-pastry-box-project.net/oli-studholme/2013-june-3 （本内容由互联网资料整理而成）

7

Making use of the amazing background gradients in CSS to create a rich, full-screen banner that loads in less than half a second and is only around 2KB in size.

WWDC and iOS 7

Apple have just revealed their latest iteration of the mobile operating system, iOS 7. In the run-up to the announcement at WWDC, they revealed an interesting banner that featured the number 7 against a dotted backdrop.

I liked this banner a lot. It’s a great combination of rich colours in the elegant, light typeface and an interesting, textured backdrop. It seemed like something that would make a great CSS project, so I had a go.

Turns out it’s indeed possible to create this banner using nothing but HTML and CSS, making use of CSS’s background gradients and 3D transforms. Let’s see how.

Compatibility

Since this demo makes use of the -webkit-background-clip and -webkit-text-fill-color, it’ll work well on Chrome and Safari. Until support for text-clipping in improves, it might not work so well in other browsers.

Source and demo

You can see the demo online, and download the source on Github.

Post-WWDC keynote update

When watching the keynote I noticed the 7 logo used inside a nice icon-shaped white box. I thought that looked pretty cool so have added it to the layout. Hiding the white background in the container element will make it look more like the banner above.

Making the 7

Aside from the extreme thinness of the font (Helvetica Neue UltraLight), it’s most striking feature is the colour gradients. To create this 7, we need to make use of CSS’s background gradient property, and then apply the gradient to the text.

Chris Coyier’s wonderful CSS-Tricks website has a great -webkit-background-clip snippet which will do nicely for the purposes of this demo.

First through, we need to set up some HTML to which we will apply the CSS:

<article class="container">
<span class="text part1">7</span>
<span class="text part2">7</span>
</article>

Here we have an article that contains two spans, each of which has a 7. The reason for including two 7s will become apparent in a moment. Before applying gradients, we set up these two spans so that they sit in an iOS-like icon in the middle of the screen.

The containing article is positioned and styled:

body {
background: black;
}

.container {
width: 512px;
height: 512px;
position: absolute;
left: 50%;
margin-left: -256px;
top: 50%;
margin-top: -256px;
background: whitesmoke;
border-radius: 120px;
}

This creates the container as a 512 by 512 pixel box and positions it in the middle, both vertically and horizontally, of the screen. The use of absolute positioning is not only a handy way of placing fixed-size elements in the centre of screens, it’ll also help when we introduce a background pattern later. For now the black background will provide contrast.

Next, set some properties for the text.

.container span.text {
font-family: "HelveticaNeue-UltraLight", "Helvetica Neue UltraLight", Roboto, Arial, Sans-serif;
font-size: 512px;
position: absolute;
top: 0;
left: 124px;
}

The font is “Helvetica Neue UltraLight”, and I’ve added a fallback of “Roboto”. This is a free Google font that should be somewhat similar, for those systems that might not have the font available. The text spans are positioned absolutely, so that both 7s will sit directly on top of each other, and both are set to 512 pixels in size.

With the two 7s placed on top of each other, and the icon in place, it should look a bit like this:

Adding some colour

If you look closely at the photo above, you can make out two gradients in the number seven. The first is a red to blue going across the top bar of the seven. The second is a red, purple, blue gradient from the foot of the seven. Since there are two gradients, it’ll mean making use of both the 7s we added to the HTML.

I picked out several key points in the gradient across the top of the seven, and created some colour stops for the first of the two 7s. I’m using a webkit version of the background gradient rather than creating all the prefixes:

span.text.part1 {
background: -webkit-gradient(linear, left top, right top, color-stop(0%, #67e1c9), color-stop(10%, #67e1c9), color-stop(40%, #60b6cf), color-stop(60%, #1f7acb), color-stop(80%, #212f7f));
}

This gradient starts at the top left and has 5 color-stop values along the way. The gradient looks a bit like this:

While this is nice, it doesn’t apply to the number in the HTML. To achieve this, we use the background-clip and text-fill-color properties:

span.text.part1 {
background: -webkit-gradient(linear, left top, right top, color-stop(0%, #67e1c9), color-stop(10%, #67e1c9), color-stop(40%, #60b6cf), color-stop(60%, #1f7acb), color-stop(80%, #212f7f));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}

The result of these properties being added should look like this:

The next step is to apply another gradient to the second seven. Since this seven sits in front, it needs to have a gradient that starts red and ends transparent. Add some colour stops to achieve this effect.

span.text.part2 {
background: -webkit-gradient(linear, left bottom, right top, color-stop(0%, #c71f1f), color-stop(30%, #c71f1f), color-stop(40%, #a24b92), color-stop(50%, #3791ea), color-stop(60%, rgba(33, 47, 127, 0)));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}

In this case the gradient starts at the bottom with the red colour, and ends with a fade to a transparent blue colour at around 60%. Transparent blue colour may seem like a contradiction, but the colour values in the R, G, and B of that RGBA have an impact on the gradient at it approaches transparent.

Now we’re getting somewhere:

Next step is to create the fancy polka-dotted background.

Making the background

The background is a collection of dots that fade into white toward the top of the banner. There is also a subtle 3D effect, with the dots looking like they recede into the distance toward the top. To recreate this effect, we can make use of CSS’s 3D transforms along with the background radial gradients.

Banner

The background will need some HTML. Place the following before the container article in the HTML source:

<div class="background-container">
<section class="background"></section>
</div>

This will make use of a background-container to contain the background and we’ll add the pattern CSS to the section contained within. First, place the background container in place with some CSS.

.background-container {
width: 100%;
height: 740px;
top: 50%;
margin: -370px auto 0;
position: absolute;
-webkit-perspective: 1200px;
overflow: hidden;
}

The container is set to the full width of the screen, and 740 pixels high. It makes use of absolute positioning so that it sits in the vertical centre of the screen, behind the icon.

Since this container will contain a 3D-transformed element, it’s necessary to specify the perspective property. In this case I’m using the -webkit prefixed version. The perspective property sets the distance for the vanishing point in a 3D scene, allowing elements within it to be placed with the 3D space.

The overflow property is set to hidden so that we can make the background larger than it’s container.

We then set up the styles for the background itself:

.background {
width: 300%;
height: 200%;
position: absolute;
left: -100%;
-webkit-transform-style: preserve-3d;
-webkit-transform: rotateX(45deg);
}

The main background element is positioned absolutely, set to 3 times the width of it’s container and twice the height, then it’s rotated 45 degrees on the X axis. This has the effect of tilting it back, so that the bottom of the element will seem closer than the top.

The width and height are set to be so much larger so that the rotated section won’t leave gaps in the top left and right corners. Since the container has the overflow property set to hidden, the extra background won’t be seen.

Making the dots

Let’s make use of a radial gradient to create the pattern.

When a CSS radial or linear gradient is generated, it is created as an image on the fly by the browser. This means that it can be tiled and sized just like a background image.

We generate the dot texture as follows:

div.example {
background: -webkit-radial-gradient(#d0d1d3 40%, white 65%);
background-size: 14px 14px;
}

The resulting dot pattern looks something like this:

Rotation problem

Rather than apply the dot pattern directly to the background element, we need to adjust it to match the banner. The dots in the banner are a diagonal pattern, rather than the straight lines above. This would mean rotating the pattern 45 degrees around the Z axis. Since the background element has been tilted back 45 degrees already, rotating it on the Z-axis would not create the desired effect:

To get around this we can create a pseudo-selector and apply the pattern to that. Pseudo-selectors can be added to an element to give us extra “elements” that we can style, referred to as before and after. Here’s the before pseudo-selector:

.background:before {
content: "";
position: absolute;
width: 300%;
height: 300%;
bottom: 0;
left: -100%;
background: -webkit-radial-gradient(#d0d1d3 40%, white 65%);
background-size: 14px 14px;
-webkit-transform: rotateZ(45deg);
}

The before element contains the pattern and is itself rotated 45 degrees on the Z axis. At this point it’s almost there, it needs the white gradient from the top of the banner. We can use the second pseudo-selector to contain that gradient:

.background:after {
content: "";
position: absolute;
left: 0;
top: -60%;
right: 0;
bottom: 0;
width: 300%;
height: 200%;
background: -webkit-gradient(linear, center top, center bottom, color-stop(0%, white), color-stop(60%, rgba(255, 255, 255, 0)));
}

The gradient on this pseudo-selector starts at white and fades to transparent. It’s positioned a little above the top to allow for the tiled effect of the background element.

Putting it all together, we get something like this:

Smaller screens

Before finishing up, we need to make sure it looks good on smaller devices. In this case, I’ll add a media query to target phones so that it fits onto the screen.

@media only screen and (max-width: 350px) {
.container {
width: 300px;
height: 300px;
margin-left: -150px;
border-radius: 80px;
margin-top: -150px;
}
.container span.text {
font-size: 300px;
left: 70px;
}
}

This adjusts the container to be smaller on screens that display fewer than 350 pixels horizontally.

Demo and get in touch

Check out the online 7 demo or download the source from Github.

I love feedback. Reach me by email or on Twitter.

原文链接：http://hop.ie/blog/seven/ （本内容由互联网资料整理而成）

IE10 的特殊样式

Published June 12, 2013 by Chris Coyier

Conditional comments are gone in IE 10. That's good. IE 10 is a very good browser. Feature detection is a better way to go in nearly all cases. But what if you find some styling situation where you absolutely need to target IE 10? I guess you'll have to do this.

Rogie posted a really simple idea a while back that should still work great for this. Add the User Agent to the <html> element with a tiny bit of JavaScript:

var doc = document.documentElement;
doc.setAttribute('data-useragent', navigator.userAgent);

IE 10's User Agent string is:

Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)

Which will result in:

<html data-useragent="Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)">

And you can then style like:

html[data-useragent*='MSIE 10.0'] h1 {
color: blue;
}

Check out this Pen!

原文链接：http://css-tricks.com/ie-10-specific-styles/ （本内容由互联网资料整理而成）

为什么需要响应式的图片

The topic of responsive images has been one of the most hotly debated topics amongst web developers for what feels like forever. I think Jason Grigsby was perhaps the first to publicly point out that simply setting a percentage width on images was not enough, you needed to resize these images as well. He showed that if you served appropriately sized images on the original responsive demo site, you could shave 78% off the weight of those images (about 162kB) on small screens.

The discussion has evolved since then with debates over what sort of solution we need (server-side, client-side), new markup (srcset vs picture) and even, in some cases, wondering whether we really needed to worry about it at all.

It’s a messy issue for sure. The current solutions for responsive images do come with some complexity and overhead. If you’re using a client-side solution and don’t want to make more than one request per image, then you end up breaking the preloader. As Steve Souders explained rather well, this can have a very negative impact on the time it takes for those images to actually start appearing to your visitors.

No doubt there are trade-offs. Complexity of solutions, preloader versus file size—these each have to be considered when making the determination of what solution to use. Eventually we’ll have a native solution which will take care of the preloader issue, but browsers sure seem to be dragging their feet on that.

In the meantime, I was curious just how much page weight could be saved with a responsive image solution in place. I know that on the projects I’ve worked on, the savings has often been huge, but I wanted to see how consistent my experience is with the web as a whole.

Experiment time!

Yoav Weiss created a bash script called Sizer-Soze that, with the help of ImageMagick and PhantomJS, determines just how much you could save in file size by serving optimized and resized images. The script is built for one url at a time, so I modified it slightly to let me loop through a list of 471 URLs (the same list used by Guy Podjarny for his analysis of responsive performance). My bash scripting skills are minimal (read: nearly non-existent), but thankfully Yoav is far more skilled there than I and was happy to help out and make the whole thing run much more efficiently.

The script looped through the 471 urls, spitting out the results into a CSV. Each site was tested at widths of 360px, 760px and 1260px. Numbers were collected for total original image size, size of images if they weren’t resized but were optimized, and size of images if they were both optimized and resized to match the size they actually displayed at (so if a 1200px image was displayed at 280px wide, the script resized the image to 280px and compared the two file sizes).

If Sizer-Soze came across an image set to “display:none” it would re-check the dimensions every 500 milliseconds (for a maximum wait of 25 seconds) to see if things had changed. This was done to account for image-based carousels where images may have been hidden initially but then later revealed. If the image became visible during that time, then the dimensions were used to process the file savings normally. If the image was never displayed, the entire weight of the image was counted as wasted.

Even with that tweak, there are few caveats about Sizer-Soze:

- It does not make a distinction between 3rd party images and images served by the site itself. So some of the weight can be attributed to things like ads.

- It does not analyze background images. That’s fine because that’s not what we want here anyway, but its worth noting that potentially even more bytes could be saved.

- It won’t be able to pickup some clever lazy-loading techniques, so again, its possible that some sites would actually be able to save even more than the reported numbers.

- It doesn’t include data-uri images in the totals as the file name exceeds the length limit for the script.

After looping through, the list shortened to 402 different responsive sites. Some of the original 471 moved to new URLs or apparently went AWOL so Sizer-Soze couldn’t follow along. Others had no images in the source code—either as a result of some sort of lazy-loading mechanism or by design. Still, 402 sites is a pretty good base to look at.

Results: Total Savings

On to the results! First up, the totals.

Viewport Size

Sum of Original Sizes

Sum of Optimized Savings

Sum of Resized Savings

360

237.66MB

12.86MB

171.62MB

760

244.39MB

13.30MB

129.34MB

1260

250.08MB

13.70MB

104.31MB

It’s not too surprising to see that the original size (what’s being served now) is pretty consistent from screen size to screen size. Guy’s research, and many others, have already demonstrated this pretty well.

What is staggering is just how massive the savings could be if these sites served appropriately sized images. At 360px wide, these 402 sites combine to serve 171.62MB of unnecessary weight to their visitors . That’s a whopping 72.2% of image weight that could be ditched by using a responsive image technique.

It’s not just small screens that would benefit. For 760px and 1260px sized screens, 52.9% and 41.7% of image weight is unnecessary.

Results: Average Savings

Let’s look at the savings in terms of per-site averages.

Viewport Size

Avg. Original Size

Avg. Optimized Savings

Avg. Resized Savings

360

603.89kB

32.68kB

436.08kB

760

622.53kB

33.88kB

329.47kB

1260

635.43kB

34.81kB

265.06kB

Looking at it from the perspective of an individual site, the numbers feel even more impactful. For each screen size, sites on average would shed about 5% of the weight of their images (from 32-34kb) by simply doing some lossless optimization. Considering that this could be automated easily into a build process, or manually done with tools like ImageOptim with little effort—that’s an easy 5% improvement.

Unsurprisingly, the gains are much more significant if those images get resized to an appropriate size as well. At 360px, the average site would drop 436.08kb. Consider that for a second. One optimization (resizing images) dropping that large of a chunk of weight. That takes image weight for a page from 603.89kB to a mere 167.81kB. That’s a huge difference that shouldn’t be dismissed.

While the improvements are slightly smaller for larger screen sizes (as you would expect), using some sort of responsive image technique would still save 320kB for sites displayed at 760px and 265kB for sites displayed at 1260px.

Conclusion

We spend a lot of time talking about responsive images online—debating the approaches, trying out new solutions. Sometimes it can be a little discouraging that we still haven’t gotten it ironed out (I know I feel that way frequently).

But the web needs us to be diligent. It needs us to not settle for seemingly simple solutions that sacrifice performance. It is extremely rare where one optimization lets us knock off such a significant amount of page weight, but here we are staring one such technique right in the face.

72% less image weight.

That’s why we need a responsive image solution.

原文链接：http://timkadlec.com/2013/06/why-we-need-responsive-images （本内容由互联网资料整理而成）

深入理解Express.js

本文針對已經對Node.js有一定了解的讀者。並且知道如何運行Node代碼，使用npm安裝相關模塊。但我保證，你不用是這方面的專家。本問針對的是Express 3.2.5版本。主要以介紹相關概念爲主。

Express.js這麼描述自己："輕量靈活的node.js Web應用框架"。它可以幫助你搭建web應用。如果你使用過Ruby裏的Sinatra,那麼相信你對這個也會很快就能熟悉。

和其他一些框架一樣，Express隱藏了代碼背後的祕密，然後告訴你："別擔心，你不用去理解這個部分"。它來幫你解決這些問題，你不用去自找煩惱了。換句話說，它有魔法！

Express的目錄裏介紹了一些它的使用者，其中就有很多知名的公司: MySpace, Klout, 甚至還有一些我做的項目。我？我很牛逼！我甚至有一個博客。

但是擁有魔力是需要付出代價的，你可能根本就不知道它的工作原理。正如駕駛一輛汽車，我可以很好的駕馭它但是可能不理解爲什麼汽車可以正常工作，但是我最好知道這些東西。如果車壞掉怎麼辦？如果你想最大程度的去發揮它的性能？如果你對知識有無限的渴望並想去弄清它？

那麼我麼首先從理解Express的最底層-Node開始。

底層：Node HTTP服務器

Node中有HTTP模塊, 它將搭建一個web服務器的過程抽象出來。你可以這樣使用:

// 引入所需模塊
var http = require("http");

// 建立服務器
var app = http.createServer(function(request, response) {
response.writeHead(200, {
"Content-Type": "text/plain"
});
response.end("Hello world!\n");
});

// 啓動服務器
app.listen(1337, "localhost");
console.log("Server running at http://localhost:1337/");

如果你運行這個程序(如果你命名爲 app.js ,你可以運行 node app.js )，你會得到"Hello world!“ 如果你在瀏覽器訪問 localhost:1337 ，你會得到同樣的結果。你也可以嘗試訪問其他地址，如 localhost:1337/whatever ，結果仍然會一樣。

分解以上代碼來看。

第一行使用 require 函數引入Node內置模塊 http 。然後存入名爲 http 的變量中。如果你要了解更多關於require函數的知識，參考Nodejitsu的文檔。

然後我們使用 http.createServer 將服務器保存至 app 變量。它將一個函數作爲參數監聽請求。稍後將會詳細介紹它。

最後我們要做的就是告訴服務器監聽來自1337端口的請求，之後輸出結果。然後一切完成。

好的，回到request請求處理函數。這個函數相當重要。

request方法

在開始這個部分之前，我事先聲明這裏所涉及的HTTP相關知識與學習Express本身沒有太大關係。如果你感興趣，可以查看HTTP模塊文檔。

任何時候我們向服務器發起請求，request方法將會被調用。如果你不信，你可以 console.log 將結果打印出來。你會發現每次請求一個頁面時它都會出來。

request 是來自客戶端的請求。在很多應用中，你可能會看到它的縮寫 req 。仔細看代碼。我們修改代碼如下:

var app = http.createServer(function(request, response) {

// 創建answer變量
var answer = "";
answer += "Request URL: " + request.url + "\n";
answer += "Request type: " + request.method + "\n";
answer += "Request headers: " + JSON.stringify(request.headers) + "\n";

// 返回結果
response.writeHead(200, {"Content-Type": "text/plain" });
response.end(answer);

});

重啓服務器並刷新 localhsot:1337 .你會發現，每次訪問一個URL，就會發起一次GET請求，並會得到一堆類似用戶代理或者一些其他的更加複雜的HTTP相關信息。如果你訪問 localhost:1337/what_is_fraser , 你會看到request的地址發生了變化。如果你使用不同的瀏覽器訪問，用戶代理也會跟着改變，如果你使用POST請求，request的方法也很改變。

response 是另外一個部分。正如 request 被縮寫爲 req ，response 同樣被簡寫爲 res 。每次response你都會得到對應的返回結果，之後你便可以通過調用 response.end 來結束。實際上最終你還是要執行這個方法的, 甚至在node的文檔裏也是這麼描述的。這個方法完成了真正的數據傳輸部分。你可以建立一個服務器並不調用 req.end 方法，它就會永遠存在。

在你返回結果之前，你也可以填寫一下header頭部部分。我們的例子裏是這麼寫的:

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

這個步驟主要完成兩件事情。第一，發送HTTP狀態碼，表示請求成功。其次，它設置了返回的頭部信息。這裏表示我們要返回的是純文本格式的內容。我們也可以返回類似JSON或者HTML格式的內容。

未完待續。。。

// 接上回

看了上面的之後，你可能會立馬開始利用它來寫api了。

var http = require("http");

http.createServer(function(req, res) {

// Homepage
if(req.url == "/") {
res.writeHead(200, { "Content-Type": "text/html" });
res.end("Welcome to the homepage!");
}

// About page
else if (req.url == "/about") {
res.writeHead(200, { "Content-Type": "text/html" });
res.end("Welcome to the about page!");
}

// 404'd!
else {
res.writeHead(404, { "Content-Type": "text/plain" });
res.end("404 error! File not found.");
}

}).listen(1337, "localhost");

你可以選擇優化代碼，讓它變得更整潔。也可以向npm.org的那幫傢伙一樣用原生的Node來編寫。但是你也可以選擇去創建一個框架。這就是Sencha所做的，並把這個框架稱爲 – Connect.

中間件: Connect

Connect是Nodejs的中間件。可能你現在還並不太理解什麼是中間件(middleware)，別擔心，我馬上會進行詳細解釋。

一段Connect代碼

假如我們想要編寫和上面一樣的代碼，但是這次我們要使用Connect.別忘記安裝Connect模塊(npm install)。完成之後，代碼看起來非常相似。

// 引入所需模塊
var connect = require("connect");
var http = require("http");

// 建立app
var app = connect();

// 添加中間件
app.use(function(request, response) {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Hello world!\n");
});

// 啓動應用
http.createServer(app).listen(1337);

下面分解這段代碼來看。

首先我們分別引入了Connect和Node HTTP模塊。

接下來和之前一樣聲明 app 變量，但是在創建服務器時，我們調用了 connect 。爲什麼要這麼寫？

原文链接：http://xvfeng.me/posts/understanding-expressjs/ （本内容由互联网资料整理而成）

基于 Web 的交互式数据可视化

Copyright © 2013 Scott Murray

Printed in the United States of America.

O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://my.safaribooksonline.com). For more information, contact our corporate/institutional sales department: 800-998-9938 or <corporate@oreilly.com>.

Nutshell Handbook, the Nutshell Handbook logo, the cover image, and the O’Reilly logo are registered trademarks of O’Reilly Media, Inc. Interactive Data Visualization for the Web, the cover image of a long-tail bushtit, and related trade dress are trademarks of O’Reilly Media, Inc.

Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and O’Reilly Media, Inc., was aware of a trademark claim, the designations have been printed in caps or initial caps.

While every precaution has been taken in the preparation of this book, the publisher and author assume no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein.

Revision History

2013-03-04

First release

2013-04-12

Second release

Data is an extremely broad term, only slightly less vague than the nearly all-encompassing information. What is data? (What isn’t data?) What kinds of data are there, and what can we use with D3?

Broadly speaking, data is structured information with potential for meaning.

In the context of programming for visualization, data is stored in a digital file, typically in either text or binary form. Of course, potentially every piece of digital ephemera may be considered “data”—not just text, but bits and bytes representing images, audio, video, databases, streams, models, archives, and anything else.

Within the scope of D3 and browser-based visualization, however, we will limit ourselves to text-based data. That is, anything that can be represented as numbers and strings of alpha characters. If you can get your data into a .txt plain text file, a .csv comma-separated value file, or a .json JSON document, then you can use it with D3.

Whatever your data, it can’t be made useful and visual until it is attached to something. In D3 lingo, the data must be bound to elements within the page. Let’s address how to create new page elements first. Then attaching data to those elements will be a cinch.

Typically, when using D3 to generate new DOM elements, the new elements will be circles, rectangles, or other visual forms that represent your data. But to avoid confusing matters, we’ll start with a simple example and create a lowly p paragraph element.

Begin by creating a new document with our simple HTML template from the last chapter. You can find it in the sample code files as 01_empty_page_template.html, and it looks like the following code. (Eagle-eyed viewers will notice that I’ve modified the src path here due to work with the directory structure of the code samples. If that doesn’t mean anything to you, don’t worry about it.)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3 Page Template</title>
<script type="text/javascript" src="../d3/d3.v3.js"></script>
</head>
<body>
<script type="text/javascript">
// Your beautiful D3 code will go here
</script>
</body>
</html>

Open that page in your web browser. Make sure you’re accessing the page via your local web server, as we discussed in Chapter 4. So the URL in your browser’s location bar should look something like this:

http://localhost:8888/d3-book/chapter_05/01_empty_page_template.html

If not viewed through a web server, the URL path will start with file:/// instead of http://. Confirm that the URL does not look like this:

file:///…/d3-book/chapter_05/01_empty_page_template.html

Once you’re viewing the page, pop open the web inspector. (As a reminder, see “Developer Tools” on how to do that.) You should see an empty web page, with the DOM contents shown in Figure 5-1.

Figure 5-1. Web inspector

Back in your text editor, replace the comment between the script tags with:

d3.select("body").append("p").text("New paragraph!");

Save and refresh, and voilà! There is text in the formerly empty browser window, and the web inspector will look like Figure 5-2.

Figure 5-2. Web inspector, again

See the difference? Now in the DOM, there is a new paragraph element that was generated on the fly! This might not be exciting yet, but you will soon use a similar technique to dynamically generate tens or hundreds of elements, each one corresponding to a piece of your dataset.

Let’s walk through what just happened. (You can follow along with 02_new_element.html.) To understand that first line of D3 code, you must first meet your new best friend, chain syntax.

D3 smartly employs a technique called chain syntax, which you might recognize from jQuery. By “chaining” methods together with periods, you can perform several actions in a single line of code. It can be fast and easy, but it’s important to understand how it works, to save yourself hours of debugging headaches later.

By the way, functions and methods are just two different words for the same concept: a chunk of code that accepts an argument as input, performs some action, and returns some other information as output.

The following code:

d3.select("body").append("p").text("New paragraph!");

might look like a big mess, especially if you’re new to programming. So the first thing to know is that JavaScript, like HTML, doesn’t care about whitespace and line breaks, so you can put each method on its own line for legibility:

d3.select("body")
.append("p")
.text("New paragraph!");

Both I and your optometrist highly recommend putting each method on its own indented line. But programmers have their own coding style; use whatever indents, line breaks, and whitespace (tabs or spaces) are most legible for you.

Many, but not all, D3 methods return a selection (actually, a reference to a selection), which enables this handy technique of method chaining. Typically, a method returns a reference to the element that it just acted on, but not always.

So remember this: when chaining methods, order matters. The output type of one method has to match the input type expected by the next method in the chain. If adjacent inputs and outputs are mismatched, the hand-off will function more like a dropped baton in a middle-school relay race.

When sussing out what each function expects and returns, the API reference is your friend. It contains detailed information on each method, including whether or not it returns a selection.

Our sample code could be rewritten without chain syntax:

var body = d3.select("body");
var p = body.append("p");
p.text("New paragraph!");

Ugh! What a mess. Yet there will be times you need to break the chain, such as when you are calling so many functions that it doesn’t make sense to string them all together. Or just because you want to organize your code in a way that makes more sense to you.

Now that you know how to generate new page elements with D3, it’s time to attach data to them.

What is binding, and why would I want to do it to my data?

Data visualization is a process of mapping data to visuals. Data in, visual properties out. Maybe bigger numbers make taller bars, or special categories trigger brighter colors. The mapping rules are up to you.

With D3, we bind our data input values to elements in the DOM. Binding is like “attaching” or associating data to specific elements, so that later you can reference those values to apply mapping rules. Without the binding step, we have a bunch of data-less, unmappable DOM elements. No one wants that.

We use D3’s selection.data() method to bind data to DOM elements. But there are two things we need in place first, before we can bind data:

- The data

- A selection of DOM elements

Let’s tackle these one at a time.

D3 is smart about handling different kinds of data, so it will accept practically any array of numbers, strings, or objects (themselves containing other arrays or key/value pairs). It can handle JSON (and GeoJSON) gracefully, and even has a built-in method to help you load in CSV files.

But to keep things simple, for now we will start with a boring array of five numbers. Here is our sample dataset:

var dataset = [ 5, 10, 15, 20, 25 ];

If you’re feeling adventurous, or already have some data in CSV or JSON format that you want to play with, here’s how to do that. Otherwise, just skip ahead to “Please Make Your Selection”.

CSV stands for comma-separated values. A CSV data file might look something like this:

Food,Deliciousness
Apples,9
Green Beans,5
Egg Salad Sandwich,4
Cookies,10
Vegemite,0.2
Burrito,7

Each line in the file has the same number of values (two, in this case), and values are separated by a comma. The first line in the file often serves as a header, providing names for each of the “columns” of data.

If you have data in an Excel file, it probably follows a similar structure of rows and columns. To get that data into D3, open it in Excel, then choose Save as… and select CSV as the file type.

If we saved the preceding CSV data into a file called food.csv, then we could load the file into D3 by using the d3.csv() method:

d3.csv("food.csv", function(data) {
console.log(data);
});

csv() takes two arguments: a string representing the path of the CSV file to load in, and an anonymous function, to be used as a callback function. The callback function is “called” only after the CSV file has been loaded into memory. So you can be sure that, by the time the callback is called, d3.csv() is done executing.

When called, the anonymous function is handed the result of the CSV loading and parsing process; that is, the data. Here I’m naming it data, but this could be called whatever you like. You should use this callback function to do all the things you can do only after the data has been loaded. In the preceding example, we are just logging the value of the data array to the console, to verify it, as shown in Figure 5-3. (See 03_csv_loading_example.html in the example code.)

Figure 5-3. Array logged to console

You can see that data is an array (because of the hard brackets [] on either end) with six elements, each of which is an object. By toggling the disclosure triangles next to each object, we can see their values (see Figure 5-4).

Figure 5-4. Array elements expanded

Aha! Each object has both a Food property and a Deliciousness property, the values of which correspond to the values in our CSV! (There is also a third property, __proto__, but that has to do with how JavaScript handles objects, and you can ignore it for now.) D3 has employed the first row of the CSV for property names, and subsequent rows for values. You might not realize it, but this just saved you a lot of time.

One more thing to note is that each value from the CSV is stored as a string, even the numbers. (You can tell because 9 is surrounded by quotation marks, as in "9" and not simply 9.) This could cause unexpected behavior later, if you try to reference your data as a numeric value but it is still typed as a string.

Note that d3.csv() is an asynchronous method, meaning that the rest of your code is executed even while JavaScript is simultaneously waiting for the file to finish downloading into the browser. (The same is true of D3’s other functions that load external resources, such as d3.json().)

This can potentially be very confusing, because you—as a reasonable human person—might assume that the CSV file’s data is available, when in fact it hasn’t finished loading yet. A common mistake is to include references to the external data outside of the callback function. Save yourself some headaches and make sure to reference your data only from within the callback function (or from within other functions that you call within the callback function).

Personally, I like to declare a global variable first, then call d3.csv() to load the data. Within the callback function, I copy the data into my global variable (so it’s available to all of my subsequent functions), and finally I call any functions that rely on that data being present. For example:

var dataset;  //Global variable

d3.csv("food.csv", function(data) {
dataset = data;    //Once loaded, copy to dataset.
generateVis();     //Then call other functions that
hideLoadingMsg();  //depend on data being present.
});

To further confuse matters, the callback function is executed whether or not the datafile was loaded successfully. That’s right, if the network connection fails, or the filename is misspelled, or for some reason an error occurs on the web server end, the callback function will still be executed. When the data fails to load, and you call functions that rely on that data being present, you will probably see an error in the console, and the visualization won’t be created. This scenario might happen only rarely, but it’s useful to know how to handle it.

Fortunately, you can include an optional error parameter in the callback function definition. If there is a problem loading the file, then error will be set to the error message returned by the web server, and data will be undefined. If the file loads successfully and there is no error, then error will be null, and the data array will be populated as expected. Note that error must be the first parameter, and data the second:

var dataset;

d3.csv("food.csv", function(error, data) {

if (error) {  //If error is not null, something went wrong.
console.log(error);  //Log the error.
} else {      //If no error, the file loaded correctly. Yay!
console.log(data);   //Log the data.

//Include other code to execute after successful file load here
dataset = data;
generateVis();
hideLoadingMsg();
}

});

Verifying your data is a great use of the csv() callback function, but typically this is where you’d call other functions that construct the visualization, now that the data is available, as in:

var dataset;  //Declare global var

d3.csv("food.csv", function(data) {

//Hand CSV data off to global var,
//so it's accessible later.
dataset = data;

//Call some other functions that
//generate your visualization, e.g.:
generateVisualization();
makeAwesomeCharts();
makeEvenAwesomerCharts();
thankAwardsCommittee();

});

One more tip: if you have tab-separated data in a TSV file, try the d3.tsv() method, which otherwise behaves exactly as the preceding method.

We’ll spend more time talking about JSON later, but for now, all you need to know is that the d3.json() method works the same way as csv(). Load your JSON data in this way:

d3.json("waterfallVelocities.json", function(json) {
console.log(json);  //Log output to console
});

Here, I’ve named the parsed output json, but it could be called data or whatever you like.

Please Make Your Selection

The data is ready to go. As a reminder, we are working with this simple array:

var dataset = [ 5, 10, 15, 20, 25 ];

Now you need to decide what to select. That is, what elements will your data be associated with? Again, let’s keep it super simple and say that we want to make a new paragraph for each value in the dataset. So you might imagine something like this would be helpful:

d3.select("body").selectAll("p")

and you’d be right, but there’s a catch: the paragraphs we want to select don’t exist yet. And this gets at one of the most common points of confusion with D3: how can we select elements that don’t yet exist? Bear with me, as the answer might require bending your mind a bit.

The answer lies with enter(), a truly magical method. See this code, which I’ll explain:

d3.select("body").selectAll("p")
.data(dataset)
.enter()
.append("p")
.text("New paragraph!");

View the example code 04_creating_paragraphs.html and you should see five new paragraphs, each with the same content, as shown in Figure 5-5.

Figure 5-5. Dynamic paragraphs

Here’s what’s happening:

d3.select("body")

Finds the body in the DOM and hands off a reference to the next step in the chain.

.selectAll("p")

Selects all paragraphs in the DOM. Because none exist yet, this returns an empty selection. Think of this empty selection as representing the paragraphs that will soon exist.

.data(dataset)

Counts and parses our data values. There are five values in our array called dataset, so everything past this point is executed five times, once for each value.

.enter()

To create new, data-bound elements, you must use enter(). This method looks at the current DOM selection, and then at the data being handed to it. If there are more data values than corresponding DOM elements, then enter() creates a new placeholder element on which you can work your magic. It then hands off a reference to this new placeholder to the next step in the chain.

.append("p")

Takes the empty placeholder selection created by enter() and appends a p element into the DOM. Hooray! Then it hands off a reference to the element it just created to the next step in the chain.

.text("New paragraph!")

Takes the reference to the newly created p and inserts a text value.

All right! Our data has been read, parsed, and bound to new p elements that we created in the DOM. Don’t believe me? Take another look at 04_creating_paragraphs.html and whip out your web inspector, shown in Figure 5-6.

Figure 5-6. New p elements in the web inspector

Okay, I see five paragraphs, but where’s the data? Switch to the JavaScript console, type in the following code, and click Enter. The results are shown in Figure 5-7:

console.log(d3.selectAll("p"))

Figure 5-7. Logging to the console, from the console

An array! Or, really, an array containing another array. Click the gray disclosure triangle to reveal its contents, shown in Figure 5-8.

Figure 5-8. Array of arrays, expanded

You’ll notice the five ps, numbered 0 through 4. Click the disclosure triangle next to the first one (number zero), which results in the view shown in Figure 5-9.

Figure 5-9. The p element, expanded

See it? Do you see it? I can barely contain myself. There it is (Figure 5-10).

Figure 5-10. Finally, bound data

Our first data value, the number 5, is showing up under the first paragraph’s __data__ attribute. Click into the other paragraph elements, and you’ll see they also contain __data__ values: 10, 15, 20, and 25, just as we specified.

You see, when D3 binds data to an element, that data doesn’t exist in the DOM, but it does exist in memory as a __data__ attribute of that element. And the console is where you can go to confirm whether or not your data was bound as expected.

The data is ready. Let’s do something with it.

We can see that the data has been loaded into the page and is bound to our newly created elements in the DOM, but can we use it? Here’s our code so far:

var dataset = [ 5, 10, 15, 20, 25 ];

d3.select("body").selectAll("p")
.data(dataset)
.enter()
.append("p")
.text("New paragraph!");

Let’s change the last line to:

.text(function(d) { return d; });

Now test out that new code in 05_creating_paragraphs_text.html. You should see the result shown in Figure 5-11.

Figure 5-11. More dynamic paragraphs

Whoa! We used our data to populate the contents of each paragraph, all thanks to the magic of the data() method. You see, when chaining methods together, anytime after you call data(), you can create an anonymous function that accepts d as input. The magical data() method ensures that d is set to the corresponding value in your original dataset, given the current element at hand.

The value of “the current element” changes over time as D3 loops through each element. For example, when looping through the third time, our code creates the third p tag, and d will correspond to the third value in our dataset (or dataset[2]). So the third paragraph gets text content of “15”.

In case you’re new to writing your own functions (a.k.a. methods), the basic structure of a function definition is:

function(input_value) {
//Calculate something here
return output_value;
}

The function we used earlier is dead simple, nothing fancy:

function(d) {
return d;
}

This is called an anonymous function, because it doesn’t have a name. Contrast that with a function that’s stored in a variable, which is a named function:

var doSomething = function() {
//Code to do something here
};

We’ll write lots of anonymous functions when using D3. They are the key to accessing individual data values and calculating dynamic properties.

This particular anonymous function is wrapped within D3’s text() function. So our anonymous function is executed first. Then its result is handed off to text(). Then text() finally works its magic (by inserting its input argument as text within the selected DOM element):

.text(function(d) {
return d;
});

But we can (and will) get much fancier because you can customize these functions any way you like. Yes, this is both the pleasure and pain of writing your own JavaScript. Maybe you’d like to add some extra text, as in:

.text(function(d) {
return "I can count up to " + d;
});

which produces the result shown in Figure 5-12, as seen in example file 06_creating_paragraphs_counting.html.

Figure 5-12. Still more dynamic paragraphs

You might be wondering why you have to write out function(d) { … } instead of just d on its own. For example, this won’t work:

.text("I can count up to " + d);

In this context, without wrapping d in an anonymous function, d has no value. Think of d as a lonely little placeholder value that just needs a warm, containing hug from a kind, caring function’s parentheses. (Extending this metaphor further, yes, it is creepy that the hug is being given by an anonymous function, but that only confuses matters.)

Here is d being held gently and appropriately by a function:

.text(function(d) {  // <-- Note tender embrace at left
return "I can count up to " + d;
});

The reason for this syntax is that .text(), attr(), and many other D3 methods can take a function as an argument. For example, text() can take either simply a static string of text as an argument:

.text("someString")

or the result of a function:

.text(someFunction())  // Presumably, someFunction() would return a string

or an anonymous function itself can be the argument, such as when you write:

.text(function(d) {
return d;
})

Here, you are defining an anonymous function. If D3 sees a function there, it will call that function, while handing off the current datum d as the function’s argument. Here, I’ve named the argument d just by convention. You could call it datum or info or whatever you like. All D3 is looking for is any argument name, into which it can pass the current datum. Throughout this book, we’ll use d because it is concise and familiar from many of the other D3 examples found online.

In any case, without that function in place, D3 couldn’t relay the current data value. Without an anonymous function and its argument there to receive the value of d, D3 could get confused and even start crying. (D3 is more emotional than you’d expect.)

At first, this might seem silly and like a lot of extra work to just get at d, but the value of this approach will become clear as we work on more complex pieces.

Things get a lot more interesting when we explore D3’s other methods, like attr() and style(), which allow us to set HTML attributes and CSS properties on selections, respectively.

For example, adding one more line to our code:

.style("color", "red");

produces the result shown in Figure 5-13, as seen in 07_creating_paragraphs_with_style.html.

Figure 5-13. Red paragraphs

All the text is now red; big deal. But we could use a custom function to make the text red only if the current datum exceeds a certain threshold. So we revise that last line to use a function instead of a string:

.style("color", function(d) {
if (d > 15) {   //Threshold of 15
return "red";
} else {
return "black";
}
});

See the resulting change, displayed in Figure 5-14, in 08_creating_paragraphs_with_style_functions.html.

Figure 5-14. Dynamically styled paragraphs

Notice how the first three lines are black, but once d exceeds the arbitrary threshold of 15, the text turns red.

Okay, we’ve got data loaded in, and dynamically created DOM elements bound to that data. I’d say we’re ready to start drawing with data!

原文链接：http://chimera.labs.oreilly.com/books/1230000000345/index.html （本内容由互联网资料整理而成）

web worker多线程研究

HTML5支持了Web Worker这样的API，允许网页在安全的情况下执行多线程代码。不过Web Worker实际上受到很多限制，因为它无法真正意义上共享内存数据，只能通过消息来做状态通知，所以甚至不能称之为真正意义上的“多线程”。

Web Worker的接口使用起来很不方便，它基本上自带一个sandbox，在沙箱中跑一个独立的js文件，通过 postMessage和 onMessge来和主线程通信：

1. varworker = newWorker("my.js");

2. varbundle = {message:'Hello world', id:1};

3. worker.postMessage(bundle); //postMessage可以传一个可序列化的对象过去

4. worker.onmessage = function(evt){

5. console.log(evt.data);    //比较worker中传回来的对象和主线程中的对象

6. console.log(bundle);  //{message:'Hello world', id:1}

7. }

1. //in my.js

2. onmessage = function(evt){

3. vardata = evt.data;

4. data.id++;

5. postMessage(data); //{message:'Hello world', id:2}

6. }

得到的结果可以发现，线程中得到的data的id增加了，但是传回来之后，并没有改变主线程的bundle中的id，因此，线程中传递的对象实际上copy了一份，这样的话，线程并没有共享数据，避免了读写冲突，所以是安全的。保证线程安全的代价就是限制了在线程中操作主线程对象的能力。
这样一个有限的多线程机制使用起来是很不方便的，我们当然希望Worker能够支持让代码看起来具有同时操作多线程的能力，例如，支持看起来像下面这个样子的代码：

1. varworker = newThreadWorker(bundle/*shared obj*/);

3. worker.run(function(bundle){

4. //do sth in worker thread...

5. this.runOnUiThread(function(bundle/*shared obj*/){

6. //do sth in main ui thread...

7. });

8. //...

9. });

这段代码里面，我们启动一个worker之后，能够让任意代码跑在worker中，并且当需要操作ui线程（比如读写dom）时，可以通过this.runOnUiThread回到主线程执行。
那么如何实现这个机制呢？ 看下面的代码：

1. functionWorkerThread(sharedObj){

2. this._worker = newWorker("thread.js");

3. this._completes = {};

4. this._task_id = 0;

5. this.sharedObj = sharedObj;

7. varself = this;

8. this._worker.onmessage = function(evt){

9. varret = evt.data;

10. if(ret.__UI_TASK__){

11. //run on ui task

12. varfn = (newFunction("return "+ret.__UI_TASK__))();

13. fn(ret.sharedObj);

14. }else{

15. self.sharedObj = ret.sharedObj;

16. self._completes[ret.taskId](ret);

17. }

18. }

19. }

21. WorkerThread.prototype.run = function(task, complete){

22. var_task = {__THREAD_TASK__:task.toString(), sharedObj: this.sharedObj, taskId: this._task_id};

23. this._completes[this._task_id++] = complete;

24. this._worker.postMessage(_task);

25. }

上面这段代码定义了一个ThreadWorker对象，这个对象创建了一个运行thread.js的Web Worker，保存了共享对象SharedObj，并且对thread.js发回的消息进行处理。
如果thread.js中传回了一个__UI_TASK__消息，那么运行这个消息传过来的function，否则执行run的complete回调
我们看看thread.js是怎么写的：

1. onmessage = function(evt){

2. vardata = evt.data;

4. if(data && data.__THREAD_TASK__){

5. vartask = data.__THREAD_TASK__;

6. try{

7. varfn = (newFunction("return "+task))();

9. varctx = {

10. threadSignal: true,

11. sleep: function(interval){

12. ctx.threadSignal = false;

13. setTimeout(_run, interval);

14. },

15. runOnUiThread: function(task){

16. postMessage({__UI_TASK__:task.toString(), sharedObj:data.sharedObj});

17. }

18. }

20. function_run(){

21. ctx.threadSignal = true;

22. varret = fn.call(ctx, data.sharedObj);

23. postMessage({error:null, returnValue:ret, __THREAD_TASK__:task, sharedObj:data.sharedObj, taskId: data.taskId});

24. }

26. _run(0);

28. }catch(ex){

29. postMessage({error:ex.toString() , returnValue:null, sharedObj: data.sharedObj});

30. }

31. }

32. }

可以看到，thread.js接收ui线程传过来的消息，其中最重要的是__THREAD_TASK__，这是ui线程传过来的需要worker线程执行的“任务”，由于function是不可序列化的，因此传递的是字符串，worker线程通过解析字符串成function来执行主线程提交的任务（注意在任务中将共享对象sharedObj传入），执行完成后将返回结果通过message传给ui线程。我们仔细看一下除了返回值returnValue以外，共享对象sharedObj也会被传回，传回时，由于worker线程和ui线程并不共享对象，因此我们人为通过赋值的方式同步两边的对象（这样是否线程安全？为什么？）
可以看到整个过程其实并不复杂，这么实现之后，这个ThreadWorker可以有以下两种用法：

1. vart1 = newWorkerThread({i: 100}/*shared obj*/);

3. setInterval(function(){

4. t1.run(function(sharedObj){

5. returnsharedObj.i++;

6. },

7. function(r){

8. console.log("t1>" + r.returnValue + ":" + r.error);

9. }

10. );

11. }, 500);

1. vart2 = newWorkerThread({i: 50});

3. t2.run(function(sharedObj){

4. while(this.threadSignal){

5. sharedObj.i++;

7. this.runOnUiThread(function(sharedObj){

8. W("body ul").appendChild("<li>"+sharedObj.i+"</li>");

9. });

11. this.sleep(500);

12. }

13. returnsharedObj.i;

14. }, function(r){

15. console.log("t2>" + r.returnValue + ":" + r.error);

16. });

这样的用法从形式和语义上来说都让代码具有良好的结构，灵活性和可维护性。

好了，关于Web Worker的用法探讨就介绍到这里，有兴趣的同学可以去看一下这个项目：https://github.com/akira-cn/WorkerThread.js (由于Worker需要用服务器测试，我特意在项目中放了一个山寨的httpd.js，是个非常简陋的http服务的js，直接用node就可以跑起来）。

月影 Uncategorized

原文链接：http://www.silverna.org/blog/?p=271 （本内容由互联网资料整理而成）

关于V8对于array处理的一个有趣的讨论

If you preallocate, do not use .push because you will create a sparse array backed by a hashtable. You can preallocate sparse arrays up to 99999 elements which will be backed by a C array, after that it's a hashtable.

With the second array you are adding elements in a contiguous way starting from 0, so it will be backed by a real C array, not a hash table.

So roughly:

If your array indices go nicely from 0 to Length-1, with no holes, then it can be represented by a fast C array. If you have holes in your array, then it will be represented by a much slower hash table. The exception is that if you preallocate an array of size < 100000, then you can have holes in the array and still get backed by a C array:

var a = new Array(N);

//If N < 100000, this will not make the array a hashtable:
a[50000] = "sparse";

var b = [] //Or new Array(N), with N >= 100000
//B will be backed by hash table
b[50000] = "Sparse";
//b.push("Sparse"), roughly same as above if you used new Array with N > 0

原文链接：http://stackoverflow.com/questions/16961838/working-with-arrays-in-v8-performance-issue （本内容由互联网资料整理而成）

纯用CSS按需加载图片

By Pavlo Pidlypenskyi

The brain is a muscle, and as all muscles, it needs regular exercise to keep sharp, which is why I decided to take very old, but efficient, web optimization technique and implement it in new crazy way. You’ve most likely heard about loading images (and other resources) on demand – which is not only a common sense, but also a good way to speedup initial page load. Usually it is implemented via JavaScript, but today I’ll share with you how you can achieve the same effect by using pure CSS.

The problem

First let’s lay out the nature of the problem. Imagine we have a set of images to show to a user, but only some of them will be visible after initial page load. The rest of the images will sit below the fold and it’s possible the user may never scroll down. So it makes sense to load those images after user start scrolling the page down.

Prevent images to load

The first problem we need to solve is how to prevent the browser from loading all the images from start. I’ve tried several approaches here, but the one which has worked for me is to have images set as background images for some div elements and set its parent display: none. Almost all modern browsers are smart enough that they do not load background images for hidden elements. When we decide its time to load/show the image we will set the patent to display: block.

When to start loading images?

Next let’s think about what styles or CSS selectors are changed as the user scrolls to determine how we can catch the moment to start a particular image request. My first approach was to use position: sticky as it behaves like position: relative within its parent until a given offset threshold is met in the viewport (in other words, the user scrolled to some position). After this point element will start behave as position: fixed. Unfortunately, the surrounding elements don’t note the change and hold their position and styling.

Then I noted that user’s cursor hovers different elements while scrolling the page. So, what if we put several page-wide div elements (with a class of .hoverer) on a page and start loading the image when the user hovers it? It may work, but there is no guarantee that user will hover all the div elements on first page so that we can load images on a second page. This lead me to the next idea – what if we load all images for first two pages from very beginning and put a div.hoverer on top of images on a second page. Once a user hovera it – we will load images for the third page. Third page will also contain div.hoverer for fourth page and so on.

The next question is: how can I determine what the size of the page is so that I can load first two screens of images initially? Unfortunately there is no way to do so, but I can make them big enough to fit majority of the screens (assuming all images are an equal, known in advance size). Examine the demonstration below in order to get a feeling of how it will work :

View this on JSFiddle

Keep images visible when the cursor has left

Here is a problem: even if we show/load images when user hovers related div.hoverer, the image will disappear when user remove cursor from the div.hoverer. So how can we preserve the hover state? My first idea was to have div.hoverer elements overlapping each other, so that when you position the cursor over one element, it will be positioned over all elements we’ve hovered already. But the hover state is not propagated over the elements, only the top element will receive a hover state. Even pointer-events: none won’t help us in this situation.

What if I just delay appearance of display: none on image parent’s element? I tried to use keyframes animation, but that didn’t work out for me. Fortunately, transition does exactly what I need. Instead of another paragraph of explanation – check out this demo.

View this on JSFiddle

There is another problem in that we can’t delay the display: block state as it is not animatable property in CSS, and transitions works only with animatable properties. Another dead end? Not exactly.

I transition the width of the element and apply a media query to it. In media query I can specify the relationship between the element’s width and its visibility. Oh, but it is not allowed to set media query for particular HTML Element; media queries are applicable to viewport only. This means that we have to put images into separate viewports (i.e. iframes). We can use iframe.srcdoc in order to avoid to having a separate URL for each image we are displaying.

Results and some comments

Here is our final result (make your viewport height equal to 5 pumpkins in order to get the best experience). Because of need for  iframe.srcdoc support, the demo works in WebKit only, but you could make it work cross-browser if you put the actual source of the iframes into separate files.

This is pretty long path to partially working solution. Would I even recommend to use it on production? No way. This is definitely not a best practice, but was an interesting task and some parts of it might be applicable in real-world web applications. I hope you had as much fun as I had, while working on this challenge. If you have any ideas of how to improve my approach – please do not hesitate to contact me.

Update:

It looks like there is a way to solve a problem with first two screens. I can have div element with a viewport size (by using height: 100vh;). The element will contain set of images wrapped into an iframe, as in my demo. The set should be big enough to fill the first two screens, and I will have a set of media queries to show different subsets of images depending on the viewport height.

This article was originally published at http://podlipensky.com/2013/06/css-only-load-images-on-demand/

原文链接：http://flippinawesome.org/2013/06/10/loading-images-on-demand-with-pure-css/ （本内容由互联网资料整理而成）

Pinterest的渲染性能案例研究

Today we’ll discuss how to improve the paint performance of your websites and Web apps. This is an area that we Web developers have only recently started looking at more closely, and it’s important because it could have an impact on your user engagement and user experience.

Frame Rate Applies To The Web, Too

Frame rate is the rate at which a device produces consecutive images to the screen. A low frames per second (FPS) means that individual frames can be made out by the eye. A high FPS gives users a more responsive feel. You’re probably used to this concept from the world of gaming, but it applies to the Web, too.

Long image decoding, unnecessary image resizing, heavy animation and data processing can all lead to dropped frames, which reduces the frame rate, resulting in janky pages. We’ll explain what exactly we mean by “jank” shortly.

Why Care About Frame Rate?

Smooth, high frame rates drive user engagement and can affect how much users interact with your website or app.

At EdgeConf earlier this year, Facebook confirmed this when it mentioned that in an A/B test, it slowed down scrolling from 60 FPS to 30 FPS, causing engagement to collapse. That said, if you can’t do high frame rates and 60 FPS is out of reach, then you’d at least want something smooth. If you’re doing your own animation, this is one benefit of using requestAnimationFrame: the browser can dynamically adjust to keep the frame rate normal.

In cases where you’re concerned about scrolling, the browser can manage the frame rate for you. But if you introduce a large amount of jank, then it won’t be able to do as good a job. So, try to avoid big hitches, such as long paints, long JavaScript execution times, long anything.

Don’t Guess It, Test It!

Before getting started, we need to step back and look at our approach. We all want our websites and apps to run more quickly. In fact, we’re arguably paid to write code that runs not only correctly, but quickly. As busy developers with deadlines, we find it very easy to rely on snippets of advice that we’ve read or heard. Problems arise when we do that, though, because the internals of browsers change very rapidly, and something that’s slow today could be quick tomorrow.

Another point to remember is that your app or website is unique, and, therefore, the performance issues you face will depend heavily on what you’re building. Optimizing a game is a very different beast to optimizing an app that users will have open for 200+ hours. If it’s a game, then you’ll likely need to focus your attention on the main loop and heavily optimize the chunk of code that is going to run every frame. With a DOM-heavy application, the memory usage might be the biggest performance bottleneck.

Your best option is to learn how to measure your application and understand what the code is doing. That way, when browsers change, you will still be clear about what matters to you and your team and will be able to make informed decisions. So, no matter what, don’t guess it, test it!

We’re going to discuss how to measure frame rate and paint performance shortly, so hold onto your seats!

Note: Some of the tools mentioned in this article require Chrome Canary, with the “Developer Tools experiments” enabled in about:flags. (We — Addy Osmani and Paul Lewis — are engineers on the Developer Relations team at Chrome.)

Case Study: Pinterest

The other day we were on Pinterest, trying to find some ponies to add to our pony board (Addy loves ponies!). So, we went over to the Pinterest feed and started scrolling through, looking for some ponies to add.

Addy adding some ponies to his Pinterest board, as one does. Larger view.

Jank Affects User Experience

The first thing we noticed as we scrolled was that scrolling on this page doesn’t perform very well — scrolling up and down takes effort, and the experience just feels sluggish. When they come up against this, users get frustrated, which means they’re more likely to leave. Of course, this is the last thing we want them to do!

Pinterest showing a performance bottleneck when a user scrolls. Larger view.

This break in consistent frame rate is something the Chrome team calls “jank,” and we’re not sure what’s causing it here. You can actually notice some of the frames being drawn as we scroll. But let’s visualize it! We’re going to open up Frames mode and show what slow looks like there in just a moment.

Note: What we’re really looking for is a consistently high FPS, ideally matching the refresh rate of the screen. In many cases, this will be 60 FPS, but it’s not guaranteed, so check the devices you’re targeting.

Now, as JavaScript developers, our first instinct is to suspect a memory leak as being the cause. Perhaps some objects are being held around after a round of garbage collection. The reality, however, is that very often these days JavaScript is not a bottleneck. Our major performance problems come down to slow painting and rendering times. The DOM needs to be turned into pixels on the screen, and a lot of paint work when the user scrolls could result in a lot of slowing down.

Note: HTML5 Rocks specifically discusses some of the causes of slow scrolling. If you think you’re running into this problem, it’s worth a read.

Measuring Paint Performance

Frame Rate

We suspect that something on this page is affecting the frame rate. So, let’s go open up Chrome’s Developer Tools and head to the “Timeline” and “Frames” mode to record a new session. We’ll click the record button and start scrolling the page the way a normal user would. Now, to simulate a few minutes of usage, we’re going to scroll just a little faster.

Using Chrome’s Developer Tools to profile scrolling interactions. Larger view.

Up, down, up, down. What you’ll notice now in the summary view up at the top is a lot of purple and green, corresponding to painting and rendering times. Let’s stop recording for now. As we flip through these various frames, we see some pretty hefty “Recalculate Styles” and a lot of “Layout.”

If you look at the legend to the very right, you’ll see that we’ve actually blown our budget of 60 FPS, and we’re not even hitting 30 FPS either in many cases. It’s just performing quite poorly. Now, each of these bars in the summary view correspond to one frame — i.e. all of the work that Chrome has to do in order to be able to draw an app to the screen.

Chrome’s Developer Tools showing a long paint time. Larger view.

Frame Budget

If you’re targeting 60 FPS, which is generally the optimal number of frames to target these days, then to match the refresh rate of the devices we commonly use, you’ll have a 16.7-millisecond budget in which to complete everything — JavaScript, layout, image decoding and resizing, painting, compositing — everything.

Note: A constant frame rate is our ideal here. If you can’t hit 60 FPS for whatever reason, then you’re likely better off targeting 30 FPS, rather than allowing a variable frame rate between 30 and 60 FPS. In practice, this can be challenging to code because when the JavaScript finishes executing, all of the layout, paint and compositing work still has to be done, and predicting that ahead of time is very difficult. In any case, whatever your frame rate, ensure that it is consistent and doesn’t fluctuate (which would appear as stuttering).

If you’re aiming for low-end devices, such as mobile phones, then that frame budget of 16 milliseconds is really more like 8 to 10 milliseconds. This could be true on desktop as well, where your frame budget might be lowered as a result of miscellaneous browser processes. If you blow this budget, you will miss frames and see jank on the page. So, you likely have somewhere nearer 8 to 10 milliseconds, but be sure to test the devices you’re supporting to get a realistic idea of your budget.

An extremely costly layout operation of over 500 milliseconds. Larger view.

Note: We’ve also got an article on how to use the Chrome Developer Tools to find and fix rendering performance issues that focuses more on the timeline.

Going back to scrolling, we have a sneaking suspicion that a number of unnecessary repaints are occurring on this page with onscroll.

One common mistake is to stuff just way too much JavaScript into the onscroll handlers of a page — making it difficult to meet the frame budget at all. Aligning the work to the rendering pipeline (for example, by placing it in requestAnimationFrame) gives you a little more headroom, but you still have only those few milliseconds in which to get everything done.

The best thing you can do is just capture values such as scrollTop in your scroll handlers, and then use the most recent value inside a requestAnimationFrame callback.

Paint Rectangles

Let’s go back to Developer Tools → Settings and enable “Show paint rectangles.” This visualizes the areas of the screen that are being painted with a nice red highlight. Now look at what happens as we scroll through Pinterest.

Enabling Chrome Developer Tools’ “Paint Rectangles” feature. Larger view.

Every few milliseconds, we experience a big bright flash of red across the entire screen. There seems to be a paint of the whole screen every time we scroll, which is potentially very expensive. What we want to see is the browser just painting what is new to the page — so, typically just the bottom or top of the page as it gets scrolled into view. The cause of this issue seems to be the little “scroll to top” button in the lower-right corner. As the user scrolls, the fixed header at the top needs to be repainted, but so does the button. The way that Chrome deals with this is to create a union of the two areas that need to be repainted.

Chrome shows freshly painted areas with a red box. Larger view.

In this case, there is a rectangle from the top left to top right, but not very tall, plus a rectangle in the lower-right corner. This leaves us with a rectangle from the top left to bottom right, which is essentially the whole screen! If you inspect the button element in Developer Tools and either hide it (using the H key) or delete it and then scroll again, you will see that only the header area is repainted. The way to solve this particular problem is to move the scroll button to its own layer so that it doesn’t get unioned with the header. This essentially isolates the button so that it can be composited on top of the rest of the page. But we’ll talk about layers and compositing in more detail in a little bit.

The next thing we notice has to do with hovering. When we hover over a pin, Pinterest paints an action bar containing “Repin, comment and like” buttons — let’s call this the action bar. When we hover over a single pin, it paints not just the bar but also the elements underlying it. Painting should happen only on those elements that you expect to change visually.

A cause for concern: full-screen flashes of red indicate a lot of painting. Larger view.

There’s another interesting thing about scrolling here. Let’s keep our cursor hovered over this pin and start scrolling the page again.

Every time we scroll through a new row of images, this action bar gets painted on yet another pin, even though we don’t mean to hover over it. This comes down more to UX than anything else, but scrolling performance in this case might be more important than the hover effect during scrolling. Hovering amplifies jank during scrolling because the browser essentially pauses to go off and paint the effect (the same is true when we roll out of the element!). One option here is to use a setTimeout with a delay to ensure that the bar is painted only when the user really intends to use it, an approach we covered in “Avoiding Unnecessary Paints.” A more aggressive approach would be to measure the mouseenter or the mouse’s trajectory before enabling hover behaviors. While this measure might seem rather extreme, remember that we are trying to avoid unnecessary paints at all costs, especially when the user is scrolling.

Overall Paint Cost

We now have a really great workflow for looking at the overall cost of painting on a page; go back into Developer Tools and “Enable continuous page repainting.” This feature will constantly paint to your screen so that you can find out what elements have costly paint times. You’ll get this really nice black box in the top corner that summarizes paint times, with the minimum and maximum also displayed.

Chrome’s “Continuous Page Repainting” mode helps you to assess the overall cost of a page. Larger view.

Let’s head back to the “Elements” panel. Here, we can select a node and just use the keyboard to walk the DOM tree. If we suspect that an element has an expensive paint, we can use the H shortcut key (something recently added to Chrome) to toggle visibility on that element. Using the continuous paint box, we can instantly see whether this has a positive effect on our pages’ paint times. We should expect it to in many cases, because if we hide an element, we should expect a corresponding reduction in paint times. But by doing this, we might see one element that is especially expensive, which would bear further scrutiny!

The “Continuous Page Repainting” chart showing the time taken to paint the page.

For Pinterest’s website, we can do it to the categories bar or to the header, and, as you’d expect, because we don’t have to paint these elements at all, we see a drop in the time it takes to paint to the screen. If we want even more detailed insight, we can go right back to the timeline and record a new session to measure the impact. Isn’t that great? Now, while this workflow should work great for most pages, there might be times when it isn’t as useful. In Pinterest’s case, the pins are actually quite deeply nested in the page, making it hard for us to measure paint times in this workflow.

Luckily, we can still get some good mileage by selecting an element (such as a pin here), going to the “Styles” panel and looking at what CSS styles are being used. We can toggle properties on and off to see how they effect the paint times. This gives us much finer-grained insight into the paint profile of the page.

Here, we see that Pinterest is using box-shadow on these pins. We’ve optimized the performance of box-shadow in Chrome over the past two years, but in combination with other styles and when heavily used, it could cause a bottleneck, so it’s worth looking at.

Pinterest has reduced continuous paint mode times by 40% by moving box-shadow to a separate element that doesn’t have border-radius. The side effect is slightly fuzzy-looking corners; however, it is barely noticeable due to the color scheme and the low border-radius values.

Note: You can read more about this topic in “CSS Paint Times and Page Render Weight.”

Toggling styles to measure their effect on page-rendering weight. Larger view.

Let’s disable box-shadow to see whether it makes a difference. As you can see, it’s no longer visible on any of the pins. So, let’s go back to the timeline and record a new session in which we scroll the same way as we did before (up and down, up and down, up and down). We’re getting closer to 60 FPS now, and that’s just from one change.

Public service announcement: We’re absolutely not saying don’t use box-shadow — by all means, do! Just make sure that if you have a performance problem, measure correctly to find out what your own bottlenecks are. Always measure! Your website or application is unique, as will any performance bottleneck be. Browser internals change almost daily, so measuring is the smartest way to stay up to date on the changes, and Chrome’s Developer Tools makes this really easy to do.

Using Chrome Developer Tools to profile is the best way to track browser performance changes. Larger view.

Note: Eberhard Grather recently wrote a detailed post on “Profiling Long Paint Times With DevTools’ Continuous Painting Mode,” which you should spend some quality time with.

Another thing we noticed is that if you click on the “Repin” button, do you see the animated effect and the lightbox being painted? There’s a big red flash of repaint in the background. It’s not clear from the tooling if the paint is the white cover or some other affected being area. Be sure to double check that the paint rectangles correspond to the element or elements that you think are being repainted, and not just what it looks like. In this case, it looks like the whole screen is being repainted, but it could well be just the white cover, which might not be all that expensive. It’s nuanced; the important thing is to understand what you’re seeing and why.

Hardware Compositing (GPU Acceleration)

The last thing we’re going to look at on Pinterest is GPU acceleration. In the past, Web browsers have relied pretty heavily on the CPU to render pages. This involved two things: firstly, painting elements into a bunch of textures, called layers; and secondly, compositing all of those layers together to the final picture seen on screen.

Over the past few years, however, we’ve found that getting the GPU involved in the compositing process can lead to some significant speeding up. The premise is that, while the textures are still painted on the CPU, they can be uploaded to the GPU for compositing. Assuming that all we do on future frames is move elements around (using CSS transitions or animations) or change their opacity, we simply provide these changes to the GPU and it takes care of the rest. We essentially avoid having to give the GPU any new graphics; rather, we just ask it to move existing ones around. This is something that the GPU is exceptionally quick at doing, thus improving performance overall.

There is no guarantee that this hardware compositing will be available and enabled on a given platform, but if it is available the first time you use, say, a 3D transform on an element, then it will be enabled in Chrome. Many developers use the translateZ hack to do just that. The other side effect of using this hack is that the element in question will get its own layer, which may or may not be what you want. It can be very useful to effectively isolate an element so that it doesn’t affect others as and when it gets repainted. It’s worth remembering that the uploading of these textures from system memory to the video memory is not necessarily very quick. The more layers you have, the more textures need to be uploaded and the more layers that will need to be managed, so it’s best not to overdo it.

Note: Tom Wiltzius has written about the layer model in Chrome, which is a relevant read if you are interested in understanding how compositing works behind the scenes. Paul has also written a post about the translateZ hack and how to make sure you’re using it in the right ways.

Another great setting in Developer Tools that can help here is “Show composited layer borders.” This feature will give you insight into those DOM elements that are being manipulated at the GPU level.

Switching on composited layer borders will indicate Chrome’s rendering layers. Larger view.

If an element is taking advantage of the GPU acceleration, you’ll see an orange border around it with this on. Now as we scroll through, we don’t really see any use of composited layers on this page — not when we click “Scroll to top” or otherwise.

Chrome is getting better at automatically handling layer promotion in the background; but, as mentioned, developers sometimes use the translateZ hack to create a composited layer. Below is Pinterest’s feed with translateZ(0) applied to all pins. It’s not hitting 60 FPS, but it is getting closer to a consistent 30 FPS on desktop, which is actually not bad.

Using the translateZ(0) hack on all Pinterest pins. Note the orange borders. Larger view.

Remember to test on both desktop and mobile, though; their performance characteristics vary wildly. Use the timeline in both, and watch your paint time chart in Continuous Paint mode to evaluate how fast you’re busting your budget.

Again, don’t use this hack on every element on the page — it might pass muster on desktop, but it won’t on mobile. The reason is that there is increased video memory usage and an increased layer management cost, both of which could have a negative impact on performance. Instead, use hardware compositing only to isolate elements where the paint cost is measurably high.

Note: In the WebKit nightlies, the Web Inspector now also gives you the reasons for layers being composited. To enable this, switch off the “Use WebKit Web Inspector” option and you’ll get the front end with this feature in there. Switch it on using the “Layers” button.

A Find-and-Fix Workflow

Now that we’ve concluded our Pinterest case study, what about the workflow for diagnosing and addressing your own paint problems?

Finding the Problem

- Make sure you’re in “Incognito” mode. Extensions and apps can skew the figures that are reported when profiling performance.

- Open the page and the Developer Tools.

- In the timeline, record and interact with your page.

- Check for frames that go over budget (i.e. over 60 FPS).

- If you’re close to budget, then you’re likely way over the budget on mobile.

- Check the cause of the jank. Long paint? CSS layout? JavaScript?

Spend some quality time with Frame mode in Chrome Developer Tools to understand your website’s runtime profile. Larger view.

Fixing the Problem

- Go to “Settings” and enable “Continuous Page Repainting.”

- In the “Elements” panel, hide anything non-essential using the hide (H) shortcut.

- Walk through the DOM tree, hiding elements and checking the FPS in the timeline.

- See which element(s) are causing long paints.

- Uncheck styles that could affect paint time, and track the FPS.

- Continue until you’ve located the elements and styles responsible for the slow-down.

Switch on extra Developer Tools features for more insight. Larger view.

What About Other Browsers?

Although at the time of writing, Chrome has the best tools to profile paint performance, we strongly recommend testing and measuring your pages in other browsers to get a feel for what your own users might experience (where feasible). Performance can vary massively between them, and a performance smell in one browser might not be present in another.

As we said earlier, don’t guess it, test it! Measure for yourself, understand the abstractions, know your browser’s internals. In time, we hope that the cross- browser tooling for this area improves so that developers can get an accurate picture of rendering performance, regardless of the browser being used.

Conclusion

Performance is important. Not all machines are created equal, and the fast machines that developers work on might not have the performance problems encountered on the devices of real users. Frame rate in particular can have a big impact on engagement and, consequently, on a project’s success. Luckily, a lot of great tools out there can help with that.

Be sure to measure paint performance on both desktop and mobile. If all goes well, your users will end up with snappier, more silky-smooth experiences, regardless of the device they’re using.

Further Reading

- “Performance Profiling With the Timeline,” Chrome DevTools, Google Developers

- Let’s Make the Web Jank-Free (resources)

- ““Don’t Guess It, Test It!” (article and video), Paul Lewis

- “CSS Paint Times and Page Render Weight,” Colt McAnlis, HTML5 Rocks

- “Accelerated Rendering in Chrome,” Tom Wiltzius, HTML5 Rocks

- “Avoiding Unnecessary Paints,” Paul Lewis, HTML5 Rocks

- “Fluid User Interface With Hardware Acceleration” (slidedeck) Ariya Hidayat, W3Conf 2013

About the Authors

Addy Osmani and Paul Lewis are engineers on the Developer Relations team at Chrome, with a focus on tooling and rendering performance, respectively. When they’re not causing trouble, they have a passion for helping developers build snappy, fluid experiences on the Web.

(al)

原文链接：http://www.smashingmagazine.com/2013/06/10/pinterest-paint-performance-case-study （本内容由互联网资料整理而成）

有效的解决gmail的内存问题

Introduction

While JavaScript employs garbage collection for automatic memory management, it is not a substitute for effective memory management in applications. JavaScript applications suffer from the same memory related problems that native applications do, such as memory leaks and bloat, yet they must also deal with garbage collection pauses. Large-scale applications like Gmail encounter the same problems facing your smaller applications. Read on to learn how the Gmail team used Chrome DevTools to identify, isolate, and fix their memory problems.

Google I/O 2013 Session

We presented this material at Google I/O 2013. Check out the video below:

Gmail, we have a problem...

The Gmail team was facing a serious problem. Anecdotes of Gmail tabs consuming multiple gigabytes of memory on resource-constrained laptops and desktops were being heard increasingly frequently, often with a conclusion of bringing the entire browser down. Stories of CPUs being pinned at 100%, unresponsive apps, and Chrome sad tabs (“He’s dead, Jim.”). The team was at a loss as to how to even begin diagnosing the problem, let alone fix it. They had no idea how widespread the problem was and the available tools didn’t scale up to large applications. The team joined forces with the Chrome teams, and together they developed new techniques to triage memory problems, improved existing tools, and enabled the collection of memory data from the field. But, before getting to the tools, let’s cover the basics of JavaScript memory management.

Memory Management Basics

Before you can effectively manage memory in JavaScript you must understand the fundamentals. This section will cover primitive types, the object graph, and provide definitions for memory bloat in general and a memory leak in JavaScript. Memory in JavaScript can be conceptualized as a graph and because of this Graph theory  plays a part in JavaScript memory management and the Heap Profiler.

Primitive Types

JavaScript has three primitive types:

1. Number (e.g. 4, 3.14159)

2. Boolean (true or false)

3. String (“Hello World”)

These primitive types cannot reference any other values. In the object graph these values are always leaf or terminating nodes, meaning they never have an outgoing edge.

There is only one container type: the Object. In JavaScript the Object is an associative array. A non-empty object is an inner node with outgoing edges to other values (nodes).

What About Arrays?

An Array in JavaScript is actually an Object that has numeric keys. This is a simplification, because JavaScript runtimes will optimize Array-like Objects and represent them under the hood as arrays.

Terminology

1. Value - An instance of a primitive type, Object, Array, etc.

2. Variable - A name that references a value.

3. Property - A name in an Object that references a value.

Object Graph

All values in JavaScript are part of the object graph. The graph begins with roots, for example, the window object.  Managing the lifetime of GC roots is not in your control, as they are created by the browser and destroyed when the page is unloaded. Global variables are actually properties on window.

When Does a Value Become Garbage?

A value becomes garbage when there is no path from a root to the value. In other words, starting at the roots and exhaustively searching all Object properties and variables that are alive in the stack frame, a value cannot be reached, it has become garbage.

What is a Memory Leak in JavaScript?

A memory leak in JavaScript most commonly occurs when there are DOM nodes that are not reachable from the page’s DOM tree, but are still referenced by a JavaScript object. While modern browsers are making it increasingly difficult to inadvertently create leaks, it’s still easier than one might think. Let’s say you append an element to the DOM tree like this:

email.message = document.createElement(“div”);
displayList.appendChild(email.message);

And later, you remove the element from the display list:

displayList.removeAllChildren();

As long as

email
exists, the DOM element referenced by message will not be removed, even though it is now detached from the page’s DOM tree.

What is Bloat?

Your page is bloated when you’re using more memory than necessary for optimal page speed. Indirectly, memory leaks also cause bloat but that is not by design. An application cache that does not have any size bound is a common source of memory bloat. Also, your page can be bloated by host data, for example, pixel data loaded from images.

What is Garbage Collection?

Garbage collection is how memory is reclaimed in JavaScript. The browser decides when this happens. During a collection, all script execution on your page is suspended while live values are discovered by a traversal of the object graph starting at the GC roots. All the values which are not reachable  are classified as garbage. Memory for garbage values is reclaimed by the memory manager.

V8 Garbage Collector in Detail

To help further understand how garbage collection happens, let’s take a look at the V8 garbage collector in detail. V8 uses a generational collector. Memory is divided into two generations: the young and the old. Allocation and collection within the young generation is fast and frequent. Allocation and collection within the old generation is slower and less frequent.

Generational Collector

V8 uses a two generation collector. The age of an value is defined as the number of bytes allocated since it was allocated. In practice, the age of an value is often approximated by the number of young generation collections that it survived. After a value is sufficiently old it is tenured into the old generation.

In practice, freshly allocated values do not live long. A study of Smalltalk programs, showed that only 7% of values survive after a young generation collection. Similar studies across runtimes found that on average between, 90% and 70%  of freshly allocated values are never tenured into the old generation.

Young Generation

The young generation heap in V8 is split into two spaces, named from and to. Memory is allocated from the to space. Allocating is very fast, until, the to space is full at which point a young generation collection is triggered. Young generation collection first swaps the from and to space, the old to space (now the from space) is scanned and all live values are copied into the to space or tenured into the old generation. A typical young generation collection will take on the order of 10 milliseconds (ms).

Intuitively, you should understand that each allocation your application makes brings you closer exhausting the to space and incurring a GC pause. Game developers, take note: to ensure a 16ms frame time (required to achieve 60 frames per second), your application must make zero allocations, because a single young generation collection will eat up most of the frame time.

Old Generation

The old generation heap in V8 uses a mark-compact algorithm for collection. Old generation allocations occur whenever a value is tenured from the young generation to the old generation. Whenever an old generation collection occurs a young generation collection is done as well. Your application will paused on the order of seconds. In practice this is acceptable because old generation collections are infrequent.

Automatic memory management with garbage collection is great for developer productivity, but, each time you allocate a value, you move ever closer to a garbage collection pause. Garbage collection pauses can ruin the feel of your application by introducing jank. Now that you understand how JavaScript manages memory, you can make the right choices for your application.

Fixing Gmail

Over the past year, numerous features and bug fixes have made their way into the Chrome DevTools making them more powerful than ever. In addition, the browser itself made a key change to the performance.memory API making it possible for Gmail and any other application to collect memory statistics from the field. Armed with these awesome tools, what once seemed like an impossible task soon became an exciting game of tracking down culprits.

As of Chrome 22, the performance.memory API is enabled by default.  For long-running applications like Gmail, data from real users is invaluable. This information allows us to distinguish between power users-- those who spend 8-16 hours a day on Gmail, receiving hundreds of messages a day-- from more average users who spend a few minutes a day in Gmail, receiving a dozen or so messages a week.

This API returns three pieces of data:

1. jsHeapSizeLimit - The amount of memory (in bytes) that the JavaScript heap is limited to.

2. totalJSHeapSize - The amount of memory (in bytes) that the JavaScript heap has allocated including free space.

3. usedJSHeapSize - The amount of memory (in bytes) currently being used.

One thing to keep in mind is that the API returns memory values for the entire Chrome process. Although it is not the default mode, under certain circumstances, Chrome may open multiple tabs in the same renderer process. This means that the values returned by performance.memory may contain the memory footprint of other browser tabs in addition to the one containing your app.

Measuring Memory At Scale

Gmail instrumented their JavaScript to use the performance.memory API to collect memory information approximately once every 30 minutes.  Because many Gmail users leave the app up for days at a time, the team was able to track memory growth over time as well as overall memory footprint statistics. Within a few days of instrumenting Gmail to collect memory information from a random sampling of users, the team had enough data to understand how widespread the memory problems were among average users. They set a baseline and used the stream of incoming data to track progress toward the goal of reducing memory consumption. Eventually this data would also be used to catch any memory regressions.

Beyond tracking purposes, the field measurements also provide a keen insight into the correlation between memory footprint and application performance.  Contrary to the popular belief that “more memory results in better performance”, the Gmail team found that the larger the memory footprint, the longer latencies were for common Gmail actions. Armed with this revelation, they were more motivated than ever to rein in their memory consumption.

Identifying a Memory Problem with the DevTools Timeline

The first step in solving any performance problem is to prove that the problem exists, create a reproducible test, and take a baseline measurement of the problem. Without a reproducible program, you cannot reliably measure the problem. Without a baseline measurement you don’t know by how much you’ve improved performance.

The DevTools Timeline panel is an ideal candidate for proving that the problem exists. It gives a complete overview of where time is spent when loading and interacting with your web app or page. All events, from loading resources to parsing JavaScript, calculating styles, garbage collection pauses, and repainting are plotted on a timeline. For the purposes of investigating memory issues, the Timeline panel also has a Memory mode which tracks total allocated memory, number of DOM nodes, number of window objects, and the number of event listeners allocated.

Proving a problem exists

Start by identifying a sequence of actions you suspect to be leaking memory. Start recording the timeline, and perform the sequence of actions.  Use the trash can button at the bottom to force a full garbage collection.  If, after a few iterations, you see a sawtooth  shaped graph, you are allocating lots of shortly lived objects. But if the sequence of actions is not expected to result in any retained memory, and the DOM node count does not drop down back to the baseline where you began, you have good reason to suspect there is a leak.

Once you’ve confirmed that the problem exists, you can get help identifying the source of the problem from the DevTools Heap Profiler.

Finding Memory Leaks with the DevTools Heap Profiler

The Profiler panel provides both a CPU profiler and a Heap profiler. Heap profiling works by taking a snapshot of the object graph. Before a snapshot is taken both the young and old generations are garbage collected. In other words, you will only see values which were alive when the snapshot was taken.

There is too much functionality in the the Heap profiler to cover sufficiently in this article, but detailed documentation can be found on the Google Developers site. We’ll focus here on the all new Object Tracker, available now via an experiment on the latest Chrome builds.  To enable the Object Tracker:

1. Make sure you have the latest Chrome Canary.

2. Navigate to about:flags, and make sure “Enable Developer Tools experiments” is enabled. You will need to restart Chrome to activate the experiments.

3. Open the Developer Tools and click on the gear icon in the lower right.  Find the Experiments item in the menu on the left, and check the box labeled “Enable heap objects tracking profile type”.  You will need to close and reopen the DevTools to make this change take effect.

4. Now, when you open the Profiler panel, you should see a fourth profile type option, called “Track Allocations”.

Using the Object Tracker

The Object Tracker combines the detailed snapshot information of the Heap Profiler with the incremental updating and tracking of the Timeline panel. Start a recording, perform a sequence of actions, then stop the recording for analysis. The Object Tracker takes heap snapshots periodically throughout the recording (as frequently as every 50 ms!) and one final snapshot at the end of the recording.

The bars at the top indicate when new objects are found in the heap.  The height of each bar corresponds to the size of the recently allocated objects, and the color of the bars indicate whether or not those objects are still live in the final heap snapshot: blue bars indicate objects that are still live at the end of the timeline, gray bars indicate objects that were allocated during the timeline, but have since been garbage collected.

In the example above, an action was performed 10 times.  The sample program caches five objects, so the last five blue bars are expected.  But the leftmost blue bar indicates a potential problem. You can then use the sliders in the timeline above to zoom in on that particular snapshot and see the objects that were recently allocated at that point.  Clicking on a specific object in the heap will show its retaining tree in the bottom portion of the heap snapshot. Examining the retaining path to the object should give you enough information to understand why the object was not collected, and you can make the necessary code changes to remove the unnecessary reference.

Resolving Gmail's Memory Crisis

By using the tools and techniques discussed above, the Gmail team was able to identify a few categories of bugs:  unbounded caches, infinitely growing arrays of callbacks waiting for something to happen that never actually happens, and event listeners unintentionally retaining their targets. By fixing these issues, the overall memory usage of Gmail was dramatically reduced. Users in the 99% percent used 80% less memory than before and the memory consumption of the median users dropped by nearly 50%.

Because Gmail used less memory the GC pause latency was reduced, increasing the overall user experience.

Also of note, with the Gmail team collecting statistics on memory usage, they were able to uncover garbage collection regressions inside Chrome. Specifically, two fragmentation bugs were discovered when Gmail’s memory data began showing a dramatic increase in the gap between total memory allocated and live memory.

Call to Action

Ask yourself these questions:

1. How much memory is my app using?

It’s possible that you are using too much memory which contrary to popular belief has a net negative on overall application performance. It’s hard to know exactly what the right number is, but, be sure to verify that any extra caching your page is using has a measurable performance impact.

If your page has memory leaks it can not only impact your page's performance but other tabs as well. Use the object tracker to help narrow in on any leaks.

1. How frequently is my page GCing?

You can see any GC pause using Timeline panel in Chrome Developer Tools. If your page is GCing frequently, chances are you are allocating too frequently, churning through your young generation memory.

Conclusion

We started off in a crisis. Covered the core basics of memory management in JavaScript and V8 in particular. You learned how to use the tools, including the new object tracker feature available in the latest builds of Chrome. The Gmail team, armed with this knowledge, solved their memory usage problem and saw improved performance. You can do the same with your web apps!

原文链接：http://www.html5rocks.com/en/tutorials/memory/effectivemanagement （本内容由互联网资料整理而成）

Web开发牛人访谈：你们都在用什么？

@玉面小飞鱼译注：早上看到这篇文章，觉得内容甚是有趣。作者跟web开发方面的诸多大牛进行了交流，了解到他们的研究动向，从访谈中可以看到各种风格的开发者，有浏览器控，有设备控。我想，知道行业里的优秀成员在做些什么以及用些什么对于我们或许会有一些用处。另外原文作者还采访了我的偶像Lea Verou，所以忍不住花了一天时间将此文翻译出来与大家共享了，不足之处还望多多批评指正！以下是正文。

在Web开发领域，我们通常会花一些时间关注行业大牛的动态，比如他们开发所用的一些工具或者类库，看他们写的技术文章，学习他们学过的一些酷霸狂旋拽的技术，甚至参加一些新语言的发布会。如果能够知道这些大牛正在关注些什么，以及他们开发时应用的工具，那必定是极好的。

关于这些问题，我访问了Web开发领域的一些闪亮明星。这些人在web开发领域都有着突出的贡献，并且得到业内的极高评价，他们通过自己的代码，文章以及领导力推动着Web开发的发展。你可以在下文中的简介部分了解更多他们的详细信息。

这些牛人非常忙碌，因此，我把问题缩减到了四个：

1. 你的开发工作主要关注点是什么？

2. 你进行开发工作时所用的硬件设备是什么？

3. 你用什么编辑器或者IDE？

4. 你的日常生活中必不可少的软件是什么？

在下文就有他们的回答，或许从这些回答中你可以发现一些更有利于你的开发工具。你会发现一些有一些通用的工具（如Sublime Text）以及一些至少对我来说很新的工具。

Scott Gonzalez

简介：我是一个web应用程序开发人员，主要致力于JavaScript。2007年开始为jQuery效力，目前是jQuery UI的项目经理。我比较活跃的社区有Node.js，WHATWG和W3C。Scott的Blog和Twitter。

Q 1. 你的开发工作主要关注点是什么？
Web开发，只要是客户端的JS以及Node.js

Q 2. 你进行开发工作时所用的硬件设备是什么？
MacBook Pro.

Q3. 你用什么编辑器或者IDE？
Sublime Text, 搭配插件TrailingSpaces（可以高亮空格并瞬间删除），Pretty JSON，GitGutter 和 Markdown Preview。

Q4.你的日常生活中必不可少的软件是什么？
Git, GitHub, Apache, Chrome, Linkinus, Skype, Node。

Raymond Camden

简介：Raymond是一个Adobe中级开发布道者。他的工作主要侧重于web标准，移动开发以及ColdFusion。他出版了一些作品，并且在很多会议和group中发表了很多主题演讲。Raymond的Blog和Twitter。

Q 1. 你的开发工作主要关注点是什么？
我的开发工作主要侧重于web标准，Adobe的Creative Cloud（侧重于HTML tools）以及客户端开发的“non-sexy”部分。我欣赏CSS，不过我对storage，JavaScript以及表单更感兴趣。

Q 2. 你进行开发工作时所用的硬件设备是什么？
我的硬件设备是MacBook Pro。因为我需要做很多的移动端开发，因此，我会在iPhone，Android phone以及各种平板（tablet）上面进行测试。比较诡异的是，我每天要用的唯一一件微软的硬件产品就是我的键盘。我用“Natural”键盘已经有15个年头了，我对它们已经上瘾了。

Q3. 你用什么编辑器或者IDE？
我的编辑器是Brackets，它是一个开源的编辑器，我们用了大约一年。它和Chrome可以很好的绑定，并且具有酷毙的扩展性能。

Q4.你的日常生活中必不可少的软件是什么？
Browser，我的编辑器，Tweetdeck以及Evernote（我用Evernote记录我所有的事情，包括项目资料以及一些零碎的事情）。

John-David Dalton

简介：JDD 是jsPerf/Benchmark.js的共同维护者，是ES5规范的布道者，JavaScript 库的爱好者，两度获得微软IE testing的MVP。在微软负责Chakra performance项目。JDD的Github和Twitter。

Q 1. 你的开发工作主要关注点是什么？
简单的实用工具库。我是一个工具库的忠实粉丝，并且热衷于围绕他们进行开发。

Q 2. 你进行开发工作时所用的硬件设备是什么？
我工作的装备是Win8和IE10。我个人的开发设备是13’’ 的Macbook Pro，OS X10.7.5，2.3GHz 处理器，8GBs的内存。

Q3. 你用什么编辑器或者IDE？
我在OS X和Windows中用的都是Komodo Edit，最爱它的高级搜索功能，可以使用正则表达式和嵌套文件进行搜索。

Q4.你的日常生活中必不可少的软件是什么？
除了我的编辑器之外，我使用Total finder，我几乎拥有所有的浏览器：22个不同版本的Chrome，5个版本的IE，23个版本的Firefox，12个版本的Opear，以及6个版本的Safari。在我发布一个产品的新版本之前，我会确保这个产品在我声明的系统以及浏览器中运行顺利，这也是我为什么要拥有所有的浏览器版本的原因。其他的必备软件包括 Node，Ringo，Rhino以及Narwhat。

Stephanie Sullivan Rewis

简介：Stephanie 是Contatta的董事，负责web运营战略以及市场营销。作为前端开发工程师，她在多个国际性会议上都有演讲，包括HOW Design，UI16，An Event Apart, Microsoft’s MIX, Macworld, SXSW, Adobe Max 等等。她出版过自己的作品，主要负责W3Conversions，并且与跨度很大的一些机构一起工作，包括Newsweek，MLB, New York Magazine, Adobe, SalesForce.com，甚至是 Disney’s “TRON” movie site。

Stephanie的 Blog和Twitter。

Q 1. 你的开发工作主要关注点是什么？
我是一个前端开发工程师，但是因为参与Contatta新启动项目的关系，我有幸可以参与完成我们的新CMS项目，因此，我需要学习一些PHP的知识。

Q 2. 你进行开发工作时所用的硬件设备是什么？
我没有很特殊的装备，我个人的开发设备是17’’ 的Macbook Pro（我没有升级装备，因为不想降级使用15’’ 的设备）。如果我在工作桌前，那么我会使用外接显示器，我喜欢用的显示器是Costco，我不太偏爱高级装备，这样我就可以看到我的网站在普通用户眼中是什么样子的。

Q3. 你用什么编辑器或者IDE？
目前我日常开发用的是Sublime Text 2。如果Adobe的开源编辑器Brackets不断朝着它所描述的方向继续发展的话，我会选择尝试一下。我也会用Dreamweaver进行邮件相关的开发。

Q4.你的日常生活中必不可少的软件是什么？
除了我的编辑器之外，我通常会用CodeKit来编译我的Sass以及压缩CSS和JS文件。我用Git进行代码管理，使用Tower来提交代码。

我利用HipChat与团队中的其他人进行沟通。HipChat最好的一点就是它的Hu Bot,它可以自动部署我的代码，我爱我的bot！

我的设计师使用Fireworks，所以我有时会用它来打开图片，切图等等（没错，我知道Adobe已经不再更新Fireworks了，但是它可以满足设计师的需求。因此，将来我们需要将它与设计师痛苦分离）。我喜欢打开音乐播放器Spotify，通常我会根据心情以及正在从事的开发工作选择艺术家（今天，我选的是Hellsongs 频道）。

最后，我会给Chrome设定每天的work out，有时候会多达150多个标签。我用它来管理我必备的一些插件（1password，OneTab, ColorZilla, Cache Killer, and Dragdis, 等等），以及一些我需要不断维护的事情，如Google Analytics, MailChimp, SproutSocial, Google Docs，同时还有一些我正在进行研究的事情。

Christian Heilmann

简介：Chris Heilmann致力于让web变得更好。他的学科背景是新闻专业，1997年建立了自己的第一个网站，此后多年效力于多家大型国际性站点。后来在Yahoo工作了几年，从事产品开发和员工培训，目前在Mozilla工作。Chris撰写了四本web开发方面的书，并且发表了上百篇博文，他的文章广泛发表在Ajaxian, Smashing Magazine, Yahoo, Mozilla, ScriptJunkie等知名站点。

Christian的 Blog和Twitter。

Q 1. 你的开发工作主要关注点是什么？
我主要的工作侧重点是确保有人接手我的工作的时候，能够很轻松地看懂我的代码并且方便地进行扩展。不幸的是，这是一项过时又耗时的不太有人愿意做的事。我认为从别人的工作中我们可以学到很多，并且我认为编写简洁易懂的代码比单纯的交付工作更加重要。

我关注的是web，不单单是某个浏览器或者操作系统。这就意味着你需要提高你的代码灵活性。灵活性意味着你的代码可以在这里运行，立刻运行，并且在未来需要添加新功能的时候可以很方便的进行扩展。我认为，经过16年的web开发，我们应该进入一个新的阶段，不要再把各种技术堆积在一起，并且不停地替换它们。

Q 2. 你进行开发工作时所用的硬件设备是什么？
Macbook Air，我经常需要跑来跑去，因此不适合携带大型的硬件设备。

Q3. 你用什么编辑器或者IDE？
Sublime Text2，很棒。

Q4.你的日常生活中必不可少的软件是什么？
Browser以及他们的开发工具，Git，an IRC client, Dropbox 以及 Spotify，我越来越多的使用线上的一些服务。

Ryan Grove

简介：Ryan Grove 是SmugMug的一个魔法师，YUI 评阅员，曾经是一家日本服装目录的少年模特。他喜欢pie，电影，老式帆船。

Ryan的 Blog和Twitter。

Q 1. 你的开发工作主要关注点是什么？
最近我的大部分时间用于SmugMugde的客户端JS组件以及新功能的开发。在课余时间，我写了很多Node.js的代码，偶尔也会写写Ruby。在SmugMug，我们的框架用的是YUI3，我也是YUI的核心评阅员，我为它贡献了一些代码，并且也审阅了其他提交者以及开发人员提交的一些代码。

在一些特定的日子，我有时候会写一些非开源的Smugmug代码，有时是一些开源的代码，或者是开源的YUI代码。我们尽可能多的开源我们的JS代码，其中有一些已经添加到了YUI框架中。

Q 2. 你进行开发工作时所用的硬件设备是什么？
我在家的时候用的是2.8GHz 四核 Mac Pro，配备16GB内存和SSD。搭配30’’ 的HP ZR39w 显示器，这样看大图以及视频的时候效果超赞！当我旅行的时候，携带的是13’’ 的Macbook Air（mid-2011, Core i7）。

我酷爱收集用于测试的移动设备。每款iPhone和iPad至少都有一台，多款Android设备，一台Windows phone以及一部Chromebook。

Q3. 你用什么编辑器或者IDE？
我用Sublime Text3来写所有的东西。I want to marry it and have its kittens。

Q4.你的日常生活中必不可少的软件是什么？
除了Sublime Text3之外，我的一些必备app包括JSHint，iTerm2，Adium，OS X messages，Tower，Dropbox and Rsync，Arq (for backup), Gmail, GitHub, 以及 Chrome。

SmugMug有很多远程工作者，所以我们利用Google Hangout开会以及进行面对面的交流。IRC也是一个重要的沟通媒介。SmugMug有自己的IRC服务器，我利用Colloquy iOS app来获取通知，当有人提到我的名字或者发送给我信息时，即使我不再电脑旁边我也可以收到消息提醒。

Charles, cURL, and the REST Console Chrome extension 在调试HTTP请求和调用API时必不可少。我超爱用Alfred来搜索我需要的资料。

Cody Lindley

简介：前端开发/UI/JS 工程师。热爱基督/人类/逻辑，热衷辩论，交流以及理性思维。已婚人士，三个男孩的爸爸。Cody的 Blog和Twitter。

Q 1. 你的开发工作主要关注点是什么？
我工作的主要是关注网站开发以及客户端web应用程序用到的前端代码（i.e HTML，CSS和JavaScript）。如果需要的话，我也会关注平板以及移动客户端的开发。

Q 2. 你进行开发工作时所用的硬件设备是什么？
我的开发装备是MacBook Pro，配备27’’苹果显示器，以及苹果无线键盘。

Q3. 你用什么编辑器或者IDE？
Sublime Text2。

Q4.你的日常生活中必不可少的软件是什么？
SmartGit, Sublime Text, Divvy, JumpCut, Google (search, gmail, drive, calendar), Skype, Terminal, Chrome, Tweetdeck, Parallels, Textual, Dropbox, Github, Assembla。

Luke Smith

简介：美国俄勒冈州波特兰市本土出品，天然草料喂养的纯有机web开发工程师。我很幸运能够在SmugMug与这个伟大的团队一起工作。说到伟大的团队，我之前在YUI做了5年的程序开发，现在仍然为这个项目做一些贡献。我的意思是为这个社区做贡献。Luke 的 Twitter。

Q 1. 你的开发工作主要关注点是什么？
我主要从事的是JavaScript的开发，日复一日。我更喜欢从事一些简单的API，基于事件系统，协议以及XHR/data IO 框架做一些抽象化的工作或者工具。我尝试着让API更加直观, 灵活，快速。基本指导原则就是至少要惊艳并且友好（surprize-friendly stuff）。与此同时，我也喜欢使用一些高级组件解决一些UI实现方面挑战。最重要的一件事情是，我喜欢尽可能的帮助别人。我希望自己可以在JS，DOM以及标准方面贡献更多。

Q 2. 你进行开发工作时所用的硬件设备是什么？
我有两台13寸的MacBook Air ，一台用于工作，一台个人使用。用于工作的Air外接一个22” 的POS显示器，搭配一个苹果键盘，以及一个神奇的触摸板（magic track pad）。我讨厌不分区的键盘布局，但是我更加喜欢它的按键的样式以及触感，因此我妥协了。我同样讨厌触摸板名字中的“magic”。

在Air出现之前我尝试过很多的笔记本，并没有产生特别的喜好。Air非常棒，是我使用过得最好的个人笔记本。顺便我要推荐一下Yapster耳机，性价比很高。

Q3. 你用什么编辑器或者IDE？
Vim

Q4.你的日常生活中必不可少的软件是什么？
必备：Terminal, Vim, Git, and Chrome (dev tools \m/)。
辅助工具：Shifter (for YUI stuff), Github’s pull request and issues systems, VirtualBox, and 1Password.
常用: Mail.app (for lack of a better client), Itsy (minimalist twitter client), Reeder, iOS Reminders app, and Adium.

Chris Williams

简介：Chris 是SaferAging产品开发的副总，同时也是JSConf US和RobotsConf的组织者。他是node-serialport的作者，JS Community Logo 的发起人，协助开发NodeBots和NodeCopter。他时常受到妻子以及两个宝贝孩子的鼓舞。

Chris的 JSconf 和RobotsConf。

Q 1. 你的开发工作主要关注点是什么？
我最近关注的是开发的整个环节。从硬件传感器的编程与开发，到高性能的服务基础架构与开发，也包括前端的信息展示。在一个礼拜的时间，我会从事焊接硬件，编写松鼠固件（squirrel firmware），检测以及升级服务器，开发新的用户界面和交互体验（不一定是基于web和视觉体验的）。所以要说明一个主要的关注点很难，因为这些技术对于我将要从事或者支持开发的产品同样重要。

Q 2. 你进行开发工作时所用的硬件设备是什么？
我所用的主要是苹果的产品，旅行的时候用MacBook Air，工作的时候用Mac Pro，在家的时候用Mac Mine，苹果的产品拥有一流的做工，并且视觉效果超好。

Q3. 你用什么编辑器或者IDE？
在不同的工作环境中我会选择不同的编辑器。在服务端，我会使用VIM。在本地设备上，我习惯使用Sublime Text 3，出于好奇心，我也会尝试使用别的编辑器。

我会使用一些插件（EJS，Emmet，Go，GitGutter，JSFormat，Squirrel）来帮助我实现语法高亮以及代码格式化。我觉得很多标准的IDE太过笨重，说实话，在用他们的时候我时常会迷路。即便是用Sublime，我也时常会混淆快捷键的组合，我想做的仅仅是完成我想要完成的，没有浮华，仅仅是在最短的时间内最优化的完成工作。

Q4.你的日常生活中必不可少的软件是什么？
Sublime Text 3，不过归结起来，一个原始的文字编辑器胜过任何东西。iTerms2和Fish shell节省了大量时间。Wunderlist提醒我各种待办事宜。除了这些软件，另外一件离不开的物品就是我的Das Keyboard，在任何其他的键盘上输入文字都让我感觉不自然不舒服。

Aaron Newton

简介：Aaron Newton是个万事通，样样都懂一点。创业老手，最近的创业项目是Cloudera，他目前在Thanx负责产品开发。他很早就参与了MooTools框架的开发，他编写了大量的教程，写过一本书，写过不计其数的JavaScript代码。

Aaron的 MooTools和  Twitter。

Q 1. 你的开发工作主要关注点是什么？
我目前是Thanx的产品经理，我是一个技术控，因此我会主持一些功能完善方面的讨论，同时也会进行代码审阅工作，我自己也会进行一些开发的工作。我们的产品主要是一款移动应用，我们有IOS版的原生app以及移动端浏览器可以访问的HTML5版本。在Android客户端中也有一款可以通过浏览器访问的HTML5版本。我倾向于开发HTML5版本，并且也会致力于开发传统的web端应用，开发一个操作面板供我们的用户以及我们内部使用。

Q 2. 你进行开发工作时所用的硬件设备是什么？
我最信任的MacBook Pro，所有的一切运行在AWS / Heroku上面。

Q3. 你用什么编辑器或者IDE？
最近在用Sublime Text。我曾经一度是TextMate的忠实粉丝，但是经过漫长的等待，TextMate仍然没有任何的技术更新。我喜欢Sublime的各种技术支持，不过导致我最终放弃TextMate拥抱Sublime的是两个功能，第一个就是分割试图（split views），另外一个就是闪电般的快速搜索。在TextMate上面进行搜索的体验类似于“我的程序正在编译，我可以出去喝杯咖啡。”

Q4.你的日常生活中必不可少的软件是什么？
除了浏览器Chrome之外，其他的一些工具包括：Cloudapp，Jing，Sequel Pro，Jumpcut，Total Terminal，GitX。

Ben Cherry

简介：Ben住在美帝三藩市，主要关注Ruby和IOS开发。之前他启动了一个基于IOS和Node.js的创业项目，不过失败了，在这之前他在Twitter和Slide上面写JavaScript的一些东西。他维护了一个有关JavaScript的技术博客：http://www.adequatelygood.com 。Ben的 Blog和  Twitter。

Q 1. 你的开发工作主要关注点是什么？
我花了3年的时间为Slide和Twittter写了大量的JavaScript，最近我致力于IOS以及Ruby开发，偶尔会写写JavaScript。

Q 2. 你进行开发工作时所用的硬件设备是什么？
13’’ 的Retina Macbook Pro，搭配27寸的Thunderbolt显示器。

Q3. 你用什么编辑器或者IDE？
Sublime Text 2，超爱它！

Q4.你的日常生活中必不可少的软件是什么？
SublimeText 2, iTerm 2, Google Chrome, 1Password, Gmail, Flipboard, Twitter, Facebook, Reddit。

Jacob Thornton

简介：我在@medium上面写一些代码，我开源了一些项目，比如Bootstrap和Bower。我常常会做一些演讲，有时候也会写写web的一些东西。

Jacob的 Blog和 Twitter。

Q 1. 你的开发工作主要关注点是什么？
我的大部分在时间是用于前端开发工作（JS/CSS/HTML），我也会进行一些工具开发以及少量服务器端的工作。此外我也在尝试提高我的可访问性——通过拜见这一领域的大牛，比如Paypal的Victor Tsaran和Joshua Miele。

Q 2. 你进行开发工作时所用的硬件设备是什么？
我在家中用的是15’’ 的Macbook Pro 以及 13’’ 的Macbook Air。我在不同的设备上进行大量的测试，包括：iPad，iPhone，Android平板，Android phone，黑莓甚至是Windows 平板（原文是Windows slate）。

Q3. 你用什么编辑器或者IDE？
我现在用的是Sublime Text 2。我之前用的是Vim，但是我发现其他的前端开发者并没有很好的用它，并且它用起来很古怪，我用的时候老是来回切换。说实话，我是个电脑白痴…我认识很多的工程师，他们把电脑玩得炉火纯青，并且灵活运动各种编辑器的个性化配置，但是对于这些我并不在行。

Q4.你的日常生活中必不可少的软件是什么？
Rdio，没有了音乐，我一无是处。

Lea Verou

简介：Lea 是W3C的开发者布道师。她长期致力于开放web标准，为了实现这个目标，她不断开发新的方法来应用这些标准，通过博客，演讲，写作，以及编写开源项目来帮助其他的开发人员更好地运用web标准。她也是CSS工作组的成员，参与设计这门语言。

Lea的 Blog和 Twitter。

Q 1. 你的开发工作主要关注点是什么？
关于客户端的所有技术。我从事的是HTML，CSS，JavaScript甚至是设计以及UX方面的工作。我热爱CSS，这种热爱在我加入CSS工作小组之后变得更加强烈。

Q 2. 你进行开发工作时所用的硬件设备是什么？
我去年六月买了13’’ MacBook Air，超爱它。它的触摸板在过去几个月有点问题，不过最近已经更换并且修好了。因此，我又爱上了我的lil’s MacBaby (这是女神赐给Air的昵称～～)。

Q3. 你用什么编辑器或者IDE？
Espresso。我知道有很多更好的编辑器，不过它整合FTP的功能非常棒！

Q4.你的日常生活中必不可少的软件是什么？
Native apps: Espresso, Transmit, CodeKit, Adobe Illustrator, Chrome, Safari, Firefox, Opera, WebKit nightlies, Chrome Canary.

Web apps: Browserstack, Dabblet, copypastecharacter.com, css.coloratum.com, Workflowy, and Github.

Jonathan Snook

简介：Jonathan Snook是Shopify的一个web设计师/开发工程师，他爱说，爱写，并且运用所有的智慧开发网站。Jonathan的 Blog 和  Twitter。

Q 1. 你的开发工作主要关注点是什么？
最近我主要在进行前端开发工作，HTML/CSS/JavaScript。

Q 2. 你进行开发工作时所用的硬件设备是什么？
我的主要开发装备是11’’ MacBook Air。当需要进行测试时，我会尽可能在真实的测试设备上进行测试。我有一台三星的平板，系统是Windows8，有一台Nexus 7，一台iPad Mini，一部iPhone以及一部更老的装载WebOS的手机。目前还没有黑莓的手机设备。对于IE6到IE9的测试，我使用的是VMWare，分别配合Windows XP, Windows 7 和 Windows 8 VMs。

Q3. 你用什么编辑器或者IDE？
Vim。它用起来超级顺手，并且当我远程登录Linux机器的时候，我喜欢用一些熟悉的工具。

Q4.你的日常生活中必不可少的软件是什么？
Vim和Chorme。我现在越来越多地用Google Docs。Google在提升他们的工具方面做得很棒！我已经开始在购买Google全套的工具。

Peter Wagenet

简介：Peter从事web应用开发将近15年了，目前就职于Ember，之前在SproutCore团队工作。他在Ruby on Rails方面也有丰富经验，同时也涉足IOS开发。他最近在Tilde项目上的工作成果可以通过Skylight查看。Peter的 Twitter。

Q 1. 你的开发工作主要关注点是什么？
我每天大部分的工作时间都在从事Ember的开发。目前，我每周有两天的时间用于Ember项目，其他的时间用在Tilde的项目上，主要是Skylight，它是一个Ember的客户端，后台语言是Rails。它也有一部分组件是Java构成的，不过我并不从事这一部分。

Q 2. 你进行开发工作时所用的硬件设备是什么？
我用的是MacBook Air，2GHz Core i7 和 8GBs of RAM，搭配一个27寸的显示器。

Q3. 你用什么编辑器或者IDE？
我最近在用的是Sublime Text3。一开始是用TextMate，那是我的最爱。不过等待TextMate2的时间太久了，所以就改用了VIM。VIM的键盘绑定功能让我着迷，然而它的插件体验让我感觉不爽。对于我来说，Sublime的快捷键可以满足我用VIM时95%的键盘绑定功能，它的插件体验更好，并且这款编辑器更加优美。我不认为使用一个成熟的IDE会使我的编程效率大增，对于我来说，代码自动补全已经够用了。我用过的唯一一款成熟的IDE是Xcode，当我用它的时候，老是会忘记键盘快捷方式。

Q4.你的日常生活中必不可少的软件是什么？
我常用的浏览器是Chrome，我听说Firefox中添加了很多很酷的开发工具，因此，我可能会被说服而改用Firefox。对于通话和沟通联系，我常用的是Adium for AIM, GTalk, IRC and Flint for Campfire。我仍然在用普通的邮件客户端以及基本的Twitter客户端。我并不是一个工具狂，但是最近我爱上了Divvy，1Password也是必备软件。因为我的菜单栏中有很多项目，因此，Bartender也必不可少。

总结

看了这么多，相信你已经大致了解了web开发领域的大牛们每天都在用哪些技术以及工具。在此，我们想对全体参与访问的Web开发者大声说一句“谢谢！”。

欢迎大家在评论中留言，分享你每天在用的开发工具、开发硬件设备、编辑器或者IDE，还有每天必不可少的软件。

英文原文：net tuts+，编译：伯乐在线 - @玉面小飞鱼

译文链接：http://blog.jobbole.com/41251/

【非特殊说明，转载必须在正文中标注并保留原文链接、译文链接和译者等信息，谢谢合作！】

(1 个评分，平均: 5.00)

Loading ...

原文链接：http://blog.jobbole.com/41251 （本内容由互联网资料整理而成）

CSS布局的未来

本文由LL根据Peter Gasston的《The future of CSS layouts》站点所译，整个译文带有我们自己的理解与思想，如果译得不好或不对之处还请同行朋友指点。如需转载此译文，需注明英文出处：http://www.netmagazine.com/features/future-css-layouts，以及作者相关信息

——作者：Peter Gasston

——译者：LL

大家都知道，css有着奇妙的特性，然而让人失望的是，css对基本页面布局上的支持有所欠缺。但是这种情况正在得到改变，更多的动态页面正是由css所支持的，正如peter gasston所说的。

这是一篇关于css布局且具有前瞻性的 文章。

在这里，我能够保证在数年之后，css3必定能够引领潮流。一揽子的前端工具正在应运而生，方便为我们带来rounded corners圆角，gradients渐变，opacity透明度，transformations，transitions，animations，甚至更多效果。但是现在我们都有了fun stuff，eye candy，还有需要什么呢？

下一个我们需要面对的就是关于定位css3的布局问题，虽然现在我们在可以使用float，relative定位，负值margin进行定位，但是我们仍然很难在多栏目的布局上大展身手。

W3C组织以及浏览器制作商意识到了这个问题，也推出了一揽子解决方案。其中的主力军是IE团队。IE10就好比步入css布局新时代的先驱者，它让我们的网站变得更加丰富多彩，灵活多变，吸引大家的眼球。

在这篇文章当中，我将为大家从优秀实用到纯粹理论阶段中介绍有关css布局的工具，也许在这些阶段中你不一定用得到他们，（至少不是现在），但仍然还很有必要去了解，通过这样可以透过迷雾，看清未来。如果你需要在这个文章当中对这些工具需要更多细节的介绍，或者更多介绍css3的内容，可以向大家推荐 这本书。

多列布局（Columns）

在多栏目中分配好内容是排版的重中之重，CSS Multi-Columns module同样能够为我们在网页上实现自适应的效果。下面有两种方法实现栏目的布局，值得一提的是这两种方法都采用了不同的属性（而且他们都需要有个干爹罩着-父级容器）。第一个方法就是直接指定，也就是说你直接指明需要在文本当中设置的栏目列数就行了。下面的代码能够产生三栏的文本，其宽度大小填满了父级的宽度。

div { column-count: 3; }

第二个方法比较灵活，首先栏目的宽度是固定的，而且其栏目的数目会一直增加直到填满父级宽度为止，举个例子吧，我设置栏目的宽度为140px，如果其父级宽度为800px的时候，那么这将会产生的栏目数为5个。

div { column-width: 140px; }

在默认的情况下，每个栏目之间的间隔长度是1em，但是你可以通过column-gap这个属性来进行改动。同样，你也可以在column-rule对column进行样式上的修改，我们可以回想到border这个属性也有着同样的写法规则。下面这个代码语句生成一个宽度为2px的虚线，而且column的间隔为28px-为大家展示了另一种的规则。

div {
column-gap: 28px;
column-rule: 2px dotted #ccc;
}

如果你想看看效果如何，狠狠点击 这里吧。对了，你需要在firefox，chrome，safari，opera11.1或者ie10的平台下才能得到正常的显示；如果你没有上面所说的浏览器，那你就看看下面的效果图片吧。

在一个水平空间上分割块状内容的时候css的columns属性为你提供了非常便捷的方法。

其实围绕着column你还可以做更多事情，但是文章篇幅有限，不能为你一一说明。如果你希望看到一个实际的例子，引用维基百科的一些例子这里可以满足你，在这里使用了column-count属性把文章分成了三栏，在火狐上multi-column的使用需要添加-moz-的前缀，在Chrome和Safari上则需要使用-webkit-前缀， opera11.1+以及ie10就不用添加前缀。

扩展阅读

——大漠

伸缩性盒模型（Flexible box）

Flexible Box Layout module（flexbox）为大家提供了一个在父级容器中不用考虑具体height和width数值的自适应方法。举个简单的例子来说吧，想象你有两个子级元素，你希望他们都能够以相同的宽度一起来填满他们的父级宽度。你也许能够使用百分比来实现，但是一旦要把border，padding，margins考虑进来的时候，情况就复杂多了。Flexbox的出现便让这个问题不再成为问题：

.parent { display: flex; }
.child-one, .child-two { flex: 1; }

简单地放置两个子级元素水平排列在父级容器当中，同时使其宽度一致。flex的数值实际上就是比例的意思，在这些子级元素当中按比例地重新分配空出来的空间在他们的宽度；好吧，多说没用，上代码！

.child-one { flex: 1; }
.child-two { flex: 2; }

当这两个子级元素的宽度都在父级容器中都得到分配的时候，.child-two的宽度将会以剩余空间的三分之二得到补充，.child-one的宽度将会以剩余空间的三分之一得到补充；所以，如果他们的父级为260px宽，每个栏目首先被赋予了100px宽度，多出来的60px将会有40px的宽度分配到child-one上，而20px的宽度将被分配到child-two上。

一例胜百言，点击在 这里,你会把这个知识点看的更加清楚（你需要firefox，chrome，safari，或者ie10+）.你还可以尝试改变浏览器窗口的大小来看看有什么变化。

正如能够动态改变一个容器的尺寸大小，FlexBox对父级容器提供属性支持控制多余的空间分配，也可以对该子级元素进行定位。justify-content属性作用在子级元素的宽度（这是默认情况下的，可以改变）.然后justify-content还有个兄弟属性，align-items，他作用在高度上，下面为你展示下，他们是如何实现效果的：

.parent {
justify-content: center;
align-items: center;
display: flex;
height: 200px;
width: 100px;
}
.child {
flex: 0;
height: 100px;
width: 100px;
}

.child的flex数值为0所以它不会有什么动态的尺寸变化，他的宽度高度都是父级容器的一半，因此，该子级元素将被定位在水平，垂直方向上的中心位置。

在.net杂志中一篇叫The CSS3 Flexible Box model explained的文章当中，你能了解更多关于Flexbox的东西。加上相关的前缀（-moz-.webkit-,-ms-）你能够在相应的firefox，chrome，safari，以及ie10pp各大浏览器平台中使用flexbox属性，在JS Polyfill, Flexie这个网站当中，你还能进行关于flexbox的尝试。我们要注意的是代码也是灵活多变的；点击这里你还能了解更多版本规范。

译文中的代码已做修改，有关于更多的信息查阅原文，或者阅读下面的扩展阅读。

扩展阅读

——大漠

网格(Grid)

Brand new to IE10PP）最值得称道的地方就是Grid Layout系统，这也是我最感到兴奋的地方。这是第一次使用columns和rows来定义我们的网格。其中我们可以使用宽度数值，关键词auto，以及一个新的长度单位，fr（fracion的缩写）。多说没用，翠花，上代码！

div {
display: grid;
grid-columns: 1fr 3fr 1fr;
grid-rows: 100px auto 12em;
}

上面的代码能够为我们带来一个三列的网格，其中最中间的栏目的宽度是左右两边栏目的三倍，第一行的高度为100px，最后一行的高度是12em，中间的行高自动调整，以刚好填满整个栏目的大小。

网格确定了之后，我们就能在里面定位其中的内容了，利用一些section 标签我创建了一个简单的页面布局，下面就是代码：

header {
grid-column: 1;
grid-column-span: 3;
grid-row: 1;
}
nav {
grid-column: 1;
grid-row: 2;
}
article {
grid-column: 2;
grid-row: 2;
}
aside {
grid-column: 3;
grid-row: 2;
}
footer {
grid-column: 1;
grid-column-span: 3;
grid-row: 3;
}

看着这些代码，你肯定会发现这些都采用了columns和rows，也就是grid-column和grid-row属性；在article的元素标签中，我把他放在了网格中的第二行，第二列，这个位置也就是在3*3网格的中心地带。同样的，我在header和footer标签当中使用了grid-column-span，这个代码让他们有了横跨三列栏目的勇气和能力，（grid-column-span也有着类似的功能，只是在这里就不引用了哈。）

我做过一个关于这些属性的布局例子，点 这里看看吧，但是这需要你用IE10PP这个平台来打开他。如果你没有这个浏览器，那你就看看下面的效果图吧。

这些属性都在IE10pp得到支持，因此你可以拿来自己试验试验，在技术文档中当中还有很多属性也是得到IE10PP支持的，所以说前景非常光明，敬请期待。

扩展阅读

——大漠

模板（Template）

另一个支持网格系统的就是Template Layout module。采用了不同的语法，第一步工作就是对position属性进行赋值，这些值就是按顺序排列下去的字母。上代码！

header { position: a; }
nav { position: b; }
article { position: c; }

我们搞定了这些posiiton工作之后，我们就可以通过这一连串的字母进行布局；每一串字母就代表着一行，每个字母就代表着一列；一例胜百言，弄一个一行三列的网格，你需要这么做，上代码！

div { display: 'abc'; }

这样，在一个水平行中你就可以显示出三个空间大小一样的元素了。同样，你可以重复字母，这样你就能够进行跨列显示了，如果你在不同字符串的相同位置使用相同的字母，那么你就能够进行跨行显示了，下面的例子就是说明了nav元素跨行显示，header，article跨列显示，上关键代码！

div {
display:
'baa'
'bcc';
}

Template Layout在目前为止没有被浏览器所支持，但是有个jQuery polyfill by Alexis Deveria能够让其得到支持。我就是依靠这个捣鼓出的这个例子,该效果跟Grid Layout的一模一样，然而其中的代码方法确实一点都不同。

这个例子运用了js所以他能够被绝大多数的现代浏览器所支持，但是你还是在浏览器看不到效果的话，那么你可以上拉回去看看介绍Grid Layout所贴出来的效果图参考参考，因为这效果图是一模一样的。同样，我记得我说过Grid Layout module博大精深？好吧，下面关于Template的语句中有包含其中的代码，不多说，上代码!

header { grid-cell: a; }
article { grid-cell: b; }
div {
display: grid;
grid-template: 'a' 'b';
}

上面的代码实现了跟Template layout属性 一样的效果，而且同样也有着不被广泛支持的命运，但我们都知道，明天肯定不会一成不变。

扩展阅读

——大漠

浮动定位

当前的float属性让我们的文本相对于一个元素向左或者向右浮动显示，但是在 IE10PP内的扩展属性,带着我们走得更远，我们可以定位浮动元素在我们想要的地方，而且其兄弟元素依然能够围绕在他们身旁。这需要float中的一个新的值，以及一些定位属性，上代码：

div {
float: positioned;
left: 200px;
position: absolute;
top: 100px;
width: 250px;
}

这段代码将会产生一个250px宽度的元素，而且这个元素的位置为距离父级容器最左边的200px处，以及最顶端的100px处。在默认情况下，其兄弟元素将会浮动在其的周围，但是你可以利用wrap-type属性进行改动，就好像下面的代码控制了文本只能在元素的上方和下方显示：

div { wrap-type: top-bottom; }

同样地，你可以把Position Float和Grid Layout module结合起来，在网格中确定元素的位置之后，安排其他元素在它周围显示，上代码：

div {
float: positioned;
grid-column: 2;
grid-row: 2;
}

Position Float是被IE10PP所支持的，所以你可以马上运用上他了，下面还有个demo，不过需要在IE10的平台下正常查看，如果你没有IE10平台，那么你就看看下面的效果图聊以自慰吧。

Floats and Positioning规范所能够做的确实比我在这里展示的多，更多的属性，包括shaped floats，或者image masks的floats；虽然说，目前为止，没什么浏览器支持这些东西，但是在各大浏览器下一个版本到来的时候，你一定会看到关于这方面的更多支持。

Exclusions

Positioned Floats在标签box-shaped的帮助下能够使得文本得以流动，不过我要说的是，shaped float可以在技术文档中查阅。这个想法来源于Adobe公司的一个模块：CSS Exclusions。在这个模块中有两个关键的属性；第一个就是wrap-float，它可以使得你创建椭圆，矩形，多边形，并以这些形式来进行浮动，上代码！

div { wrap-shape: circle(50%, 50%, 100px); }

这个代码能够产生一个半径为100px的圆，并且在父级容器的中心显示出来。你同样能够利用polygn（）来创建任何你想要的形状，用空格来显示一个组的纵，横坐标，一个三角形的代码如下显示：

div { wrap-shape: polygon(0,100px 100px,100px 50px,0); }

当你得到了你的形状的时候，你能够通过使用第二个属性wrap-shape-mode来使得内敛元素围绕显示在原来的元素当中，当然了这些内联元素需要和你的定位元素有共同的父级容器。上代码！

div {
wrap-shape: circle(50%, 50%, 100px);
wrap-shape-mode: around;
}

你可以通过下载来查看这个css的拓展功能，这个网站上有完整的技术说明，以及一些让人印象深刻的实例，其中一个的效果如下图所示。

正如上面所提到的，Exclusions语法已经被Floats模块接纳，所以很有可能在以后会以一个拓展的内容来展示给我们，而不是一个独立的新内容。

扩展阅读

1. CSS Floats and Positioning Level 3

——大漠

Regions

来自Adobe的一个更加凶猛的支持：CSS Regions，在一个多文件中提供一个自适应内容。在第一次的声明就确定了，在float属性中设定一些独特的字符串作为数值，然后在content属性中利用from（）功能中指定自适应的区域，说得有点乱七八糟，上代码：

.content { flow: foo; }
.target1, .target2 { content: from(foo); }

看代码，就相当简单，类名叫.content的内容，首先是放在类名叫.target1的元素中，如果内容溢出了，那么继续放在.target2中。为了清楚显示，所以在两个target元素中不会出现重复的内容，他开始于target1，如果有需要的话在target2中得到补充。一图胜百言，上图！

随便提一下，这两个target不需要在html文档中相互紧挨在一起；如果有需要的话，他们有可能在一个页面的两端显示。

然而，Regions这个用法还没有被浏览器所普遍支持，面对这种情况，你可以从Adobe Labs中下载这个属性 ，自己来尝试一下。

扩展阅读

——大漠

结论

FlexBox和Columns这两个内容，我也不敢确定在新的布局模块中被浏览器完全支持。我还要说的是，Positioned Floats 和 Exclusions 这两个模块非常接近，很大概率被合并。在IE10中Grid Layout则把Template Layout包含起来了。Regions 已经被webkit所支持了，因此很快地已经出现在webkit浏览器中（safari，Chrome）。

因此，我感觉一些语法上即将会发生改变，在这里你所看到的效果，即将出现在将来的CSS3效果当中。如果这成为现实，我想这绝对是个好情况；这些新的方法将会是个对CSS3很好的补充和完善，在数年之后，我们即使创建一个复杂的网站都是非常简单轻松的了。

感谢Oli Studholme对这篇文章的专业评价

一篇类似的，关于css布局且具有前瞻性的　文章。

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

如需转载烦请注明出处：

英文原文：http://www.netmagazine.com/features/future-css-layouts

中文译文：http://www.w3cplus.com/css3/future-css-layouts.html

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

Caption Hover Effects

A tutorial on how to create some subtle and modern caption hover effects.

View demo Download source

Today we want to show you how to create some simple, yet stylish hover effects for image captions. The idea is to have a grid of figures and apply a hover effect to the items which will reveal a caption with the title, author and a link button. For some of the effects we will use 3D transforms. The aim is to keep the effects subtle and provide inspiration for many different variations.

Please note: this only works as intended in browsers that support the respective CSS properties.

The images used in the demos are Dribbble shots by talented Jacob Cummings.

Let’s get started.

The Markup

The structure of our grid and the figures will be made of an unordered list and each item will contain a figure element. The figure will contain an image and a figcaption with some text elements and a link:

<ul class="grid cs-style-1">
<li>
<figure>
<img src="images/1.png" alt="img01">
<figcaption>
<h3>Camera</h3>
<span>Jacob Cummings</span>
<a href="http://dribbble.com/shots/1115632-Camera">Take a look</a>
</figcaption>
</figure>
</li>
<li>
<figure>
<!-- ... -->
</figure>
</li>
<!-- ... -->
</ul>

This is the default structure for all the grid examples. Note that for effect 4 we will have an additonal division wrapping the image.
The class for each single effect will be added to the list; so example 1 will have “cs-style-1″, example 2 will have “cs-style-2″ and so on. That’s how we will define the effect styles for each single example.

But first let’s define the common styles for all effects.

The CSS

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

The common styles for all the figures is the following. First, we’ll define the styles for the grid and the list items that will serve as the containers of our figures:

.grid {
padding: 20px 20px 100px 20px;
max-width: 1300px;
margin: 0 auto;
list-style: none;
text-align: center;
}

.grid li {
display: inline-block;
width: 440px;
margin: 0;
padding: 20px;
text-align: left;
position: relative;
}

Making the list items display as inline-blocks will allow us to center them be applying a centerd text-align to the parent.

Let’s reset the margins of the figure elements and set the position to relative. Our figcaption will be positioned absolutely, so we need to make sure it will do so inside of the figure:

.grid figure {
margin: 0;
position: relative;
}

The image will have a maximum width of 100% which will come in handy when we define a media query to resize the list items:

.grid figure img {
max-width: 100%;
display: block;
position: relative;
}

The figcaption will be positioned absolutely. By default it will be positioned in the top left corner. We won’t define any width or height here as we will do so in all the individual styles:

.grid figcaption {
position: absolute;
top: 0;
left: 0;
padding: 20px;
background: #2c3f52;
color: #ed4e6e;
}

And finally, let’s define some styles for the text elements and the link:

.grid figcaption h3 {
margin: 0;
padding: 0;
color: #fff;
}

.grid figcaption span:before {
content: 'by ';
}

.grid figcaption a {
text-align: center;
padding: 5px 10px;
border-radius: 2px;
display: inline-block;
background: #ed4e6e;
color: #fff;
}

We’ll add the “by” for the span that contains the author name using the pseudo-class :before. Of course you can add that in the HTML, but this will give you the freedom to change it easily into something like “made by” or “Designer: ” or similar. Be careful not to remove meaning from your HTML, though, by doing something like this.

In the end of our CSS we will also add a media query for smaller screens:

@media screen and (max-width: 31.5em) {
.grid {
padding: 10px 10px 100px 10px;
}
.grid li {
width: 100%;
min-width: 300px;
}
}

And now let’s start by doing some nice effects.

Note that we will use Modernizr to detect touch. But be aware that this is not 100% bulletproof for testing if you are on a touch device as pointed out here. We will replace the hover for the touch and add a class that will trigger the effects when we have detected touch. So you will always see another rule for that in addition to the :hover. We only want the hover to trigger when we don’t detect touch.

Effect 1

Let’s start with a very simple effect. We want the caption to fade in and move a bit to the right and down, creating the illusion of a 3D layer that comes out of the image.

For that we first need to set the width and height of the figcaption and set the initial opacity to 0:

.cs-style-1 figcaption {
height: 100%;
width: 100%;
opacity: 0;
text-align: center;
backface-visibility: hidden;
transition: transform 0.3s, opacity 0.3s;
}

We also add a transition and set the backface-visibility to hidden to avoid a jump in the text rendering in the end of the transition. You don’t have to use that if you don’t mind the little glitch.

On hover (or on touch) we will set the opacity to 1 and translate the figcaption a bit:

.no-touch .cs-style-1 figure:hover figcaption,
.cs-style-1 figure.cs-hover figcaption {
opacity: 1;
transform: translate(15px, 15px);
}

Additionally, we will position the text elements:

.cs-style-1 figcaption h3 {
margin-top: 70px;
}

.cs-style-1 figcaption span {
display: block;
}

.cs-style-1 figcaption a {
margin-top: 30px;
}

Effect 2

This effect will move the image up and reveal the figcaption just like you can see on Minimamente from which it got inspired by.

So let’s add a transition for the transform to the image and make it move up on hover:

.cs-style-2 figure img {
z-index: 10;
transition: transform 0.4s;
}

.no-touch .cs-style-2 figure:hover img,
.cs-style-2 figure.cs-hover img {
transform: translateY(-90px);
}

We’ve set the z-index to 10, so that the image stays on top of the caption.

The figcaption needs a fixed height and a width of 100%. We’ll stick it to the bottom of the figure:

.cs-style-2 figcaption {
height: 90px;
width: 100%;
top: auto;
bottom: 0;
}

Let’s also position the link button on the right side:

.cs-style-2 figcaption a {
position: absolute;
right: 20px;
top: 30px;
}

Effect 3

A different approach to effect 2 is to hide any overflow when moving the image. Let’s do that and make it appear as if the caption is slightly pushing the image up.

First, we need to set the overflow of the figure to hidden. Like this we won’t see anything that spills out when moving around:

.cs-style-3 figure {
overflow: hidden;
}

The image needs a transition for the transform and on hover we will translate it 50px up:

.cs-style-3 figure img {
transition: transform 0.4s;
}

.no-touch .cs-style-3 figure:hover img,
.cs-style-3 figure.cs-hover img {
transform: translateY(-50px);
}

The figcaption will be a bit higher than in the previous example and we will translate it out of the view of the figure. Let’s also add a transition for the transform and the opacity:

.cs-style-3 figcaption {
height: 100px;
width: 100%;
top: auto;
bottom: 0;
opacity: 0;
transform: translateY(100%);
transition: transform 0.4s, opacity 0.1s 0.3s;
}

On hover we’ll set to opacity to 1 and translate it up. See how we have added two transitions? One for the normal state and one for the hover? This is how we can control what happens when we hover and when we hover out. The transition here will be applied on hover: we want the element to become opaque quickly while taking 0.4 seconds for the transform. When we hover out, the opacity will be set again to 0 but only after a delay of 0.3 seconds. This will make the effect look consistent and natural.

.no-touch .cs-style-3 figure:hover figcaption,
.cs-style-3 figure.cs-hover figcaption {
opacity: 1;
transform: translateY(0px);
transition: transform 0.4s, opacity 0.1s;
}

Let’s not forget about our link button:

.cs-style-3 figcaption a {
position: absolute;
bottom: 20px;
right: 20px;
}

Effect 4

The forth example will make use of some 3D goodness. The aim is to flip the caption from the left side and push the image to the right.

We will use the list item as a perspective container so that we can play around with 3D transforms:

The CSS

.cs-style-4 li {
perspective: 1700px;
perspective-origin: 0 50%;
}

The child needs to have the following transform-style if we want the 3D transforms to work in the other elements:

.cs-style-4 figure {
transform-style: preserve-3d;
}

As mentioned earlier, this example is going to have another wrapper for the image, Why do we need this? Well, we need to set the image’s parent to overflow hidden, because we don’t want to see the image spilling out of the container when we move it. We could set the overflow of the figure to hidden but then we won’t see the beautiful 3D effect of the caption. So, let’s add another wrapper and set it to overflow hidden instead:

.cs-style-4 figure > div {
overflow: hidden;
}

Let’s move the image on hover:

.cs-style-4 figure img {
transition: transform 0.4s;
}

.no-touch .cs-style-4 figure:hover img,
.cs-style-4 figure.cs-hover img {
transform: translateX(25%);
}

The figcaption will have half of the width of the figure and we’ll set its initial opacity to 0. Now, let’s rotate it 90 degrees on the Y-axis which will make it be flipped towards us with the origin on its left side. We would basically not see it like that. Let’s set a transition for the “hover out” which will work in the same principle like described in the previous example:

.cs-style-4 figcaption {
height: 100%;
width: 50%;
opacity: 0;
backface-visibility: hidden;
transform-origin: 0 0;
transform: rotateY(-90deg);
transition: transform 0.4s, opacity 0.1s 0.3s;
}

On hover we will fade it in and rotate it to 0 degrees, making it flip like a page of a book from the left side:

.no-touch .cs-style-4 figure:hover figcaption,
.cs-style-4 figure.cs-hover figcaption {
opacity: 1;
transform: rotateY(0deg);
transition: transform 0.4s, opacity 0.1s;
}

Last, but not least, our little link button:

.cs-style-4 figcaption a {
position: absolute;
bottom: 20px;
right: 20px;
}

Effect 5

This effect will make the image shrink and scale the caption in from the back.

Let’s put the image on top of the caption and add a transition for the transform:

.cs-style-5 figure img {
z-index: 10;
transition: transform 0.4s;
}

On hover, we want to scale the image down:

.no-touch .cs-style-5 figure:hover img,
.cs-style-5 figure.cs-hover img {
transform: scale(0.4);
}

The caption will initially scaled to 0.7 and faded out:

.cs-style-5 figcaption {
height: 100%;
width: 100%;
opacity: 0;
transform: scale(0.7);
backface-visibility: hidden;
transition: transform 0.4s, opacity 0.4s;
}

On hover, we will scale it up and fade it in:

.no-touch .cs-style-5 figure:hover figcaption,
.cs-style-5 figure.cs-hover figcaption {
transform: scale(1);
opacity: 1;
}

Super-easy. Oh, and of course, the little link button wants to be in the bottom right corner:

.cs-style-5 figure a {
position: absolute;
bottom: 20px;
right: 20px;
}

Effect 6

This effect is a variation of effect 5. There are many possibilities to play around with this type of effect, think about positioning the image in a different place and showing some more text. This effect will position the text and the image in a different place than before and we will not fade the caption in or scale it, it will already be there, creating a different “environment”.

So, let’s again do the same thing for the image, just that on hover we will also translate it up a bit:

.cs-style-6 figure img {
z-index: 10;
transition: transform 0.4s;
}

.no-touch .cs-style-6 figure:hover img,
.cs-style-6 figure.cs-hover img {
transform: translateY(-50px) scale(0.5);
}

So, no transition for the caption this time:

.cs-style-6 figcaption {
height: 100%;
width: 100%;
}

And let’s position the text elements:

.cs-style-6 figcaption h3 {
margin-top: 60%;
}

.cs-style-6 figcaption a {
position: absolute;
bottom: 20px;
right: 20px;
}

Effect 7

The last effect in this tutorial will “grow” the caption from behind the image, making it look like a frame.

Since the frame of the first elements will be overlapping the other list items, we have to make sure that the z-indexes are correct (reversed):

.cs-style-7 li:first-child { z-index: 6; }
.cs-style-7 li:nth-child(2) { z-index: 5; }
.cs-style-7 li:nth-child(3) { z-index: 4; }
.cs-style-7 li:nth-child(4) { z-index: 3; }
.cs-style-7 li:nth-child(5) { z-index: 2; }
.cs-style-7 li:nth-child(6) { z-index: 1; }

Just like in the previous examples, we want the image to be on top of the caption:

.cs-style-7 figure img {
z-index: 10;
}

The caption will be 100% of the figure and we’ll set the transition for the opacity, height and box-shadow. Why the box shadow? We can easily use the box shadow to create a frame around the caption:

.cs-style-7 figcaption {
height: 100%;
width: 100%;
opacity: 0;
backface-visibility: hidden;
box-shadow: 0 0 0 0px #2c3f52;
transition: opacity 0.3s, height 0.3s, box-shadow 0.3s;
}

On hover we will set the opacity to 1, increase the height and set the box shadow’s spread to 10 pixels:

.no-touch .cs-style-7 figure:hover figcaption,
.cs-style-7 figure.cs-hover figcaption {
opacity: 1;
height: 130%;
box-shadow: 0 0 0 10px #2c3f52;
}

Let’s position the text elements. We want the elements to appear just after we animated the caption’s height but when we “hover out”, we want them to disappear immediately. So we’ll set the transition-duration to 0 seconds for the normal state.

.cs-style-7 figcaption h3 {
margin-top: 86%;
}

.cs-style-7 figcaption h3,
.cs-style-7 figcaption span,
.cs-style-7 figcaption a {
opacity: 0;
transition: opacity 0s;
}

.cs-style-7 figcaption a {
position: absolute;
bottom: 20px;
right: 20px;
}

On hover we will make all elements appear with a delay:

.no-touch .cs-style-7 figure:hover figcaption h3,
.no-touch .cs-style-7 figure:hover figcaption span,
.no-touch .cs-style-7 figure:hover figcaption a,
.cs-style-7 figure.cs-hover figcaption h3,
.cs-style-7 figure.cs-hover figcaption span,
.cs-style-7 figure.cs-hover figcaption a {
transition: opacity 0.3s 0.2s;
opacity: 1;
}

And that’s it! I hope you enjoyed this tutorial and got inspired to create many cool caption hover effects.

View demo Download source

原文链接：http://tympanus.net/codrops/2013/06/18/caption-hover-effects/ （本内容由互联网资料整理而成）

Apple Mac Pro page deconstructed

The Apple Worldwide Developers Conference (WWDC) held in San Francisco earlier this week introduced a few new Apple products and updates.

While the hugely expected iPhone 6 Nano with super narrow display hasn’t been revealed yet, the new iOS 7 caused a huge debate around the “flat” icons and updated UI design.

What stood out for me was the new Apple Mac Pro with its futuristic black design and a power house configuration. This futuristic product is also showcasing its features on a great looking website at www.apple.com/mac-pro/ which is full of interesting effects.

To better understand what is happening on the page, have a look at the simplified html page structure below.

View HTML Deconstruction

Now lets have a look at how some of the fancy effects were created.

Introduction video sequence

There are two video files used on the page:

- A short 4 second (1.4MB) intro and

- A 49 second (19.5MB) main video clip

<!-- On Page Load -->
<div id="introcontainer">

<video src="macpro_intro_desktop.mp4"></video>

</div>
<div id="videocontainer"></div>

<!-- After Intro Playback -->
<div id="introcontainer" style="display: none;">

<video src="macpro_intro_desktop.mp4"></video>

</div>
<div id="videocontainer" style="display: block;">

<video src="macpro_main_desktop.mp4"></video>

</div>

The intro clip <video src="macpro_intro_desktop.mp4"> in the div#introcontainer is loaded first. After it finishes playing the <video src="macpro_main_desktop.mp4"> tag is injected into div#videocontainer which is then set to display: block, while the div#introcontainer is set to display: none.

div#introcontainer has a higher z-index and the last frame of the intro video is also the first frame of the main one, that means that you don’t see any transition.

Scrolling down

When you scroll down the page the main nav#globalheader fades out and moves up, thanks to -webkit-transform: translate3d(0, -20px, 0);.

<!-- Nav on page load -->
<div id="navcontainer">

<nav id="globalheader" class="visible" style="opacity: 1; -webkit-transform: translate3d(0, 0px, 0);">
...
</nav>

</div>

<!-- Nav after scroll down -->
<div id="navcontainer">

<nav id="globalheader" class="" style="opacity: 0; -webkit-transform: translate3d(0, -20px, 0);">
...
</nav>

</div>

Selecting one of the sections in the side-navigation bar plays the video forwards or backwards to the appropriate time point. This is based on the data-seek-time attribute of the clicked li.

<ol class="list">
<li data-seek-index="1" data-seek-time="2" class="active">...</li>
</ol>

The main navigation then fades in on the last “Later This Year” panel. Thanks to opacity set to almost 1 and visibility set to visible.

element.style {
opacity: 0.9999999999999956;
-webkit-transform: translate3d(0, 0px, 0);
}
#desktop .clip.visible {
visibility: visible;
}

Fade Out effect between panels

If you use the section navigation on the right side and jump further than the next or previous section, you will see a nice fade out and fade in effect. This is thanks to div#curtain.

All direct child elements of #wrapper are positioned absolute on top of each other and their individual z-index values take care of the visual order.

Curtain hidden HTML/CSS

<div id="wrapper">
<div id="navcontainer">...</div>
<div id="introcontainer">...</div>
<div id="videocontainer">...</div>
<div id="stillcontainer">...</div>
<div id="panelcontainer">...</div>
<div id="curtain"></div>
</div>

#curtain {
height: 100%;
width: 100%;
background: #000;
position: absolute;
z-index: 30;
opacity: 0;
-webkit-transition: opacity 0.6s ease-out;
-moz-transition: opacity 0.6s ease-out;
transition: opacity 0.6s ease-out;
}

Curtain visible HTML/CSS

<div id="curtain" style="display: block" class="fadeOut"></div>

#curtain.fadeOut {
z-index: 10000;
opacity: 1;
}

On navigation click the div#curtain is set to display:block and gets an additional class fadeOut. This class is then removed when the video in the background rewinds to the appropriate time, and a still image of that time point is displayed on top of the video.

These assets are shown in the overview image as two images in #stillcontainer with the class still still_1 clip. The current section image has an additional class of visible crossFade.

There are a total of 13 video overlay images img.still.clip, with a few section sharing the same image.

If you are still having trouble understanding the structure of the page layers, have a look at a more visual demonstration below.

View HTML Deconstruction

Conclusion

I hope that this deconstruction answers some of your questions about how the Apple Mac Pro page was built.

As always, feel free to leave a comment or ask any questions below.

Enjoy responsibly.

原文链接：http://ihatetomatoes.net/apple-mac-pro-page-deconstructed （本内容由互联网资料整理而成）

Making Infield Form Labels Suck Less

Let me start off by saying you really shouldn’t put form labels—or even placeholder text—inside of form fields if you want to be safe. But we can’t always play it safe. Sometimes putting labels inside of form fields is the best option we’ve got. Jeremy Fields, Steve Schoeffel, and I found ourselves making that decision on a recent project, and we set out to make the best of a tricky usability situation.

Why Shouldn’t I Put Labels Inside Of Form Fields?

There are a number of usability issues with putting labels inside of form fields especially if they’re not implemented well. From a usability perspective, we see:

- Text inside the field can get mixed with user input if it’s not removed from the field.

- It turns out that many users won’t enter text into a field, if they see text inside of it.

- The purpose of the field is obscured when the label is removed, forcing the user to rely on short-term memory to remember what they need to enter.

If—like we did—you’ve found that infield form labels are your best option given the project requirements, there are some ways to mitigate these usability issues. UX Movement has a good checklist:

- Group related fields (e.g. addresses, credit card information)

- Clearly differentiate labels from user input

- Provide good visual feedback

We made sure to address each of these, but weren’t completely happy with the result. In particular, we thought we could do more to help users recall the purpose of each field once the field was active and text was being entered.

Fixing Infield Form Label Visibility

The simplest solution to the problem of disappearing form labels is to make sure they don’t actually disappear once the form field is active. But if you’re going to keep the field labels around, you need to figure out where to put them. We played with several approaches, weighing the pros and cons of each.

Labels slide outside of the fields

Pros:

- Labels are visually consistent inside and outside of the form field.

Cons:

- Only really works when you can move labels in a direction where they won’t end up inside another form field. This generally limits you to moving the labels to the left or right of the form field.

Example:

Labels appear next to fields as tooltips

Pros:

- Reuses a common design pattern (tooltips) to present form labels so that labels are visually distinct from other form elements.

Cons:

- Can obscure adjacent form fields and other form elements depending on where you place the tooltip. Keeping the tooltips small can minimize this problem.

A note on positioning your field label: If your solution relies on moving the field label outside of the input, make sure there’s somewhere for it to go. On small screens a solution that moves labels to the left or right could end up positioning the label outside the browser’s viewport.

Example:

Swap label position from left to right (or right to left)

Pros:

- Keeps the label inside the field and doesn’t obscure any other form fields or form elements.

Cons:

- While it avoids other form elements, the label can get in the way of user input. In particular, there’s nowhere for the label to go in a short field (e.g. ZIP code) without overlapping user input.

Example:

Our Solution

We ended up using the tooltip approach, placing labels above their input once the input has focus. We liked this approach because the active input labels are clearly distinct from other form elements, and the same approach can be used when the design scales down to smaller screens. We’d prefer not to obscure the form elements above the active input, but this approach is all about compromises.

Interested in how we implemented this solution? Jeremy has a great writeup of the details.

原文链接：http://viget.com/inspire/making-infield-form-labels-suck-less （本内容由互联网资料整理而成）

Making Infield Form Labels Suck Less II

Hopefully you’ve already read Jackson Fox’s post on Making Infield Form Labels Suck Less from a UX perspective. If you haven’t, I recommend that you check it out before reading my thoughts from the front-end development perspective.

Can't wait to check out the code? Head down to the jsFiddle at the end of the post.

So often in web design and development, things that are easy to implement aren’t appropriately examined. In this case, placing the label for a text field within the field is a common practice to make form layouts more compact. The implications of that choice create interaction and technical challenges that need to be considered carefully.

Since Jackson covered usability issues with this approach, I want to discuss some of the technical and accessibility considerations. Trevor covered this a few years ago, and while the browser landscape has changed quite a bit, it’s still a good read on the subject. My issue with the popular techniques is more semantic than technical. There are a bunch of ways to get text into a text field to serve as a label, but most of these techniques only solve it visually. Let’s take a look at the two most popular.

Value Attribute

One of the most popular implementations of this pattern is to use the value attribute of the text field for the label. JavaScript is then used to remove the value when the field is either focused or typing begins. This method is full of issues, including:

- When JavaScript fails or is unavailable, the interaction breaks. Either the value isn’t set at all leaving no label (worse) or the user has to remove the label before they can enter their information (annoying) and the label is gone forever if they forget what the field is for.

- Extra care must be taken by the developer to ensure that values for fields not filled in by the user aren't sent along to the server when the form is submitted.

The most problematic part of this method, though, is that the value attribute does not provide proper accessibility for users navigating with a keyboard or screen reader. According to WebAIM’s article on Creating Accessible Forms:

When a screen reader accesses a form item that has a <label> element associated with it, it will read the text within the <label> element and indicate the type of form item it is (e.g., "First Name. Text box" or "Age. Check box").

Using anything other than a <label> creates extra work, at best, and confusion, at worst, for users that have vision or mobility impairments.

Placeholder Attribute

The HTML5 placeholder attribute seems to be the perfect native solution to the problem. According to caniuse.com, the placeholder now has over 68% support among browsers. That makes it a much more viable option than when Trevor wrote his article. The problem with the placeholder is that it’s not an alternative to the label. The W3C puts it very bluntly:

The placeholder attribute should not be used as an alternative to a label.

This issue is described in great detail by Roger Johansson on his blog 456 Berea St.

The placeholder is also an accessibility can of worms. From low visual contrast to no reference once a field has been focused or filled in, placeholders have lots of issues.

Solution

To solve this problem and make the infield label pattern suck a little less, Jackson and I came up with a list of requirements:

- The label needed to be visible while the user was filling out that field.

- The placement of the label needed to work within the layout of the form and page.

- It had to use the <label> tag to ensure good accessibility and semantics.

- It had to be useable if JavaScript is not available.

What we came up with wasn’t revolutionary. A lot of smart people have headed in this direction before. Instead, our solution was an iteration toward a cleaner and less obtrusive implementation.

The Code

The JavaScript is in the form of a jQuery plugin so it can be easily dropped into any project and bound to any text inputs currently on the page or if they're added to the DOM later. The goal was to keep it very simple and leverage the native events provided by the browser.

For example, when a <label> is correctly set up with a for attribute that matches the id attribute on an input field, clicking on the label will automatically bring focus to the input. Because of that, the focus and blur events on the input only need to be bound.

For the CSS, a .js class is being set on the <html> or <body> to determine if JavaScript is available. Using that class, the <label> is positioned on top of the input if JavaScript is available or above as a fallback if it isn't.

Play around with the jsFiddle below or head over to GitHub and download the code.

原文链接：http://viget.com/inspire/making-infield-form-labels-suck-less-2 （本内容由互联网资料整理而成）

Native JavaScript Equivalents of jQuery Methods: CSS and Animation

Do You Really Need jQuery? Sometimes — especially if you want to support IE6/7/8 using jQuery 1.x. However, modern browser APIs now provide much of the functionality we take for granted in jQuery. In this article, we’re going to look at methods related to CSS.

Class Manipulation

One of the most common jQuery tasks is applying a class to a specific element:

$("#myelement").addClass("myclass");

We can achieve the same thing in native JavaScript:

document.getElementById("myelement").className = "myclass";

This isn’t quite the whole story:

1. jQuery can apply the class to any number of nodes.

2. jQuery appends the new class to existing class definitions, but the native example will overwrite them.

In native JavaScript, the className property is simply a string. We therefore need a function to replicate how jQuery works, e.g.

function addClass(node, class) {
if (!node.length) node = [node];
for (var n = 0, m = node.length; n < m; n++) {
if ((" " + node[n].className + " ").indexOf(" "+class+" ") >= 0) {
node.className += " " + class;
}
}
}
// apply myclass to all nodes
addClass(document.getElementById("myelement"), "myclass");

While this code is smaller and faster than jQuery, we’re replicating what’s already available in the library — there’s little point.

Fortunately, modern browsers now offer a new classList property which implements a DOMTokenList — an array-like collection of all classes applied to a node. The following properties are available:

- length — the number of class names applied

- item(index) — the class name at a specific index

- contains(class) — returns true if a node has that class applied

- add(class) — applies a new class to the node

- remove(class) — removes a class from the node

- toggle(class) — removes or adds a class if it’s applied or not applied respectively

We can use this in preference to the clunkier className property:

document.getElementById("myelement").classList.add("myclass");

classList is supported by most browsers except IE9. Fortunately, a couple of shims are available which could be conditionally loaded in that browser.

Style Manipulation

jQuery provides a number of methods to apply specific styles, e.g.

$("#myelement").css({
color: "#c00",
backgroundColor: "#eee",
width: "200px",
height: "100px",
borderColor: "#f00"
});

The native equivalent:

var m = document.getElementById("myelement"), c = m.style;
c.color = "#c00";
c.backgroundColor = "#eee";
c.width = "200px";
c.height = "100px";
c.borderColor = "#f00";

Over 10,000 iterations using cached selectors, the jQuery code executed in 6,670ms. Native JavaScript took 330ms — it was 20x faster.

Of course, you shouldn’t use either unless a value needs to be calculated in some way. It’s more efficient to define a class of styles in CSS then apply its name to the element.

Animation

jQuery offers various animated effects out of the box including sliding and fading. Native JavaScript can be faster but none of that matters: CSS3 animation trounces both.

I was initially skeptical about CSS3 animation. It can never offer fine-grained control (such as stopping an animation after N frames) and trespasses on JavaScript’s behavioral responsibilities. However, the benefits more than outweigh the drawbacks:

1. CSS3 animation is handled by the browser; it will always be faster than JavaScript execution.

2. CSS3 animation is easier to use and requires significantly less code.

3. CSS3 offers effects such as 3D transformations which would be impractical — if not impossible — in JavaScript alone.

IE9 and below won’t show the effects but they can degrade gracefully and IE10 should be the dominant version within a few months.

The CSS3 genie will never go back in the lamp. If you’re still using jQuery or JavaScript for DOM animation in modern browsers, you’re probably wasting your time.

That said, JavaScript can be used to react to CSS3 animations when they start, stop or proceed to the next iteration using animationstart, animationend and animationiteration accordingly. For more information, refer to How to Capture CSS3 Animation Events in JavaScript.

In my next article, we’ll finish the series by looking at events, Ajax and utility functions.

Series Navigation
Tagged as: animation, CSS, CSS3, HTML5 Dev Center, javascript, jQuery

原文链接：http://www.sitepoint.com/jquery-vs-raw-javascript-2-css3-animation/ （本内容由互联网资料整理而成）

Adventures in Jank Busting: Parallax, performance, and the new Flickr Home Page

tl;dr version: transform3d() is your friend, but use sparingly. Chrome Dev Tools are awesome.

What’s old is new again: Stealing from the arcade

Back in 1985, games like Super Mario Bros. popularized the effect of horizontal parallax scrolling – a technique wherein the background moves at a slower speed relative to the foreground, giving the impression of depth. In 2013, the web is seeing a trend of vertical parallax effects as developers look to make pages feel more interactive and responsive. Your author’s $0.25, for the record, is that we’ll continue to see arcade and demoscene-era effects being ported over to the mainstream web in creative ways as client-side performance improves.

While the effect can be aesthetically pleasing when executed correctly, parallax motion tends to be expensive to render – and when performance is lacking, the user’s impression of your site may follow suit.

Vertical parallaxing is pretty straightforward in behaviour: For every Y pixels of vertical axis scrolling, move an absolutely-positioned image in the same direction at scale. There are some additional considerations for the offset of the element on the page and how far it can move, but the implementation remains quite simple.

The following are some findings made while working on Flickr’s redesigned signed-out homepage at flickr.com/new, specifically related to rendering and scrolling performance.

Events and DOM performance

To optimize performance in the browser environment, it’s important to consider the expensive parts of DOM “I/O”. You ideally want a minimal amount of both, particularly since this is work being done during scrolling. Executing JavaScript on scroll is one of the worst ways to interrupt the browser, typically because it’s done to introduce reflow/layout and painting – thus, denying the browser the chance to use GPU/hardware-accelerated scrolling. window.onscroll() can also fire very rapidly on desktops, making way for a veritable flood of expensive scroll → reflow → paint operations if your “paths” are not fast.

A typical parallax implementation will hook into window.onscroll(), and will update the backgroundPosition or marginTop of an element with a background image attached in order to make it move. An <img> could be used here, but backgrounds are convenient because they allow for positioning in relative units, tiling and so on.

A minimal parallax example, just the script portion:

window.onscroll = function(e) {

var parallax = document.getElementById('parallax-background');

parallax.style.marginTop = (window.scrollY/2) + 'px';

}

This could work for a single element, but quickly breaks down if multiple elements are to be updated. In any case, references to the DOM should be cached for faster look-ups; reading window.scrollY and other DOM attributes can be expensive due to potential to cause layout/reflow themselves, and thus should also be stored in a local variable for each onscroll() event to minimize thrashing.

An additional performance consideration: Should all parallax elements always be moved, even those which are outside of the viewport? Quick tests suggested savings were negligible in this case at best. Even if the additional work to determine in-view elements were free, moving only one element did not notably improve performance relative to moving only three at a time. It appears that Webkit’s rendering engine is smart about this, as the only expensive operations seen here involve painting things within the viewport.

In any event, using marginTop or backgroundPosition alone will not perform well as neither take advantage of hardware-accelerated compositing.

And now, VOIDH (Video Or It Didn’t Happen) of marginTop-based parallax performing terribly:

Look at that: Terrible. Jank city! You can try it for yourself in your browser of choice, via via ?notransform=1.

Enter the GPU: Hardware Acceleration To The Rescue

Despite caching our DOM references and scroll properties, the cost of drawing all these pixels in software is very high. The trick to performance here is to have the GPU (hardware) take on the job of accelerating the compositing of the expensive bits, which can be done much faster than in software rendering.

Elements can be promoted to a “layer” in rendering terms, via CSS transforms like translate3d(). When this and other translateZ()-style properties are applied, the element will then be composited by the GPU, avoiding expensive repaints. In this case, we are interested in having fast-moving parallax backgrounds. Thus, translate3d() can be applied directly to the parallax element.

window.onscroll = function(e) {

// note: most browsers presently use prefixes: webkitTransform, mozTransform etc.

var parallax = document.getElementById('parallax-background');

parallax.style.transform = 'translate3d(0px,' + (window.scrollY/2) + 'px, 0px)';

}

In webkit-based browsers like Safari and Chrome, the results speak for themselves.

Look, ma! Way less jank! The performance here is comparable to the same page with parallax disabled (i.e., regular browser scrolling/drawing.)

GPU acceleration sounds like a magic bullet, but it comes at the cost of both video memory and cache. If you create too many layers, you may see rendering problems and even degraded performance – so use them selectively.

It’s also worth noting that browser-based hardware acceleration and performance rests on having agreement between the browser, drivers, OS, and hardware. Firefox might be sluggish on one machine, and butter-smooth on another. High-density vs. standard-resolution screens make a big difference in paint cost. All GPUs are made equal, but some GPUs are made more equal than others. The videos and screenshots for this post were made on my work laptop, which may perform quite differently than your hardware. Ultimately, you need to test your work on a variety of devices to see what real-world performance is like – and this is where Chrome’s dev tools come in handy.

Debugging Render Performance

In brief, Chrome’s Developer Tools are awesome. Chrome Canary typically has the freshest features in regards to profiling, and Safari also has many of the same. The features most of interest to this entry are the Timeline → Frames view, and the gear icon’s “Show Paint rectangles” and “Show composited layer borders” options.

Timeline → Frames view: Helpful in identifying expensive painting operations.

Paint rectangles + composited layer borders, AKA “Plaid mode.” Visually identify layers.

Timeline → Frames view

Timeline’s “Frames” view allows you to see how much time is spent calculating and drawing each frame during runtime, which gives a good idea of rendering performance. To maintain a refresh rate of 60 frames per second, each frame must take no longer than 16 milliseconds to draw. If you have JS doing expensive things during scroll events, this can be particularly challenging.

Expensive frames in Flickr’s case stem primarily from occasional decoding of JPEGs and non-cached image resizes, and more frequently, compositing and painting. The less of each that your page requires, the better.

Paint rectangles

It is interesting to see what content is being painted (and re-painted) by the browser, particularly during scroll events. Enabling paint rectangles in Chrome’s dev tools results in red highlights on paint areas. In the ideal case when scrolling, you should see red only around the scrollbar area; in the best scenario, the browser is able to efficiently move the rest of the HTML content in hardware-accelerated fashion, effectively sliding it vertically on the screen without having to perform expensive paint operations. Script-based DOM updates, CSS :hover and transition effects can all cause painting to happen when scrolling, so keep these things in mind as well.

Composited layer borders

As mentioned previously, layers are elements that have been promoted and are to be composited by the GPU, via CSS properties like translate3d(), translateZ() and so on. With layer borders enabled, you can get a visual representation of promoted elements and review whether your CSS is too broad or too specific in creating these layers. The browser itself may also create additional layers based on a number of scenarios such as the presence of child elements, siblings, or elements that overlap an existing layer.

Composited borders are shown in brown. Cyan borders indicate a tile, which combines with other tiles to form a larger composited layer.

Other notes

Image rendering costs

When using parallax effects, “full-bleed” images that cover the entire page width are also popular. One approach is to simply use a large centered background image for all clients, regardless of screen size; alternately, a responsive @media query-style approach can be taken where separate images are cut to fit within common screen widths like 1024, 1280, 1600, 2048 etc. In some cases, however, the single-size approach can work quite nicely.

In the case of the Flickr homepage, the performance cost in using 2048-pixel-wide background images for all screens seemed to be negligible – even in spite of “wasted” pixels for those browsing at 1024×768. The approach we took uses clip-friendly content, typically a centered “hero” element with shading and color that extends to the far edges. Using this approach, the images are quite width-agnostic. The hero-style images also compress quite nicely as JPEGs thanks to their soft gradients and lighting; as one example, we got a 2048×950-pixel image of a flower down to 68 KB with little effort.

Bandwidth aside, the 2048-pixel-wide images clip nicely on screens down to 1024 pixels in width and with no obvious flaws. However, Chrome’s dev tools also show that there are costs associated with decoding, compositing, re-sizing and painting images which should be considered.

Testing on my work laptop*, “Image resized (non-cached)” is occasionally shown in Chrome’s timeline → frames view after an Image Decode (JPEG) operation – both of which appear to be expensive, contributing to a frame that took 60 msec in one case. It appears that this happens the first time a large parallax image is scrolled into the viewport. It is unclear why there is a resize (and whether it can be avoided), but I suspect it’s due to the retina display on this particular laptop. I’m not using background-size or otherwise applying scaling/sizing in CSS, merely positioning eg., background-position:50% 50%; and background-repeat: no-repeat;. As curiosity sets in, this author will readily admit he has some more research to do on this front.

There are also aspects to RAM and caching that can affect GPU performance. I did not dig deeply into this specifically for Flickr’s new homepage, but it is worth considering the impact of the complexity and number of layers present and active at any given time. If regular scrolling triggers non-cached image resizes each time an asset is scrolled into view, there may be a cache eviction problem stemming from having too many layers active or present at once.

* Work laptop: Mid-2012 15″ Retina MBP, 16 GB RAM, 2.6 Ghz Intel i7, NVIDIA GeForce GT 650M/1024 MB, OS X 10.8.3.

Debugging in action

Here are two videos showing performance of flickr.com/new/ with transforms disabled and enabled, respectively.

Transforms off (marginTop-based parallax)

Notice the huge spikes on the timeline with transforms disabled, indicating many frames that are taking up to 80 msec to draw; this is terrible for performance, “blowing the frame budget” of 16 ms, and lowers UI responsiveness significantly. Red paint rectangles indicate that the whole viewport is being repainted on scroll, a major contributor to performance overhead. With compositing borders, you see that every “strip” of the page – each parallax background, in effect – is rendered as a single layer. A quick check of the FPS meter and “continuous repaint” graphs does not look great.

Side note: Continuous repaint is most useful when not scrolling. The feature causes repeated painting of the viewport, and displays an FPS graph with real-time performance numbers. You can go into the style editor while continuous repaint is on and flip things off, e.g., disabling box-shadow, border-radius or hiding expensive elements via display to see if the frame rate improves.

Transforms on (translate3d()-based parallax)

With GPU acceleration, you see much-improved frame times, thus a higher framerate and a smoother, more-responsive UI. There is still the occasional spike when a new image scrolls into view, but there is much less jank overall than before. Paint rectangles are much less common thanks to the GPU-accelerated compositing, and layer borders now indicate that more individual elements are being promoted. The FPS meter and continuous repaint mode does have a few dips and spikes, but performance is notably improved.

You may notice that I intentionally trigger video playback in this case, to see how it performs. The flashing red is the result of repainting as the video plays back – and in spite of overflow: hidden-based clipping we apply for the parallax effect on the video, it’s interesting to notice that the overflowed content, while not visible, is also being painted.

Miscellany

Random bits: HTML5 <video>

A frame from a .webm and H.264-encoded video, shown in the mobile portion of Flickr’s redesigned home page.

We wanted the signed-out Flickr homepage to highlight our mobile offerings, including an animation or video showing a subtly-rotating iPhone demoing the Flickr iOS app on a static background. Instead of an inline video box, it felt appropriate to have a full-width video following the pattern used for the parallax images. The implementation is nearly the same, and simply uses a <video> element instead of a CSS background.

With video, the usual questions came up around performance and file size: Would a 2048-pixel-wide video be too heavy for older computers to play back? What if we cropped the video only to be as wide as needed to cover the area being animated (eg., 500 pixels), and used a static JPEG background to fill in the remainder of the space?

As it turned out, encoding a 2048×700 video and positioning it like a background element – even including a slight parallax effect – was quite reasonable. Playback was flawless on modern laptops and desktops, and even a 2006-era 1.2 GHz Fujitsu laptop running WinXP was able to run the video at reasonable speed. Per rendering documentation from the Chrome team, <video> elements are automatically promoted to layers for the GPU where applicable and thus benefit from accelerated rendering. Due to the inline nature of the video, we excluded it from display on mobile devices, and show a static image to clients that don’t support HTML5 video.

Perhaps the most interesting aspect of the video was file size. In our case, the WebM-encoded video (supported natively in Chrome, Firefox, and Opera) was clearly able to optimize for the low amount of motion within the wide frame, as eight seconds of 2048×700 video at 24 fps resulted in a .webm file of only 900 KB. Impressive! By comparison, the H.264-encoded equivalent ended up being about 3.8 MB, with a matching data rate of ~3.8 mbps.

The “Justified” View

It’s worth mentioning that the Justified photos at the bottom of the page lazy-load in, and have been excluded from any additional display optimizations in this case. There is an initial spike with the render and subsequent loading of images, but things settle down pretty quickly. Blindly assigning translate-type transforms to the Justified photo container – a complex beast in and of itself – causes all sorts of rendering hell to break loose.

In Review

This article represents my findings and approach to getting GPU-accelerated compositing working for background images in the Webkit-based Chrome and Safari browsers, in May 2013. With ever-changing rendering engines getting smarter over time, your mileage may vary as the best route to the “fast path” changes. As numerous other articles have said regarding performance, “don’t guess it, test it.”

To recap:

- Painting: Expensive. Repaints should be minimal, and limited to small areas. Reduce by carefully choosing layers.

- Compositing: Good! Fast when done by the GPU.

- Layers: The secret to speed, when done correctly. Apply sparingly.

References / further reading:

… And finally, did I mention we’re hiring? (hint: view-source )

Like this:

Like Loading...

原文链接：http://code.flickr.net/2013/06/04/adventures-in-jank-busting-parallax-performance-and-the-new-flickr-home-page （本内容由互联网资料整理而成）

A Couple of Best Practices for Tablet-Friendly Design

Published June 17, 2013 by Guest Author

The following is a guest post by Ben Terrill. Ben is co-author of the e-book Tablet Web Design Best Practices and is the VP of Customer Success at Mobify, where he works on big client sites like British Telecom, Starbucks and Expedia.

The tablet revolution is upon us. New data from Adobe shows that global websites now get more traffic from tablets than smartphones. And yet, a standard desktop site doesn’t work very well on a tablet. The typical desktop 12-pixel font is too small, as are buttons. Images aren’t sharp and, worst of all, some features simply don’t work.

The good news is you don’t have to completely revamp your website. A working desktop site is a great place to start building an effective tablet site. In this article, I’ll share six techniques from Mobify’s latest ebook Tablet Web Design Best Practices for significantly improving desktop websites on tablets.

Go 100% Touch Friendly

One of the best ways to make your desktop website sing on a tablet is to make it touch friendly. If website elements look as though they can be swiped, tapped or pinched, then you’ll need to build in that functionality to make your website tablet ready.

Consider adding elements like carousels and accordions, drawers and panels. Mobify has a variety of open source JavaScript modules you can use for this purpose.

Editor's note: We recently covered the JavaScript for touch-friendly sliders. I also think Royal Slider is a nice slider that is touch-friendly and also responsive.

Bump Up Default Font Size and Line Height

Don’t make users double tap or pinch your content. Instead, increase the font size to at least 16px. You can also use a line height of 1.5 to allow for breathing room between text on content-rich pages, as Mashable does in the example below. Remember, text must always be legible, no matter how a user holds their tablet.

Be Finger Friendly

Our fingers are much clumsier than a cursor, so bumping up the spacing between different touch targets will improve user accuracy. And, make those touch targets big! Our fingertips typically require upwards of 44px to comfortably fit within a touch target so design for that.

Make each touch target at least 44px by 44px and use padding rather than margin. Padding increases the actual tappable area, whereas margin simply increases the whitespace around the element.

Enable Contextual Keyboards

The great thing about software keyboards is that they’re dynamic. That is, you can change their layout to suit context. For instance, if your input field requires an email address, the keyboard should feature the ‘@’ symbol, underscores and hyphens. If the user is asked to input a phone number, provide a numeric keypad. Try using the following input types on form fields:

- Standard keyboard | <input type="text" />

- URL parameters | <input type="url" />

- Email-specific keyboard | <input type="email" />

- Numeric keyboard | <input type="text" pattern="[0-9]*" />

Example of a better numeric keyboard (iOS on left, Android on right) (via)

Editor's note: I also detailed data about HTML5 input attributes/types/elements. It's getting a smidge old, but still useful.

Font-Based Icons for the Win

Resolutions and pixel densities on tablet screens are far greater than on desktop and laptop screens. As a result, graphics can look pixelated if they’re not designed with high resolution screens in mind. For this reason, font-based icons are a good choice because they scale well on super high resolution displays; they’re easy to colour and shade using CSS; and they only require one HTTP request to download. Plus, you don’t have to deal with a sprite sheet.

Create your own icon font sets, or use existing sets like Font Awesome, glyphish, iconsweets, symbolset, or icnfnt.

Editor's note: I once did a massive roundup of icon fonts (which I still have to add to). I'm a fan of using these HTML techniques for adding them to the page, which keep them accessible. I'm also a fan of IcoMoon for the creating trimmed down, customized icon font sets.

Performance is Design

Modern web design techniques, like responsive design, can cripple website performance. Since 57% of users are likely to leave your website if it takes 3 seconds to load, performance considerations are critical. Some tips for improving mobile website performance include compressing images and concatenating CSS and JavaScript to reduce the number of HTTP requests and overall page size. With these fixes, you’ll notice significantly speedier page load time and happier, higher converting users. Use tools like Uglify, Sass, Compass and Mobify.js to automate performance improvements.

Editor's note: I cover some of these performance techniques and some others in #114: Let’s Do Simple Stuff to Make Our Websites Faster

Go Forth!

With these tablet transformation techniques in your toolbox, there’s no reason to get stressed out about not having a totally tablet-optimized website. For more ways to make your desktop site tablet friendly, read Mobify’s free ebook, Tablet Web Design Best Practices.

原文链接：http://css-tricks.com/a-couple-of-best-practices-for-tablet-friendly-design/ （本内容由互联网资料整理而成）

那些年，我们踩过的“坑”

1. 使用try catch时，catch后面一定要跟上e，否则就会报错：

try {
alert(a);
} catch() {}//没有e会报错

2. Android下audio会自动被触发的bug，场景是当你在网页中使用了audio标签，当暂停后，这时如果有系统的声音被触发，这个audio的音频在某些设备上又会被“唤醒”播放。解决方法是播放结束后将src设为空页面（不是空字符串”"）:

$audio.on(‘ended’, function() {

$audio.attr(‘src’, ‘about:blank’);

});

3. Manifest更新问题，当有资源更改时我们知道需要修改manifest文件使其触发更新，但是即使是这样，也只是将缓存更新，页面还是使用之前老的资源，需要用户第二次进入才可以更新为最新的，解决方法是在更新完毕后刷新页面，同时注意Manifest文件不要设置缓存头，强制每次都取最新的：

window.applicationCache.addEventListener(‘updateready’, function(e) {

if(window.applicationCache.status === window.applicationCache.UPDATEREADY) window.reload();

});

4. Mobile上滚动事件处理，在Android2.3以下监听window的scroll事件时，只有在scroll结束后才会触发事件，而在浏览器中则是会实时触发，解决方法是使用touchmove事件来代替scroll事件。但是有时我们又需要这种scroll时只触发一次的事件，比如在手机上滚动结束后才触发某个事件，解决办法是使用定时器，保证只在最后触发一个事件处理，其余的则在滚动未结束时清除定时器，如在GMU中的处理方法：

function throttle() {
var timeId;
function wrapper() {
function exec() {};
timeId && clearTimeout(timeId);
timeId = setTimeout(exec, delay);
}
return wrapper;
})();
$(window).on(‘scroll’, throttle);

5. Zepto穿透bug，当两个层叠加在一起时，使用zepto的tap事件时点击上面一个层时有时会触发下面层的事件，俗称“穿透”，原因是由于zepto的tap事件是绑定在document上的，解决方法是延迟一定时间处理事件或是监听touchend事件并在事件中使用preventDefault阻止冒泡，还有人提出来是使用css的pointer events来避免，当然也有一个第三方的库，实在还是不行的话就使用”click”代替“tap”有时也能解决此问题。。。

6. Android2.2以下不支持position:fixed，同时在需要支持position:fixed支持时需要设置一下 <meta name=”viewport” content=”width=device-width, user-scalable: no”>  ，这样在有些设备还是有问题，比如这个元素在CSS中被设置为position: absolute；后来你再用JS设置position: fixed时调整位置，再次修改位置时发现position:fixed无法设了，解决方法是CSS里默认就将其设置为position: fixed；同时不要给这个元素设置transition动画，不然有可能也会影响position:fixed的效果。

原文链接：http://adamlu.com/?p=776 （本内容由互联网资料整理而成）

当前 WEB APP 开发的最佳实践

前段时间 forecast.io 家的 App 挺火挺热（请用 iPhone Safari 打开链接 http://forecast.io，然后添加到桌面看看效果 ）。接着官方博客释出了一篇文章，可以认为是当前 Mobile Web App 开发的最佳实践，我先总结一下：

1. 不要刻意模仿 iOS 的默认样式和交互。毕竟是 Web App，肯定会有模仿不到位的地方，这样会很快露出马脚；用自己的风格和交互则不会有这样的问题，没有参照物也就不容易察觉错误，容易糊弄过去。

2. 不要做得像个网站。

3. 只用硬件加速的 CSS 3 属性做动画效果。说白了，只使用 translate3d 系属性，而且使用 transition 时也不可以应用到没有硬件加速的属性上。

4. 不要自己实现滚动条。使用 -webkit-overflow-scrolling: touch 而不是采用类似 iScroll 这样的东西。

5. Web 技术上还做不好的事情就别JB做。

6. 用 FastClick 和 AppCache 提升用户体验。

7. 吃自己狗粮。

看到第 3 点没？其实现在做 Web App 门槛挺高，应付奇葩的 Javascript 实现所导致奇葩范式还算好，关键在于面对这么一坨从 Web 诞生至今延续下来的开发环境。换言之，假如现在微软释出一套大一统 SDK，包含从 MS DOS 到 .Net 4 的所有 API，会好学到哭么。奇迹，但是 W3C 做到了。

另外在 Chrome Dev Tools 里打开 Show paint rectangles 和 Show composited layer borders 选项就能直观地看到浏览器是怎么渲染你的 Web App 的。对于观察硬件加速的优化效果来说很有帮助。

言归正传，对于第 4 点，可能对 Mobile Web App 更适用。桌面 Web App 使用大数据的动态列表还是用 iScroll 这样的实现吧，效果比原生滚动强不是一点半点。

接下来几点是我总结的，面向基于 Angular.js 框架的大型 Web App 的优化实践，不过我想某些点对别的框架也适用。

1. 不要写…大型… Web App …（有气无力）

2. Model 的观察者要小要短.

3. 高频事件（例如 WebSocket ）的回调函数中需要对 View 进行修改的，用 throttle 控制事件频度。

4. 一个页面中不要超过 2000 条 Angular 表达式。

5. Angular.js 使用 dirty check 实现数据绑定，因此在 digest cycle 中尽量减少深度比较，仅仅包含会导致 View 变化的操作。

6. 除非万不得已，不要操作 DOM。

7. 局部性原理：操作 DOM 的语句尽可能连续地放在一起。

8. 多条语句连续地操作 DOM 时，用 setTimeout 分割它们可以得到明显效果。

9. 不要滥用 setTimeout。

10. 程序很慢，但是人类更慢。除非有明显的性能问题，否则不要过度优化（例如使用以上优化方式），只会搞得更糟。

不过话说回来，总算看到了 Web App 的一线曙光，其诸多优势让人没法忽视。所以先从 Hybrid App 开始吧。别说你讨厌 Hybrid App，其实它早就潜入我们身旁你都不一定感觉得到。例如 Tweetbot（最初的 OS X 版），SpeedTao 还有 …… 微信。其实吧，说不喜欢的，只不过是技术性偏执罢了。

原文链接：http://lyric.im/best-practice-for-web-app-development/#comments （本内容由互联网资料整理而成）

从Android界面开发谈起

这篇文章没有打算有一个很好的逻辑去介绍android的某个方面，全盘大致上就是我接触、了解android的ui开发后到现在的一些感想以及个人理解吧！

全文可能会涉及到java、android开发、android源码研究、设计模式等各方面的初级知识，属于典型的杂侃天下，深入研究还需要各位和我一起给力、加油了！

好了，废话少说，开动！

一、楔子：android界面开发意味着什么

第一个问题，android界面开发涉及到了哪些方面。

当你接触过一段时间的android应用开发，了解到了一些android的知识后，你应该能够在心中形成这样的印象：android的开发分为两块。一个是资源部分，一个是资源操作部分：详细点说的话，就是一个是对资源的导入、设置、整合等这些方面的工作，另一个就是对资源的调用、使用、控制（甚至改变）等这些方面的工作。前者在一个典型的android工程中的表现形式就是assets文件夹中的音频、视频等原生资源文件和res文件夹中的各式各样的xml文档文件以及形形色色的图片文件——很容易想到的是，这些东西是无法程序在运行时改变的，也就是静态的。后者在android工程则表现为src文件夹和gen文件夹中各式各样的java文件（有的是你手动输入生成的，有的则是adt通过aidl自动生成的），而通过开发人员的设计以及实现，这部分在应用运行时是可能发生改变的，也就是动态的。

而界面的开发便处在了这样一个极为重要的位置之上：沟通资源和对资源的操作（后者我们还可以简述为软件的“功能”）这两个部分。也就是说，如果你想要做出一个最低标准为“差强人意”的android界面的话，你至少首先对android的两大开发部分有一个大致上的了解——你得会写xml代码，以至于你可以形成一个又一个的还算符合逻辑的界面结构；你得学会P图（或者让会P图的人懂得该给你P什么图），抑或搜图，从而可以为你的界面准备一些养眼的图片资源，以给人眼前一亮的感觉；你得掌握android.widget包里面的一些常用类的使用方法以及一些使用技巧，从而可以让你的资源在应用运行时可以以很舒服的形态展示出来；你甚至得对android的窗口运行、管理机制有一定的了解，以到达更自由地定制界面特性的目的.....

另外一个问题就是，android界面开发到底体现在哪些地方。

这个问题就不得不提到用户体验这个永恒的话题上了，用户体验好，你就成功了一半。而用户体验的很大一部分就是界面的各种相关。让我们罗列出下面几个条件：

1.你的应用和用户打交道的就是，而且仅仅是它的界面

2.界面是沟通程序后台功能和用户的接口

3.界面有好坏之分

4.人是喜欢好的东西的

不知道你得出了什么结论，我的是：界面开发很重要，是不可敷衍了事的！

你也许会反驳我：如果功能实现的不完美，动不动就崩溃，界面再好又有什么用？是的，作为一个和我一样的“程序猿”，这样想是非常符合“骡迹”的，但一个对你的应用没有任何了解的客户却不是这么想的——他第一眼看到的仅仅是你应用的界面，而不是你的数据库是咋么工作的（能看到的话，估计黑客早就OUT了）——界面好看不，好用不？这些都是他所感受到、体验到的。只有这些类似于第一印象的东西在客户心中打下了获得好感的基础，客户才会有进一步了解你这个应用的欲望：应用程序东施很贤惠，数据库工作稳定，占用系统资源极少，但长的确实后现代了点；应用程序西施功能基本上没啥特点，有的功能东施都有，而且都不及东施，有时候甚至会导致系统崩溃（亡国），但就是界面极为人性化（也就是漂亮）。就是这样的两个应用，当摆在客户勾践面前的时候，该小白就选择花一美元买下西施，送给了上级夫差。

也就是说，想让客户相中你家应用，就得在它的界面上多下功夫。

其实刚开始我也是对界面这一块不以为然，以为它属于整个android开发流程中最为短期、最为轻松的部分，所以就打算用最快的速度弄完界面后和其他成员一起去进行功能上的开发。但是后来我才发现这是导致我们项目烂尾的最初起源之一：我的界面决定了整个应用的功能模块分布情况，不仅仅会影响到用户体验，而且在某些方面甚至会影响到功能模块的设计以及开发。而我的界面却没有像想象中完美，所以后来在功能开发完成后，我们都45度斜望着自家应用，泪流满面。

把以上的文字总结为一句话就是：界面开发很重要，因为它直接关系到用户体验，而且间接关系到功能开发。

下面是几个我曾经主要分析了的优秀的，成熟的界面：

(1)手机QQ

这个登录界面很清爽，很美观，我喜欢。

(2)Seesmic

这个好友列表看起来简约大方，很Cool。

(3)bump

bump，很有创意的一款软件，它的界面和刚才那个的风格极为类似——简约不简单。同时你也可以看到TabActivity的重要性。

二、开端：android界面开发基础知识介绍

1.MVC模式和android界面开发

当我在欣赏四人帮（GoF）的《设计模式》的第一章时，就提到了这个在应用程序设计中最为经典的设计模式——MVC，也就是Model-View-Controller（模型-视图-控制器）。

这个模式的最大特点在我理解来看，就是实现了视图和控制器的分离，视图的更新经由模型，完全听由控制器的安排。详细了解请点击链接。

以下为《设计模式》书中原话的援引：

看到这段话你想到了什么？没错，想到了两个类：android.view.View和android.view.ViewGroup。前者很像上述文字中提到的View，后者则很像CompositeView——而且ViewGroup就是View的子类，它还可以嵌套View以及ViewGroup。

没这么巧吧？

其实这不是一个巧合，而是android界面系统的构建本身就是一个借鉴了MVC模式的活生生的例子（有些地方说是C/S模式也是对的，但我个人觉得那是偏向管理方面的，真正结构上还是吸收了MVC模式的影子。而且更重要的是，C/S模式对于我们来说还太难懂，所以我选择了android擦了边的MVC来引入话题）。我们甚至可以找到android中对应于控制器的东西：android.view.ViewManager，虽然它仅仅是一个接口而已。然后你再想想那些常用的android.widget包中的会显示在屏上的类都是继承自View....是不是有一种豁然开朗的感觉啊？

看了这半天你也许会问，讲android界面开发好好的，为啥忽然跳到了设计模式上面来了？其实你应该了解这样一个事实：android也是人做出来的，能做出来，也就一定有它的依据——而所谓的设计模式也就是其中的依据之一。这么看来，如果想要了解android的实质，在android的开发中能够更如鱼得水，设计模式是一定要研究的——这样至少可以让你了解到系统各个组件之间的依存关系。

希望了解到了MVC模式后，再去看看android参考文档，你能够对android的界面系统有一个较为本质性的深入化的了解。

再举两个在android中应用设计模式例子:

(1)老在开发中用到名字中带Factory的类，而其实这里属于工厂模式的范畴。

(2)你可以让你的Activity带上singleInstance的activity launch mode，而这里涉及到了单例模式。

更多的就等待你去发现了，不过发现了别忘了第一个告诉我啊！

2.关于一些界面开发中重要的组件

对于什么是Activity、什么是TextView等等，我就不多说了，因为大家都已经对这些有了一些基本的了解了。在这里，我想谈谈自己平时较常用到的一些界面开发组件的特点以及怎么用它。

(1)常用ViewGroup

一个界面的设计工作，第一步就是整个界面框架结构的设计，而这些框架结构在android中是用ViewGroup类别组件来实现的。ViewGroup有常见子类AbsoluteLayout, AdapterView<T extends Adapter>, FrameLayout, LinearLayout, RelativeLayout, SlidingDrawer。

由于android设备市场现在群雄并起，所以各种显示特点的设备都有。为了让你家应用可以在各种机器上都能够得到最真实的写照，AbsoluteLayou最好还是别用了。要用的话你就必须有巧妙的技术避开其缺点，或者你就不得不针对每种设备设计一套独有的UI（当然我们是不会这样去做的）。

SlidingDrawer是一个还算炫的组件，它可以让你实现一个抽屉功能，进而去扩展那少的可怜的手机屏幕面积。在1.6时代的机子上Home界面下方的那个点了之后拉出很多应用的箭头就是SlidingDrawer的一个实例。

我个人使用的最多的是LinearLayout，RelativeLayout，AdapterView<T extends Adapter>。

LinearLayout和RelativeLayout我主要用来进行界面的整体布局。

界面中经常出现一种几个widget成竖排或横排的形式出现的情况，这个时候通常就得用LinearLayout。它有一个属性：orientation，这个属性可以设置LinearLayout内部的组件是怎样排列的。

RelativeLayout没有LinearLayout死板，但比AbsoluteLayout要设备兼容性更强，所以一旦涉及到方位的布局，我一般会首先考虑它，它的一些类似于android:layout_alignLeft、android:layout_alignParentLeft等属性在方位布局上用起来总是得心应手。

而如果将刚才两把利器结合起来的话，你就会发现，只要是信息容量不大的界面，基本上用它们都可以实现布局了。例如刚才的手机QQ的登录界面就是这样的。

当界面中有大量的信息内容需要展现时，我们通常会想到AdapterView<T extends Adapter>。

其实AdapterView<T extends Adapter>（尖括号涉及到java中泛型的概念）只是一个抽象类，它是android中一类信息包含量极大，可以显示几乎各种形式数据的界面组件们的父类。而它的子类就包含了我们熟悉的Gallery, GridView, ListView, Spinner。这个系列的组件在显示数据时都会需要一个接口android.widget.Adapter的实现类帮忙，例如ArrayAdapter<T>, BaseAdapter, CursorAdapter,SimpleAdapter, SimpleCursorAdapter, SpinnerAdapter（相信大家都很熟悉了，所以就不简介了，而且我很怀疑这又是一个设计模式的实例，但还没找到具体是哪种，希望知道的同学告诉我）。

(2)常用View

界面结构弄好了，当然就是向里面加入东西了。常用的View（除去ViewGroup）有这些：TextView,ImageView,, ProgressBar,AutoCompleteTextView, Button, CheckBox,EditText,ImageButton, ImageSwitcher,RadioButton, RadioGroup,SeekBar,Spinner, TabHost, TabWidget, TableLayout,WebView等等等等，等等等等.....

可以说深入的了解这些组件是开发出西施级界面的必由之路。当然，限于篇幅，这里还是不一一介绍了，有兴趣的同学可以去网上搜索（我以后会把关于该组件的我看到的最好的博文以链结的方式放上来）。

在这里就和大家分享几个小经验：

(1).这些组件应该都有一个类似的构造方法：某某(Context context)。例如TextView就有构造方法TextView(Context context)，这样以后如果你在java代码中想要生成一个View实例时，就可以用这个万金油式的构造方法（关于Context，刚接触时我也是很纳闷的，但看了这篇文章，和这篇文章后，我就有了一个大致的了解）。

(2).有时候你想在java文件里面设置一个组件的属性，但是你却不知道这个方法是否存在，那你就可可以去参看android文档中该类的XML Attributes一栏，这里罗列了该组件在xml文件中所有的可设置属性，更给力的是，这里也把该属性对应的java方法罗列了出来——如果xml属性后面有对应java方法，那你就可以很有福气的在java文档中调用了，如果没有，那你就只能自认倒霉了。举个例子：View类有一个xml属性是设置其背景的，名字叫做android:background="@%#$@%$#"，而文档中它后面有一个setBackgroundResource(int)方法（如图），这就表明在java代码中你可以通过view实例来动态设置其背景了。

(3).这些组件其实并不是一成不变的——它们是具有极大的定制性的。这句话也就是说，你可以初级性的定义该组件的外观（后面的一个实例会提到这个），也可以高级性的定义该组件的行为——这些意味着，你可以设置一个Button在成为焦点，失去焦点，按下等等状态下的外观（点这里看例子），也可以设置该Button对触摸事件，按键事件等等做出怎样的反应（我又想起了事件机制，呵呵）。有了这些，难怪有些应用会然你看到一些组件很奇怪的反应——例如禁止单击，只许长按。

(4).这些组件的可设置属性大致可以这样分组：应用于该组件内部的，应用于该组件的。举个例子：android:layout_gravity属性设置的是该组件在其父组件内部的位置特性，而和其相对应的就有android:gravity来设置该组件子组件在其内部的位置特性；android:paddingLeft="10dip"指的是该组件内部组件里左边必须有10dip的距离，而android:marginLeft="10dip"则指的该组件离其父组件左边界必须有10dip的距离......

说了这么多，其实就是想给大家一个tip，希望大家能够在以后的界面开发中有什么想法后能够知道可以用什么组件去实现。还有一个观点想告诉大家，想了解一个android库类，最先想到的一定要是android文档——虽然是英文，但只有它才会告诉你最本源的信息。同时你也可以采取广而深的查看方法去地毯式的查看文档中某一方面的类——这样看就会有一个很全面的了解过程，印象也就会更深。在这里推荐大家看看android.view.View和android.app.Activity的文档，那里有许多很基础、很给力的知识。

3.关于开发工具

哎，到了这里，我就不得不吐槽下了：android的可视化界面开发工具——Layout Editor——刚开始用的真的很不习惯！竟然连vc的都不如，实在有点out了！

所以在这里推荐一个还算好的民间高手用java编写的DroidDraw(虽然还有些不完善，但它的“所见即所得”还是做的比Layout Editor好很多的)：介绍在这里，下载在这里。

三、升华：高级技巧浅尝

哈哈，小生菜鸟，不敢鲁班门前甩斧头，在这里就简单说说几个自己了解的比较高手级别的做法吧。另外，雪地原地翻转720度凌空转体三周半空中抱头翻转两周半后跪求高手指教小弟。一日为师，终生为..你懂的。

1.自建widget

也就是说，你可以自己建立一个类继承于android.view.View类，然后override一些View的方法，之后再加上你的一些自己的实现，最终构成一个自己构建的widget（当然你也可以来一个自定义的ViewGroup，我可是不介意的）。有兴趣了解这方面知识的童鞋可以去百度上Google一下，这里就不贴具体帖子了。

另附文档中一段比较重要的文字：

Implementing a Custom View

To implement a custom view, you will usually begin by providing overrides for some of the standard methods that the framework calls on all views. You do not need to override all of these methods. In fact, you can start by just overriding onDraw(android.graphics.Canvas).

Category

Methods

Description

Creation

Constructors

There is a form of the constructor that are called when the view is created from code and a form that is called when the view is inflated from a layout file. The second form should parse and apply any attributes defined in the layout file.

onFinishInflate()

Called after a view and all of its children has been inflated from XML.

Layout

onMeasure(int, int)

Called to determine the size requirements for this view and all of its children.

onLayout(boolean, int, int, int, int)

Called when this view should assign a size and position to all of its children.

onSizeChanged(int, int, int, int)

Called when the size of this view has changed.

Drawing

onDraw(Canvas)

Called when the view should render its content.

Event processing

onKeyDown(int, KeyEvent)

Called when a new key event occurs.

onKeyUp(int, KeyEvent)

Called when a key up event occurs.

onTrackballEvent(MotionEvent)

Called when a trackball motion event occurs.

onTouchEvent(MotionEvent)

Called when a touch screen motion event occurs.

Focus

onFocusChanged(boolean, int, Rect)

Called when the view gains or loses focus.

onWindowFocusChanged(boolean)

Called when the window containing the view gains or loses focus.

Attaching

onAttachedToWindow()

Called when the view is attached to a window.

onDetachedFromWindow()

Called when the view is detached from its window.

onWindowVisibilityChanged(int)

Called when the visibility of the window containing the view has changed.

2.在源码环境下进行应用开发

没错，Google是很大方的，因为android实现了完全开源——你可以用Git这个代码版本管理工具下载整个android平台的源代码（甚至自己利用源码编译一个android平台出来，不过听说至少2小时）。但如果我告诉你，我们经常接触的android SDK仅仅只提供了这些源码中的一部分实现，你又会怎么看呢？嗯，不是Google小气，做这些隐藏实现其实是为了保证系统的安全性、稳定性（水果公司的隐藏实现部分还必须勤劳的开源社区人士破解出来才能使用，所以Google确实不是小气的）。当然，既然Google给了我们源码，我们就得好好利用它——在源码环境下实现android程序开发。在源码环境下，你可以实现sdk环境中无法实现的一些界面效果：例如用虚拟按钮来模拟Menu按键（后面有一帖子介绍）。这个是我即将进行探索的一个领域，所以现在还无法和大家分享自己的经验。就推荐两个帖子给大家解解馋吧：

(1)环境搭建：Android源码环境搭建

(2)实例：Android模拟按键——源码环境下开发应用程序

希望大家能够有志于android的高级技巧探索，然后和大家分享（我再次表示不会介意的）。

四、高潮：一个界面的实现

说了这么多，咱们“程序猿”该看点代码了。在这里就把我最新做出来的Life TraXer的欢迎界面以及Log In 界面的代码贴出来大家拍拍板砖。

1.欢迎界面的xml代码

2.欢迎界面的java代码（注意Handler那部分）

3.登陆界面xml代码（看看嵌套的方式）

4.登录界面的java

5.实际效果贴图

欢迎界面

登录界面

五、尾声：鸣谢

好啦，鸣谢：摆渡、谷哥。

各位看官，谢谢围观。

如有纰漏，欢迎拍砖！

原文链接：http://blog.csdn.net/nieweilin/article/details/5967815 （本内容由互联网资料整理而成）

浅析 Cordova for iOS

Cordova，对这个名字大家可能比较陌生，大家肯定听过 PhoneGap 这个名字，Cordova 就是 PhoneGap 被 Adobe 收购后所改的名字。

Cordova 是一个可以让 JS 与原生代码(包括 Android 的 java，iOS 的 Objective-C 等)互相通信的一个库，并且提供了一系列的插件类，比如 JS 直接操作本地数据库的插件类。

这些插件类都是基于 JS 与 Objective-C 可以互相通信的基础的，这篇文章说说 Cordova 是如何做到 JS 与 Objective-C 互相通信的，解释如何互相通信需要弄清楚下面三个问题：

1. JS 怎么跟 Objective-C 通信

2. Objective-C 怎么跟 JS 通信

3. JS 请求 Objective-C，Objective-C 返回结果给 JS，这一来一往是怎么串起来的

Cordova 现在最新版本是 2.7.0，本文也是基于 2.7.0 版本进行分析的。

JS 怎么跟 Objective-C 通信

JS 与 Objetive-C 通信的关键代码如下：(点击代码框右上角的文件名链接，可直接跳转该文件在 github 的地址)

JS 发起请求 cordova.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

function iOSExec() {
...
if (!isInContextOfEvalJs && commandQueue.length == 1)  {
// 如果支持 XMLHttpRequest，则使用 XMLHttpRequest 方式
if (bridgeMode != jsToNativeModes.IFRAME_NAV) {
// This prevents sending an XHR when there is already one being sent.
// This should happen only in rare circumstances (refer to unit tests).
if (execXhr && execXhr.readyState != 4) {
execXhr = null;
}
// Re-using the XHR improves exec() performance by about 10%.
execXhr = execXhr || new XMLHttpRequest();
// Changing this to a GET will make the XHR reach the URIProtocol on 4.2.
// For some reason it still doesn't work though...
// Add a timestamp to the query param to prevent caching.
execXhr.open('HEAD', "/!gap_exec?" + (+new Date()), true);
if (!vcHeaderValue) {
vcHeaderValue = /.*\((.*)\)/.exec(navigator.userAgent)[1];
}
execXhr.setRequestHeader('vc', vcHeaderValue);
execXhr.setRequestHeader('rc', ++requestCount);
if (shouldBundleCommandJson()) {
// 设置请求的数据
execXhr.setRequestHeader('cmds', iOSExec.nativeFetchMessages());
}
// 发起请求
execXhr.send(null);
} else {
// 如果不支持 XMLHttpRequest，则使用透明 iframe 的方式，设置 iframe 的 src 属性
execIframe = execIframe || createExecIframe();
execIframe.src = "gap://ready";
}
}
...
}

JS 使用了两种方式来与 Objective-C 通信，一种是使用 XMLHttpRequest 发起请求的方式，另一种则是通过设置透明的 iframe 的 src 属性，下面详细介绍一下两种方式是怎么工作的：

XMLHttpRequest bridge

JS 端使用 XMLHttpRequest 发起了一个请求：execXhr.open('HEAD', "/!gap_exec?" + (+new Date()), true); ，请求的地址是 /!gap_exec；并把请求的数据放在了请求的 header 里面，见这句代码：execXhr.setRequestHeader('cmds', iOSExec.nativeFetchMessages()); 。

而在 Objective-C 端使用一个 NSURLProtocol 的子类来检查每个请求，如果地址是 /!gap_exec 的话，则认为是 Cordova 通信的请求，直接拦截，拦截后就可以通过分析请求的数据，分发到不同的插件类(CDVPlugin 类的子类)的方法中：

UCCDVURLProtocol 拦截请求UCCDVURLProtocol.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

+ (BOOL)canInitWithRequest:(NSURLRequest*)theRequest
{
NSURL* theUrl = [theRequest URL];
NSString* theScheme = [theUrl scheme];
// 判断请求是否为 /!gap_exec
if ([[theUrl path] isEqualToString:@"/!gap_exec"]) {
NSString* viewControllerAddressStr = [theRequest valueForHTTPHeaderField:@"vc"];
if (viewControllerAddressStr == nil) {
NSLog(@"!cordova request missing vc header");
return NO;
}
long long viewControllerAddress = [viewControllerAddressStr longLongValue];
// Ensure that the UCCDVViewController has not been dealloc'ed.
UCCDVViewController* viewController = nil;
@synchronized(gRegisteredControllers) {
if (![gRegisteredControllers containsObject:
[NSNumber numberWithLongLong:viewControllerAddress]]) {
return NO;
}
viewController = (UCCDVViewController*)(void*)viewControllerAddress;
}
// 获取请求的数据
NSString* queuedCommandsJSON = [theRequest valueForHTTPHeaderField:@"cmds"];
NSString* requestId = [theRequest valueForHTTPHeaderField:@"rc"];
if (requestId == nil) {
NSLog(@"!cordova request missing rc header");
return NO;
}
...
}
...
}

Cordova 中优先使用这种方式，Cordova.js 中的注释有提及为什么优先使用 XMLHttpRequest 的方式，及为什么保留第二种 iframe bridge 的通信方式:

// XHR mode does not work on iOS 4.2, so default to IFRAME_NAV for such devices.
// XHR mode’s main advantage is working around a bug in -webkit-scroll, which
// doesn’t exist in 4.X devices anyways

iframe bridge

在 JS 端创建一个透明的 iframe，设置这个 ifame 的 src 为自定义的协议，而 ifame 的 src 更改时，UIWebView 会先回调其 delegate 的 webView:shouldStartLoadWithRequest:navigationType: 方法，关键代码如下：

UIWebView拦截加载CDVViewController.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

// UIWebView 加载 URL 前回调的方法，返回 YES，则开始加载此 URL，返回 NO，则忽略此 URL
- (BOOL)webView:(UIWebView*)theWebView
shouldStartLoadWithRequest:(NSURLRequest*)request
navigationType:(UIWebViewNavigationType)navigationType
{
NSURL* url = [request URL];
/*
* Execute any commands queued with cordova.exec() on the JS side.
* The part of the URL after gap:// is irrelevant.
*/
// 判断是否 Cordova 的请求，对于 JS 代码中 execIframe.src = "gap://ready" 这句
if ([[url scheme] isEqualToString:@"gap"]) {
// 获取请求的数据，并对数据进行分析、处理
[_commandQueue fetchCommandsFromJs];
return NO;
}
...
}

Objective-C 怎么跟 JS 通信

熟悉 UIWebView 用法的同学都知道 UIWebView 有一个这样的方法 stringByEvaluatingJavaScriptFromString:，这个方法可以让一个 UIWebView 对象执行一段 JS 代码，这样就可以达到 Objective-C 跟 JS 通信的效果，在 Cordova 的代码中多处用到了这个方法，其中最重要的两处如下：

获取 JS 的请求数据CDVCommandQueue.m

1
2
3
4
5
6
7
8
9
10
11
12

- (void)fetchCommandsFromJs
{
// Grab all the queued commands from the JS side.
NSString* queuedCommandsJSON = [_viewController.webView
stringByEvaluatingJavaScriptFromString:
@"cordova.require('cordova/exec').nativeFetchMessages()"];
[self enqueCommandBatch:queuedCommandsJSON];
if ([queuedCommandsJSON length] > 0) {
CDV_EXEC_LOG(@"Exec: Retrieved new exec messages by request.");
}
}

把 JS 请求的结果返回给 JS 端CDVCommandDelegateImpl.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

- (void)evalJs:(NSString*)js scheduledOnRunLoop:(BOOL)scheduledOnRunLoop
{
js = [NSString stringWithFormat:
@"cordova.require('cordova/exec').nativeEvalAndFetch(function(){ %@ })",
js];
if (scheduledOnRunLoop) {
[self evalJsHelper:js];
} else {
[self evalJsHelper2:js];
}
}
- (void)evalJsHelper2:(NSString*)js
{
CDV_EXEC_LOG(@"Exec: evalling: %@", [js substringToIndex:MIN([js length], 160)]);
NSString* commandsJSON = [_viewController.webView
stringByEvaluatingJavaScriptFromString:js];
if ([commandsJSON length] > 0) {
CDV_EXEC_LOG(@"Exec: Retrieved new exec messages by chaining.");
}
[_commandQueue enqueCommandBatch:commandsJSON];
}
- (void)evalJsHelper:(NSString*)js
{
// Cycle the run-loop before executing the JS.
// This works around a bug where sometimes alerts() within callbacks can cause
// dead-lock.
// If the commandQueue is currently executing, then we know that it is safe to
// execute the callback immediately.
// Using    (dispatch_get_main_queue()) does *not* fix deadlocks for some reaon,
// but performSelectorOnMainThread: does.
if (![NSThread isMainThread] || !_commandQueue.currentlyExecuting) {
[self performSelectorOnMainThread:@selector(evalJsHelper2:)
withObject:js
waitUntilDone:NO];
} else {
[self evalJsHelper2:js];
}
}

怎么串起来

先看一下 Cordova JS 端请求方法的格式：

1
2
3
4
5
6

// successCallback : 成功回调方法
// failCallback    : 失败回调方法
// server          : 所要请求的服务名字
// action          : 所要请求的服务具体操作
// actionArgs      : 请求操作所带的参数
cordova.exec(successCallback, failCallback, service, action, actionArgs);

传进来的这五个参数并不是直接传送给原生代码的，Cordova JS 端会做以下的处理：

1. 会为每个请求生成一个叫 callbackId 的唯一标识：这个参数需传给 Objective-C 端，Objective-C 处理完后，会把 callbackId 连同处理结果一起返回给 JS 端

2. 以 callbackId 为 key，{success:successCallback, fail:failCallback} 为 value，把这个键值对保存在 JS 端的字典里，successCallback 与 failCallback 这两个参数不需要传给 Objective-C 端，Objective-C 返回结果时带上 callbackId，JS 端就可以根据 callbackId 找到回调方法

3. 每次 JS 请求，最后发到 Objective-C 的数据包括：callbackId, service, action, actionArgs

关键代码如下：

JS 端处理请求cordova.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

function iOSExec() {
...
// 生成一个 callbackId 的唯一标识，并把此标志与成功、失败回调方法一起保存在 JS 端
// Register the callbacks and add the callbackId to the positional
// arguments if given.
if (successCallback || failCallback) {
callbackId = service + cordova.callbackId++;
cordova.callbacks[callbackId] =
{success:successCallback, fail:failCallback};
}
actionArgs = massageArgsJsToNative(actionArgs);
// 把 callbackId，service，action，actionArgs 保持到 commandQueue 中
// 这四个参数就是最后发给原生代码的数据
var command = [callbackId, service, action, actionArgs];
commandQueue.push(JSON.stringify(command));
...
}
// 获取请求的数据，包括 callbackId, service, action, actionArgs
iOSExec.nativeFetchMessages = function() {
// Each entry in commandQueue is a JSON string already.
if (!commandQueue.length) {
return '';
}
var json = '[' + commandQueue.join(',') + ']';
commandQueue.length = 0;
return json;
};

原生代码拿到 callbackId、service、action 及 actionArgs 后，会做以下的处理：

1. 根据 service 参数找到对应的插件类

2. 根据 action 参数找到插件类中对应的处理方法，并把 actionArgs 作为处理方法请求参数的一部分传给处理方法

3. 处理完成后，把处理结果及 callbackId 返回给 JS 端，JS 端收到后会根据 callbackId 找到回调方法，并把处理结果传给回调方法

关键代码：

Objective-C 返回结果给 JS 端CDVCommandDelegateImpl.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

- (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callbackId
{
CDV_EXEC_LOG(@"Exec(%@): Sending result. Status=%@", callbackId, result.status);
// This occurs when there is are no win/fail callbacks for the call.
if ([@"INVALID" isEqualToString : callbackId]) {
return;
}
int status = [result.status intValue];
BOOL keepCallback = [result.keepCallback boolValue];
NSString* argumentsAsJSON = [result argumentsAsJSON];
// 将请求的处理结果及 callbackId 通过调用 JS 方法返回给 JS 端
NSString* js = [NSString stringWithFormat:
@"cordova.require('cordova/exec').nativeCallback('%@',%d,%@,%d)",
callbackId, status, argumentsAsJSON, keepCallback];
[self evalJsHelper:js];
}

JS 端根据 callbackId 回调cordova.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

// 根据 callbackId 及是否成功标识，找到回调方法，并把处理结果传给回调方法
callbackFromNative: function(callbackId, success, status, args, keepCallback) {
var callback = cordova.callbacks[callbackId];
if (callback) {
if (success && status == cordova.callbackStatus.OK) {
callback.success && callback.success.apply(null, args);
} else if (!success) {
callback.fail && callback.fail.apply(null, args);
}
// Clear callback if not expecting any more results
if (!keepCallback) {
delete cordova.callbacks[callbackId];
}
}
}

通信效率

Cordova 这套通信效率并不算低。我使用 iPod Touch 4 与 iPhone 5 进行真机测试：JS 做一次请求，Objective-C 收到请求后不做任何的处理，马上把请求的数据返回给 JS 端，这样能大概的测出一来一往的时间(从 JS 发出请求，到 JS 收到结果的时间)。每个真机我做了三组测试，每组连续测试十次，每组测试前我都会把机器重启，结果如下：

组\序号

第1次

第2次

第3次

第4次

第5次

第6次

第7次

第8次

第9次

第10次

组平均时间

第一组

10

11

8

13

11

9

14

13

9

12

11.0

第二组

33

13

9

13

11

8

14

12

15

37

15.2

第三组

20

19

9

16

11

17

13

9

10

8

13.2

这三十次测试的平均时间是：(11.0 + 15.2 + 13.2) / 3 = 13.13 毫秒

组\序号

第1次

第2次

第3次

第4次

第5次

第6次

第7次

第8次

第9次

第10次

组平均时间

第一组

3

3

4

2

3

2

3

2

2

3

2.7

第二组

7

2

2

2

2

3

2

2

2

4

2.8

第三组

6

3

2

3

2

2

2

3

2

2

2.7

这三十次测试的平均时间是：(2.7 + 2.8 + 2.7) / 3 = 2.73 毫秒

这通信的效率虽然比不上原生调原生，但是也是属于可接受的范围了。

原文链接：http://zhenby.com/blog/2013/05/16/cordova-for-ios/ （本内容由互联网资料整理而成）

How Behance went responsive with Sass and Require.js

At Behance, we recently made our powerful search and discovery tools on the homepage responsive.

Making a responsive website was new territory to all of us, so none of us had experience designing or building one, let alone any first-hand experience with best practices or tricks for doing so.

How different should the phone view be from the tablet view from the desktop view? How should we structure our code? What tools and frameworks should we use? Does anybody in this Apple-happy office have an Android phone we can test on?

With a small team of dedicated developers, we got it done and learned a lot. We laid a foundation of responsive modules that could be re-used on the rest of the site using the power of Sass to make our CSS clean, modular and extensible. We flexed our JavaScript muscles by making and using our own breakpoint notifier and using Require.js for modular JS and asynchronous code loading. We also built up a modest mobile device testing station in our office to boot.

Since then, we've started working on making other pages of Behance responsive and have launched our first fully-responsive website for the 99U. Here are the most important things we learnt from our first responsive endeavour:

Retrofitting a website is hard

There are a number of considerations to make when you retrofit a site to be responsive. Behance wasn't originally built with responsiveness in mind and had too many pages to upgrade the entire website to be responsive all at once. We had to think carefully about how we could upgrade pieces of the site without affecting others. We would need a different base layout, a new way of including our CSS and JS, and some way to create or adjust existing components (popup dialogs, form elements, etc) to be responsive without negatively impacting older, non-responsive pages.

The layout

One of the first things we had to do was change the core of our layout to be responsive. Our fixed-width columns were the first to need adjusting, plus we needed to implement a special header toolbar and off-screen navigation (or, as we like to call it, 'the basement') for phones and tablets. Our new layout included:

Markup for the toolbar and basement navigation

Getting rid of elements is the easiest way to make the most important content fit comfortably on smaller screens. We love to display: none; anything that doesn't strictly improve the mobile browsing experience. Sometimes you can't remove things entirely, and that's when off-canvas elements come into play. We decided to go with an off-canvas menu for our main site navigation. We liked that it offered a way to keep elements accessible without being visible all the time and that the design pattern was common enough that users should already be comfortable using it.

Phone and tablet views with the basement navigation open

The HTML was structured like:

1. <div class="top-panel">

2. <div class="hamburger"></div>

3. <!-- site content -->

4. </div>

5. <div class="basement">

6. <!-- basement items -->

7. </div>

And the structural and functional Sass code:

1. .basement,

2. .top-panel {

3. @include translate3d(0,0,0);

4. }

6. .basement {

7. height: 100%;

8. position: absolute;

9. top: 0;

10. left: 0;

11. width: 75%;

12. }

14. .top-panel {

15. @include transition(transform .2s ease 0s);

16. display: block;

17. overflow: hidden;

18. position: relative;

19. height: 100%;

20. top: 0;

21. left: 0;

22. z-index: 2;

24. .basement-open & {

25. @include translate3d(75%, 0, 0);

26. }

28. } // .top-panel

The JavaScript binds a click/tap event to .hamburger to toggle a basement-open class on the body. When added, the content panel slides to the right, revealing the basement underneath. When removed, the content panel slides to the left, covering the basement. Since the animations are using CSS transitions instead of JavaScript animations, the effect is smooth.

Feature detection

We use the feature detection library has.js throughout the site, and dropped a line in along with Require.js at the beginning of our tag to add a class when a user is on a touch device:

1. <script type="text/javascript">

2. require(['has'], function(has) {

3. $(document.body).addClass(has('touch-device') ? 'touch-device' : '');

4. });

5. </script>

Thanks to Require.js, the call to the library is asynchronous and fast, so it's non-blocking. We used the class to style certain elements differently if the user is on a touch device. Modernizr is another popular library that provides similar functionality.

We also used conditional comments for our HTML tag so we could fix the inevitable IE-only display issues:

1. <!--[if IE 7]> <html class="ie ie7"> <![endif]-->

2. <!--[if IE 8]> <html class="ie ie8"> <![endif]-->

3. <!--[if IE 9]> <html class="ie ie9"> <![endif]-->

4. <!--[if (gt IE 9)|!(IE)]><!--> <html> <!--<![endif]-->

A viewport meta tag to ensure content always fits the device and cannot be zoomed or scaled by the user

It took us a few minutes to figure out why our site wasn't scaling at all on mobile devices before we had this in place. It's restrictive, but we want our content to fit the device screen at all times and, if the design is right, the user won't need to zoom in for anything anyway.

1. <meta name="viewport" content="width=device-width, initial-scale=0.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />

Asset loading

Maintaining or improving performance of a site can be hard when you retrofit, since you are building extra functionality into an established system. We wanted to keep load times down as much as possible. We used Require.js to asynchronously load the majority of JS files and experimented with a few different ways of including our CSS files:

Method 1: A link tag per breakpoint

1. <link rel="stylesheet" href="desktop/site.css" media="(min-width: 1025px)" />

2. <link rel="stylesheet" href="tablet/site.css" media="(min-width: 604px) and (max-width: 1024px)" />

3. <link rel="stylesheet" href="phone/site.css" media="(max-width: 603px)" />

Our primary hope for this approach was that the CSS files wouldn't download on a device without a matching media query. As a result, we prevented complex desktop styles being undone by the CSS for the simpler phone and tablet views. But, in practice, not only were all the CSS files always downloaded, we found that IE8 wouldn't load any media-qualified links at all, leaving the desktop site completely unstyled. We could have just removed the media attribute from the desktop CSS, but decided we didn't like the file structure and number of HTTP requests this created anyway.

Experiment 2: Media queries within the CSS

We opted for a desktop-first approach and layered any necessary phone and tablet styles on top by putting our media queries last. With this approach, your CSS file may look like:

1. /* desktop styles */

3. @media (min-width: 604px) and (max-width: 1024px) {

4. /* tablet styles */

5. }

7. @media (max-width: 603px) {

8. /* phone styles */

9. }

The biggest benefit here is that there are fewer HTTP requests for the browser to make. We ramped it a degree by using Sass partials for each breakpoint and utilities (like our variables and mixins), so the end result is a single CSS file. However, our code and file structure is a little more modular:

1. $tablet_upper: 1024px;

2. $phone_upper: 603px;

4. @mixin phone {

6. @media (max-width: $phone_upper) {

7. @content;

8. }

10. } // @mixin phone

12. @mixin tablet {

14. @media (min-width: $phone_upper+1) and (max-width: $tablet_upper) {

15. @content;

16. }

18. } // @mixin tablet

_utility.scss partial

1. @import "_utility.scss";

3. /* desktop styles */

5. @import "_tablet.scss";

6. @import "_phone.scss";

site.scss

Then, within each _tablet.scss and _phone.scss file respectively:

1. @include tablet {

2. /* tablet styles */

3. }

_tablet.scss partial

1. @include phone {

2. /* phone styles */

3. }

_phone.scss partial

With Sass, any file whose filename starts with an underscore is a partial (a file that doesn't compile directly to a CSS file, but instead only compiles when it's imported from a regular Sass file). It's also important to note that a media query doesn't increase specificity, so any media queries you use should come after all your base styles.

The compiled code results in a single CSS file (like the example above), but for development, our files are structured and separated neatly. Sass source maps make it easy to use the inspector and see exactly what line and Sass file a rule came from, even if it's nested within other rules and imported from a partial. If you're using Firefox, FireSass will let you view this information in the styles panel of Firebug. Sass source map support has been available experimentally in Chrome since version 24 and Sass 3.3 will offer even more advanced source maps.

Firebug's Style panel without source maps (left); with source maps (right)

Component upgrades

Similarly to how we utilised partials for breaking up our responsive styles, we also created partials for our new responsive components. It's an ongoing set that will grow over time, but for now our file structure looks a bit like:

1. responsive.scss

2. responsive/

3. _popups.scss

4. _buttons.scss

5. _inputs.scss

Our compiled responsive.css gets included on any responsive page, and comes with the contents of our partials that adjust our existing components to be mobile-friendly. We also have a set of less commonly used components that can be included only in the files that need them (for example, a social media icon on a project page that isn't used very often).

The JavaScript has to respond, too

The homepage of behance.net is a complex page that can sort, search and filter multiple different types of content based on a number of different criteria. The core of its interactive power comes from our use of client-side templating with mustache.js and AMD modularity with Require.js.

Sometimes we needed code to run in one breakpoint but not another. For example, there's no need to load phone-specific mustache templates if the user is on a desktop, or to initialise the basement navigation on a desktop since it's only visible at tablet size or lower.

We built our own breakpoint notifier around the native matchMedia API so we could check the breakpoint the browser was currently in and fire events when the breakpoint changed. The latter is useful if you need to do something like initialise the basement when the user resizes their desktop browser window to be small enough to warrant it.

A native matchMedia check may look like:

1. if (window.matchMedia("(max-width: 603px)").matches) { /* window is less than 603px wide */ }

With our wrapper, you define your breakpoints:

1. media({

2. 'phone'  : 'all and (max-width: 603px)',

3. 'desktop': 'all and (min-width: 1025px)',

4. 'tablet' : 'all and (min-width: 604px) and (max-width: 1024px)'

5. });

Then you can do a few different operations with it, including a basic boolean check:

1. if (media.is('phone')) { /* window is less than 603px wide */ }

Running code automatically when a certain breakpoint matches:

1. media.on('phone', function(isPhone) {

2. this.requestView( isPhone ? 'phone' : 'desktop' );

3. });

Or running code when you enter or leave a breakpoint:

1. media.on('tablet:enter', initializeBasementNavigation);

2. media.on('phone:exit', stopListenForResize);

With the breakpoint values in sync between the CSS and JS, the end result makes for a seamless transition between breakpoints and optimised code execution times.

Test responsive content on real devices

We started by testing the phone and tablet code by resizing our windows up and down in a desktop browser, in the iOS simulator and on our personal iPhone 5s. We were feeling pretty good about it until one of the developers pulled the site up on his older Android and pointed out how sluggish it performed and how clunky it was to use. It was a far cry from what we'd seen up to that point.

We immediately gathered up a list of the most popular devices (both generally speaking and as reported by Google Analytics) and bought a bunch of contract-free phones and tablets so we could do some real-world testing.

Real-world device testing

Tools like weinre and Adobe Edge Inspect make it easy to view, inspect and debug your content across devices. If you don't have the devices at hand, you may have luck with groups like Open Device Lab, who have started a grassroots movement establishing physical locations around the world for web and app developers to go to use a shared community pool of devices.

In our device testing, we were surprised to find quirks on some Android devices in places where it worked fine in others, some critical IE bugs on Windows Phones, varying user experience issues and performance differences across the board. No two ways about it, you have to test on real devices.

Sweat the small stuff

We worked hard to fine tune the details and usability of every breakpoint so that a user would have the best experience possible no matter what device they used (which is also why testing on real devices proved to be so important and valuable).

We tweaked box-shadows and border-radius values for better performance on desktop, and removed many of them for phone and tablet views. Chrome Canary has several amazing tools for gathering performance metrics, which will help you figure out your problem areas and measure the impact of your optimisations.

We spent time making sure that hit areas on smaller screens were big enough to be easy to tap and that our hover and active states made sense for a tap as well as a mouse. We got rid of WebKit's obtrusive transparent-black tap highlight color by setting the following code on tappable elements that had our own touch style:

1. -webkit-tap-highlight-color: transparent;

We also solved a bit of flickering on iOS and Android devices by enabling hardware acceleration on specific elements using:

1. -webkit-backface-visibility: hidden;

2. -webkit-transform: translateZ(0);

We figured that we'll never use a fixed position element on a phone or tablet ever again. The original intent was for the toolbars at the top of the screen to be fixed at every breakpoint. We found out pretty quickly that, in practice, fixed position elements are sluggish and choppy while scrolling on handheld devices, and also didn't play well with our CSS-transformed basement navigation implementation. We opted to get rid of our incredibly useful (but horribly performing) fixed-position toolbars from the phone and tablet breakpoints in favour of a less stilted scrolling experience.

Phone view with performance optimisations, without fixed-position elements

Conclusion

Ultimately, we were pleased with the final result and came out with a ton more knowledge than we started with. We carry these lessons through every new responsive project we work on. We're always learning something new along the way, whether that's a technique, a trick, a tool, or something else.

Responsive web development is still fairly new in the grand scheme of things, and we're always experimenting and testing new and better ways of doing things.

How do you build your responsive sites? Do you have any tips for retrofitting, or a better way to handle responsive code? Let us know in the comments below!

原文链接：http://www.netmagazine.com/features/how-behance-went-responsive-sass-and-requirejs （本内容由互联网资料整理而成）

异步编程：When.js快速上手

前些天我在团内做了一个关于AngularJS的分享。由于AngularJS大量使用Promise，所以我把基于Promise的异步编程也一并介绍了下。很多东西都是一带而过，这里再记录下。

AngularJS内置的是Kris Kowal的Q框架，我介绍的是自己用得更多的cujoJS的when.js，两者都是Promises/A规范的实现。when.js很小，压缩后只有数kb，gzip后的大小几乎可以忽略。在Node和浏览器环境里都可以使用when.js，唯一需要注意的是：在浏览器使用时，要先加几行代码，再引入js文件。

首先，我们看一小段代码（在浏览器中预览）：

var getData = function(callback) {
$.getJSON(api, function(data){
callback(data[0]);
});
}

var getImg = function(src, callback) {
var img = new Image();

img.onload = function() {
callback(img);
};

img.src = src;
}

var showImg = function(img) {
$(img).appendTo($('#container'));
}

getData(function(data) {
getImg(data, function(img) {
showImg(img);
});
});

这段代码完成了三个任务：1)获取数据；2)加载图片；3)显示图片，其中，任务1和2是异步，3是同步，使用的是最常见的callback机制来处理异步逻辑，好处是浅显易懂，缺点是强耦合、不直观、处理异常麻烦等等。

另外一种常见的实现异步编程的方案是事件监听器，例如使用QWrap的CustEvent，让任务成功时fireEvent，那么注册了这个Event的监听器就可以收到这个事件，并收到事件传递过来的数据，Dom标准事件也是采用的这种形式。这种方案也很好理解，代码从略。事件监听可以解耦，可以绑定任意多个监听器，但是依然不直观，而且事件发生之后再绑定的监听器也得不到触发。

我们尝试用when.js改写下这段代码（在浏览器中预览）：

var getData = function() {
var deferred = when.defer();

$.getJSON(api, function(data){
deferred.resolve(data[0]);
});

return deferred.promise;
}

var getImg = function(src) {
var deferred = when.defer();

var img = new Image();

img.onload = function() {
deferred.resolve(img);
};

img.src = src;

return deferred.promise;
}

var showImg = function(img) {
$(img).appendTo($('#container'));
}

getData()
.then(getImg)
.then(showImg);

看最后三行代码，是不是一目了然，非常的语义化？来看下改写后的任务1、2多了些什么：

var deferred = when.defer();

定义了一个deferred对象。

deferred.resolve(data);

在异步获取数据完成时，把数据作为参数，调用deferred对象的resolve方法。

return deferred.promise;

返回了deferred对象的promise属性。

在Promises/A规范中，每个任务都有三种状态：默认(pending)、完成(fulfilled)、失败(rejected)。

- 默认状态可以单向转移到完成状态，这个过程叫resolve，对应的方法是deferred.resolve(promiseOrValue)；

- 默认状态还可以单向转移到失败状态，这个过程叫reject，对应的方法是deferred.reject(reason)；

- 默认状态时，还可以通过deferred.notify(update)来宣告任务执行信息，如执行进度；

- 状态的转移是一次性的，一旦任务由初始的pending转为其他状态，就会进入到下一个任务的执行过程中。

有人可能会觉得奇怪：改变任务状态的resolve和reject方法是定义在deferred对象上，但最后返回的却是deferred的promise属性。这么做一是因为规范就是这么定的，二是可以防止任务状态被外部改变。

then有三个参数，分别是onFulfilled、onRejected、onProgress，通过这三个参数，就可以指定上一个任务在resolve、reject和notify时该如何处理。例如上一个任务被resolve(data)，onFulfilled函数就会被触发，data作为它的参数；被reject(reason)，那么onRejected就会被触发，收到reason。任何时候，onFulfilled和onRejected都只有其一可以被触发，并且只触发一次；onProgress顾名思义，每次notify时都会被调用。下面是reject和notify的用法（在浏览器中预览）：

function run() {
var deferred = when.defer();
var start = 1, end = 100;

(function() {
if(start <= end) {
deferred.notify(start++);
setTimeout(arguments.callee, 50);
} else {
deferred.reject('time out!');
}
})();

return deferred.promise;
}

run().then(undefined,
function(reason) {
alert(reason);
}, function(s) {
document.getElementById('output').innerHTML = s + '%';
}
);

then会传递错误，也就是说有多个任务串行执行时，我们可以只在最后一个then定义onRejected。只定义了onRejected的then等同于otherwise，也就是说 otherwise(onRejected) 是 then(undefined, onRejected) 的简便写法。

then会在try..catch..的包裹之下执行任务，所以任务的异常都会被when.js捕获，当做失败状态处理，类似这样：

try {
...
} catch (e) {
deferred.reject(e);
}

在任务状态改变之后再then，依然可以正常工作，后续任务会立刻执行。如果要在多个任务最后做cleanup工作，而不管之前的任务成功与否，可以用ensure方法。它只接受一个参数onFulfilledOrRejected，始终会执行。另外when.js还有一个always方法，即将废弃，建议大家不要使用。

回到上面加载图片的场景，如果把任务2变为：加载多张图片，全部完成后再执行任务3。这时候需要用到when.all，when.all接受一个promise数组，返回promise，这个promise会在promise数组中每一个promise都resolve之后再resolve。说起来拗口，看代码就明白了（在浏览器中预览）：

var getData = function() {
var deferred = when.defer();

$.getJSON(api, function(data){
var data = data.slice(0, 3);
deferred.resolve(data);
});

return deferred.promise;
}

var getImg = function(src) {
var deferred = when.defer();

var img = new Image();

img.onload = function() {
deferred.resolve(img);
};

img.src = src;

return deferred.promise;
}

var showImgs = function(imgs) {
$(imgs).appendTo($('#container'));
}

var getImgs = function(data) {
var deferreds = [];
for(var i = 0; i < data.length; i++) {
deferreds.push(getImg(data[i]));
}
return deferreds;
}

when.all(getData().then(getImgs)).then(showImgs);

如果我们只是想把一个promise数组挨个执行一遍，可以用when.settle：

var promise1 = function() {
var deferred = when.defer();
setTimeout(function() {
deferred.reject('A');
}, 2000);
return deferred.promise;
};

var promise2 = function() {
var deferred = when.defer();
setTimeout(function() {
deferred.resolve('B');
}, 2000);
return deferred.promise;
};

when.settle([promise1(), promise2()]).then(function(result) {
console.log(result); /*
[{"state":"rejected","reason":"A"},
{"state":"fulfilled","value":"B"}] */
});

有时候，我们需要引入任务竞争机制，例如从一批cdn中找到最快的那个，when.any就派上用场了，when.any接受promise数组，在其中任何一个resolve后就接着执行后续任务了。如果要在一批promise中某几个resolve后执行后续任务，可以用when.some，它比when.any多一个howMany的参数。

Promise给异步编程代码带来了巨大的方便，从此我们可以更专注单个任务的实现，promise会很好的替我们解决任务调度问题。when.js提供的功能远远不止本文提到的这些，有兴趣的同学可以前往官方api文档了解更多。

本文链接：http://www.imququ.com/post/promises-when-js.html

--EOF--

原文链接：http://www.imququ.com/post/promises-when-js.html （本内容由互联网资料整理而成）

eval() isn’t evil, just misunderstood

In all of JavaScript, I’m not sure there is a more maligned piece than eval(). This simple function designed to execute a string as JavaScript code has been the more source of more scrutiny and misunderstanding during the course of my career than nearly anything else. The phrase “eval() is evil” is most often attributed to Douglas Crockford, who has stated[1]:

The eval function (and its relatives, Function, setTimeout, and setInterval) provide access to the JavaScript compiler. This is sometimes necessary, but in most cases it indicates the presence of extremely bad coding. The eval function is the most misused feature of JavaScript.

Since Douglas hasn’t put dates on most of his writings, it’s unclear whether he actually coined the term as an article in 2003[2] also used this phrase without mentioning him. Regardless, it has become the go-to phrase for anyone who sees eval() in code, whether or not they really understand it’s use.

Despite popular theory (and Crockford’s insistence), the mere presence of eval() does not indicate a problem. Using eval() does not automatically open you up to a Cross-Site Scripting (XSS) attack nor does it mean there is some lingering security vulnerability that you’re not aware of. Just like any tool, you need to know how to wield it correctly, but even if you use it incorrectly, the potential for damage is still fairly low and contained.

Misuse

At the time when “eval() is evil” originated, it was a source of frequent misuse by those who didn’t understand JavaScript as a language. What may surprise you is that the misuse had nothing to do with performance or security, but rather with not understanding how to construct and use references in JavaScript. Suppose that you had several form inputs whose names contained a number, such as “option1″ and “option2″, it was common to see this:

function isChecked(optionNumber) {
return eval("forms[0].option" + optionNumber + ".checked");
}

var result = isChecked(1);

In this case, the developer is trying to write forms[0].option1.checked but is unaware of how to do that without using eval(). You see this sort of pattern a lot in code that is around ten years old or older as developers of that time just didn’t understand how to use the language properly. The use of eval() is inappropriate here because it’s unnecessary not because it’s bad. You can easily rewrite this function as:

function isChecked(optionNumber) {
return forms[0]["option" + optionNumber].checked;
}

var result = isChecked(1);

In most cases of this nature, you can replace the call to eval() by using bracket notation to construct the property name (that is, after all, one reason it exists). Those early bloggers who talked about misuse, Crockford included, were mostly talking about this pattern.

Debugability

A good reason to avoid eval() is for debugging purposes. Until recently, it was impossible to step into eval()ed code if something went wrong. That meant you were running code into a black box and then out of it. Chrome Developer Tools can now debug eval()ed code, but it’s still painful. You have to wait until the code executes once before it shows up in the Source panel.

Avoiding eval()ed code makes debugging easier, allowing you to view and step through the code easily. That doesn’t make eval() evil, necessarily, just a bit problematic in a normal development workflow.

Performance

Another big hit against eval() is it’s performance impact. In older browsers, you encountered a double interpretation penalty, which is to say that your code is interpreted and the code inside of eval() is interpreted. The result could ten times slower (or worse) in browsers without compiling JavaScript engines.

With today’s modern compiling JavaScript engines, eval() still poses a problem. Most engines can run code in one of two ways: fast path or slow path. Fast path code is code that is stable and predictable, and can therefore be compiled for faster execution. Slow path code is unpredictable, making it hard to compile and may still be run with an interpreter[3]. The mere presence of eval() in your code means that it is unpredictable and therefore will run in the interpreter – making it run at “old browser” speed instead of “new browser” speed (once again, a 10x difference).

Also of note, eval() makes it impossible for YUI Compressor to munge variable names that are in scope of the call to eval(). Since eval() can access any of those variables directly, renaming them would introduce errors (other tools like Closure Compiler and UglifyJS may still munge those variables – ultimately causing errors).

So performance is still a big concern when using eval(). Once again, that hardly makes it evil, but is a caveat to keep in mind.

Security

The trump card that many pull out when discussing eval() is security. Most frequently the conversation heads into the realm of XSS attacks and how eval() opens up your code to them. On the surface, this confusion is understandable, since by it’s definition eval() executes arbitrary code in the context of the page. This can be dangerous if you’re taking user input and running it through eval(). However, if you’re the input isn’t from the user, is there any real danger?

I’ve received more than one complaint from someone over a piece of code in my CSS parser that uses eval()[4]. The code in question uses eval() to convert a string token from CSS into a JavaScript string value. Short of creating my own string parser, this is the easiest way to get the true string value of the token. To date, no one has been able or willing to produce an attack scenario under which this code causes trouble because:

1. The value being eval()ed comes from the tokenizer.

2. The tokenizer has already verified that it’s a valid string.

3. The code is most frequently run on the command line.

4. Even when run in the browser, this code is enclosed in a closure and can’t be called directly.

Of course, since this code has a primary destination of the command line, the story is a bit different.

Code designed to be used in browsers face different issues, however, the security of eval() typically isn’t one of them. Once again, if you are taking user input and passing it through eval() in some way, then you are asking for trouble. Never ever do that. However, if your use of eval() has input that only you control and cannot be modified by the user, then there are no security risks.

The most common attack vector cited these days is in eval()ing code that is returned from the server. This pattern famously began with the introduction of JSON, which rose in popularity specifically because it could quickly be converted into a JavaScript by using eval(). Indeed, Douglas Crockford himself used eval() in his original JSON utility due to the speed with which it could be converted. He did add checks to make sure there was no truly executable code but the implementation was fundamentally eval().

These days, most use the built-in JSON parsing capabilities of browsers for this purpose, though some still fetch arbitrary JavaScript to execute via eval() as part of a lazy-loading strategy. This, some argue, is the real security vulnerability. If a man-in-the-middle attack is in progress, then you will be executing arbitrary attacker code on the page.

The man-in-the-middle attack is wielded as the ever-present danger of eval(), opening the security can of worms. However, this is one scenario that doesn’t concern me in the least, because anytime you can’t trust the server you’re contacting means any number of bad things are possible. Man-in-the-middle attacks can inject code onto the page in any number of ways:

1. By returning attacker-controlled code for JavaScript loaded via <script src="">.

2. By returning attacker-controlled code for JSON-P requests.

3. By returning attacker-controlled code from an Ajax request that is then eval()ed.

Additionally, such an attack can easily steal cookies and user data without altering anything, let alone the possibility for phishing by returning attacker-controlled HTML and CSS.

In short, eval() doesn’t open you up to man-in-the-middle attacks any more than loading external JavaScript does. If you can’t trust the code from your server then you have much bigger problems than an eval() call here or there.

Conclusion

I’m not saying you should go run out and start using eval() everywhere. In fact, there are very few good use cases for running eval() at all. There are definitely concerns with code clarity, debugability, and certainly performance that should not be overlooked. But you shouldn’t be afraid to use it when you have a case where eval() makes sense. Try not using it first, but don’t let anyone scare you into thinking your code is more fragile or less secure when eval() is used appropriately.

References

Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.

You can leave a response, or trackback from your own site.

原文链接：http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood （本内容由互联网资料整理而成）

未知高度多行文本垂直居中

近日，微博上有朋友比较纠结未知高度的文本垂直居中问题。这个和「未知高度图片垂直居中」有些类似，但是有一些细节需要注意。dmc上海云路网络科技有限公司

这里有之前写的一个未知宽高对话框的垂直居中（拖动改变大小看是不是依然居中？），只不过对话框是相对于 viewport（视口）居中的，这里的文字需要的是相对于容器垂直居中。dmc上海云路网络科技有限公司

拿到这样的需求时，先不要想着如何兼容 IE6/7。先想想文字垂直居中靠什么属性？vertical-align: middle 对吧，好的，自然也就联系到了可爱的 inline-block。dmc上海云路网络科技有限公司

主要的代码如下，Demo：dmc上海云路网络科技有限公司

<body>dmc上海云路网络科技有限公司
<div class=”box”>dmc上海云路网络科技有限公司
<p class=”text”>dmc上海云路网络科技有限公司
多行文本未知高度垂直居中-by 一丝多行文本未知高度垂直居中-by 一丝多行文本未知高度垂直居中-by 一丝dmc上海云路网络科技有限公司
</p>dmc上海云路网络科技有限公司
</div>dmc上海云路网络科技有限公司

dmc上海云路网络科技有限公司

.box:before{dmc上海云路网络科技有限公司
content: ‘我是那个备胎元素’;dmc上海云路网络科技有限公司
display: inline-block;dmc上海云路网络科技有限公司
vertical-align: middle;dmc上海云路网络科技有限公司
width: 0;dmc上海云路网络科技有限公司
height: 100%;dmc上海云路网络科技有限公司
}dmc上海云路网络科技有限公司
.text{dmc上海云路网络科技有限公司
display: inline-block;dmc上海云路网络科技有限公司
font-size:16px;dmc上海云路网络科技有限公司
vertical-align: middle;/* 保证文字垂直居中 */dmc上海云路网络科技有限公司
}dmc上海云路网络科技有限公司

vertical-align的对齐是需要有参照物的，那么box 容器通过 before 生成一个高度 100% 的「备胎」，他的高度和容器的高度是一致的，相对于「备胎」垂直居中，在视觉上表现出来也就是相对于容器垂直居中了。让我们一起来试试。dmc上海云路网络科技有限公司

1.可以发现按照我们的思路，文字换行了，这是肿么了？Demo：dmc上海云路网络科技有限公司

dmc上海云路网络科技有限公司

2.别急，既然「备胎」占用了本来文字的位置，那我来用 margin 负值试试，Demo。dmc上海云路网络科技有限公司

好像还是不行捏？凌乱鸟~dmc上海云路网络科技有限公司

还记得《inline-block 前世今生》中我们说到的 inline-block 元素间会产生空隙，难道是这货在捣乱？dmc上海云路网络科技有限公司

3.还记得之前怎么处理空隙的吗？font-size:0 ！试试看dmc上海云路网络科技有限公司

dmc上海云路网络科技有限公司

4.柳暗花明又一村，世界和谐了，那么最后只要隐藏掉 before 生成的内容即可，请看最终 Demo。dmc上海云路网络科技有限公司

最后，记得把「content 」中的备胎去掉哦！兼容IE8+，Webkit，Firefox，Opera。（不要问我IE6怎么搞了，思路最重要）dmc上海云路网络科技有限公司

看看高度改变时的动画演示：dmc上海云路网络科技有限公司

dmc上海云路网络科技有限公司

诚然，以上是一种非常  Hack 的解决方案。本质上还是应该由 Flex 来解决，在面对这样的需求时候，思路很重要。关于CSS 3 对齐规范在这里《CSS Box Alignment Module Level 3》。dmc上海云路网络科技有限公司

以上dmc上海云路网络科技有限公司
一丝dmc上海云路网络科技有限公司

转载请注明出处：http://www.iyunlu.com/view/css-xhtml/77.htmldmc上海云路网络科技有限公司

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

Creating iOS 7 effects with CSS3: translucency and transparency

So, the iOS 7 Beta has been out for a couple of weeks, and while the opinions over whether it’s amazing, terrible, too much like Android or Windows Phone continues, it’s fair to say that, as Maxine observed a week ago here at Web Directions:

it’s hard to imagine today’s release still not having a massive impact on the design of not just iPhone apps, but apps developed for any platform, including the web, and web sites themselves more generally

So, we thought we’d take a look at some of the more notable design features from the beta, and how you might implement them using web technology. Note that while we’re part of the iOS Developer Program, we’re basing these observations purely on Apple’s publicly released images and videos.

In this first instalment, we’ll look at the use of translucency in the interface. Here’s what we are going to build: there’s a bit more to it than you might think!

Transparency and Translucency

While the word on the street in advance of the release was that Apple would be adopting a “flat” style of UI with iOS7, as has become popular on the web and on various platforms such as Android, Windows Phone, and Windows 8, Apple went out of their way to emphasise the concept of “Depth”. One of the key ways they’ve brought a depth to the new OS is through translucency.

The translucent background of the Control Center allows the layers behind to remain present (Image © Apple)

Now, you might be wondering what the fuss is, after all, we’ve had transparency in interfaces for years.

But translucency is not necessarily transparency. For an object to be transparent, any light passing through it should not be dispersed, so the image of something behind it remains as sharp as if the transparent object weren’t there.

We’re probably most used to semi-transparency in UIs, where an image behind another is darkened, but the definition of that object is not lowered. Here’s a very simple example we’d all be familiar with.

Here we use semi-transparency to allow the image behind our element to “shine through” its background.

We could do this in a couple of ways on the web. We could use the CSS property opacity. This as you almost certainly know, takes a value between 0 and 1, where the lower the value, the more transparent an element is (opacity is the opposite of translucency, and we’ll see in a moment why the property arguably should have been called transparency. So, we might use this CSS

h2 {
opacity: .3
}

But the problem is, this applies to the entire element (not just the background), as well as all of its descendant elements. We can’t even do this

h2 * {
opacity: 1
}

to “turn off” opacity for descendent elements. Once opacity is set, it’s on for the element, and all its descendants.

So opacity certainly isn’t what we always want for creating transparency in our designs. We could use a PNG image, with alpha channel transparency as a background-image for the element, but CSS provides a simpler, more generalizable way to do this, using RGBa colors. RGBa colors are like regular RGB colors, but also take an opacity value between 0, and 1 as a fourth parameter. As an example, the effect achieved above uses rgba(255, 255, 255, .8), a white background color with an opacity of 80% (or in other words, 20% transparency).

Note how the image behind is still sharp, its edges aren’t blurred. Now take a look at Apple’s Control Center above. The icons of the homescreen it overlays are ‘smudged’ as if seen through frosted glass. This is not simply transparency as we know it on the web—it’s translucency. Translucency is essentially a superset of transparency. Where with transparency light is not dispersed as it passes through the object, with translucency, it may be. Think of it like looking through frosted glass. Now, how can we do this with web technologies?

Translucency

To tell the truth, there’s no easy way to achieve this effect right now in the browser. There are a number of ways of emulating aspects of the effect, with varying degrees of support. We’ll take a look at some of these now.

CSS Filters

The closest we’re likely to get right now are CSS filters. Not to be confused with either Internet Explorer’s old, non standard, and no longer supported in IE10 filter property, or the various filter techniques we used to rely on to hide CSS from various browsers in the good old days.

At present, this technique is only supported in modern webkit based browsers, using the -webkit- vendor prefix, and on iOS6+ and Blackberry 10+ (though not the standard Android browser). The good thing is that it falls back nicely for browsers that don’t support CSS filters.

A filter is a “graphical operation that is applied to an element as it is drawn into the document”. Filters can be quite simple, and there are a small number of “canned” filters for achieving common effects such as blurring an image. There are also more complex approaches to creating filters, all the way up to creating shaders in a shader language.

Today we’re just going to use the basic “blur” effect (other basic effects include grayscale, sepia, contrast and invert). We use these effects by using the filter property, which takes a function as its value. In this case, the blur function, which takes a value specifying how blurry the effect should be.

Here, we’ll blur an element with the id of “homescreen”

#homescreen {
-webkit-filter: blur(10px);
filter: blur(10px);
}

Which will produce a result rather like this (before on the left, after on the right)

Using the blur filter to blur an element

So, this looks perfect! Why don’t we use this technique as follows:

- We’ll have a foreground “Control Center” element, which contains the controls we want to present to the user

- Behind this, with the same dimensions, we’ll have another element, blurred using the blur filter, as the “background” for the controls

- All this in front of our homescreen element. Note that this time we won’t blur the homescreen as we just did, rather the “background” of the foreground element.

Schematically, this is what we’re doing

Creating the blurred effect

And here’s what we get

Apply the blur to the background element

Which isn’t quite what we expected. Why? Well, the blur effect only applies to the element itself, so it’s not affecting the elements shining through the background of the blurred element. We’ll have to apply the blur to the homescreen element itself. Let’s do that and see what happens.

Apply the blur to the element behind the background

This is a lot closer to what we want. Behind the foreground element, we have our homescreen element blurred. But, we have one big stumbling block—we’ve also blurred the part of the homescreen that’s peeking over the top. Not what we want. This is a limitation of the basic CSS filters, they apply to the whole of an element, not just parts of them.

So, we’re going to have to come up with a hack. Here’s my thinking. Firstly, we no longer need our fake background element. We’ll just apply a semi-transparent background color using rgba to the control panel element itself. But here’s how I’m going to fake the only-partly-blurred homescreen element. We’re going to clone the element. Then we’ll apply the blur to the cloned homescreen, but not the original. Lastly, we only want part of the cloned element to show, not all of it. Hmm, how to achieve this all? Let’s position the cloned element behind the “real” homescreen element.

Here’s how we might visualize that

Emulating the blur with a cloned element

And let’s see how that works in the browser

Our blurred effect in the browser

Which is starting to get there. It’s not a general solution, and it’s certainly less than ideal having to clone an existing element. But for now it’s a start.

Animating the translucent overlay

Just to show this is not a completely hacked up solution, we can even animate the effect of the overlay sliding up over the homescreen, and down when no longer needed. We’ll do this using a tiny bit of JavaScript, and CSS transitions for the animation itself.

Our JavaScript will simply be

- set the height of the ‘real’ homescreen element to 20%, and top of the Control Center element to 20% to slide the control center element up

- set the height of the ‘real’ homescreen element to 100% and the top of the Control Center element to 100% to slide the control center element down

You can see this in action here.

Notice that we don’t have to change the cloned homescreen element at all. It just sits there quietly behind the ‘real’ homescreen. Here’s more or less all the JavaScript we need to do this

if(slidingUp === true) {
//sliding the ControlCenter up
homeScreen.style.height = "20%"
controlCenter.style.top = "20%"
}

else {
//sliding the ControlCenter down
homeScreen.style.height = "100%"
controlCenter.style.top = "100%"
}

Alternatively, we could create two classes, such as “up” and “down”, and simply change the class of each element, with the actual styling taking place in our style sheet. This better separates presentation from behavior.

Now for the animation, we just have two simple CSS transitions, one for the height property of the homescreen element

transition: height .75s

And one for the top property of the Control Center element

transition: top .75s

You’ll want to add a -webkit- prefixed version as well for some webkit browsers, including Android and iOS. Of course, to really animate this in the most lifelike way possible for touch devices, you’ll want to make the speed of the animation a function of how quickly the user ‘flicked’ the Control Center up or down. But hopefully this demonstrates how we can implement an animatable, translucent overlay effect, using CSS filters. It’s also backwards compatible, as browsers which don’t support filters will show the semi-transparent overlay, without the blurring of the homescreen element which is behind it.

Caveats

This article is not meant to provide a bullet-proof way of creating translucent effects. Rather, it’s an exploration of the various features of CSS are available to create an effect we’re likely to be seeing quite a lot of on the web and elswhere in coming months. The properties we’ve looked at here will work mostly in webkit browsers, with the advantage that they fall back nicely for browsers which don’t as yet support CSS Filters.

There is in fact another way to create the translucent effect, using SVG filters, that is more widely supported, and also does away with the need for our cloned background element. Sadly, at present, while SVG filters are quite well supported in modern browsers, this technique won’t actually work in most browsers.

More Translucency

There’s other uses of translucency in iOS 7 that present additional challenges in terms of implementation using web technologies, which we’ll explore soon in part II.

Further reading and watching

Technologies covered in this post

- CSS opacity

- CSS filters

- rgba colors

- CSS transitions

Browser Support via Can I Use

- CSS filters

- CSS transitions

原文链接：http://www.webdirections.org/blog/creating-ios-7-effects-with-css3-translucency-and-transparency/ （本内容由互联网资料整理而成）

Static Memory Javascript with Object Pools

Introduction

So you get an email saying how your web-game / web-app is performing badly after a certain amount of time, you dig through your code, don’t see anything that stands out, until you open up Chrome’s memory performance tools, and see this:

One of your co-workers chuckles, because they realize that you’ve got a memory-related performance problem.

In the memory graph view, this saw-tooth pattern is very telling about a potentially critical performance problem. As your memory usage grows, you’ll see the chart area also grow in the timeline capture. When the chart dips suddenly, it’s an instance when the Garbage Collector has run, and cleaned up your referenced memory objects.

In a graph like this, you can see that there’s lots of Garbage Collection events occurring, which can be harmful to your web-apps’ performance. This article will talk about how to take control of your memory usage, reducing the impact on your performance.

Garbage collection and performance costs

JavaScript’s memory model is built on a technology known as a Garbage Collector. In many languages, the programmer is directly responsible for allocating and freeing memory from the system’s Memory Heap. A Garbage Collector system, however, manages this task on behalf of the programmer, meaning that objects aren’t directly freed from memory when the programmer dereferences it, but rather at a later time when the GC’s heuristics decide that it would be beneficial to do so. This decision process requires that the GC execute some statistical analysis on active and inactive objects, which takes a block of time to perform.

In computer science, Garbage Collector (GC) is a form of automatic memory management. The garbage collector attempts to reclaim garbage, or memory occupied by objects that are no longer in use by the program.

Garbage collection is often portrayed as the opposite of manual memory management, which requires the programmer to specify which objects to deallocate and return to the memory system

The process in which a GC reclaims memory is not free, it usually cuts into your available performance by taking a block of time to do its work; alongside that, the system itself makes the decision when to run. You have no control over this action, a GC pulse can occur at any time during code execution, which will block code execution until it’s completed. The duration of this pulse is generally unknown to you; will take some amount of time to run, depending on how your program is utilizing memory at any given point.

High performance applications rely on consistent performance boundaries to ensure a smooth experience for users. Garbage collector systems can short circuit this goal, as they can run at random times for random durations, eating into the available time that the application needs to meet its performance goals.

Reduce Memory Churn, Reduce Garbage Collection taxes

As noted, a GC pulse will occur once a set of heuristics determines that there are enough inactive objects that a pulse would be beneficial. As such, the key to reducing the amount of time that the Garbage Collector takes from your application lies in eliminating as many cases of excessive object creation and release as you can. This process of creating/freeing object frequently is called “memory churn”. If you can reduce memory churn during the lifetime of your application, you also reduce the amount of time GC takes from your execution. This means you need to remove / reduce the number of created and destroyed objects, effectively, you have to stop allocating memory. This process will move your memory graph from this :

to this:

In this model, you can see that the graph no longer has a sawtooth like pattern, but rather grows a great deal in the beginning, and then slowly increases over time. If you’re running into performance problems due to memory churn, this is the type of graph you’ll want to create.

Moving towards static-memory JavaScript

Static Memory JavaScript is a technique which involves pre-allocating, at the start of your app, all the memory that will be needed for its lifetime, and managing that memory during execution as objects are no longer needed. We can approach this goal in a few simple steps:

1. Instrument your application to determine what the maximum number of required live memory objects (per type) are for a range of usage scenarios

2. Re-implement your code to pre-allocate that maximum amount, and then manually fetch/release them rather than going to main memory.

In reality, accomplishing #1 requires us to do a bit of #2, so let’s start there.
Object Pools

In simple terms, object pooling is the process of retaining a set of unused objects which share a type. When you need a new object for your code, rather than allocating a new one from the system Memory Heap, you instead recycle one of the unused objects from the pool. Once the external code is done with the object, rather than releasing it to main memory, it is returned to the pool. Because the object is never dereferenced (aka deleted) from code it won’t be garbage collected. Utilizing object pools puts control of memory back in the hands of the programmer, reducing the influence of the garbage collector on performance.

Since there’s a heterogenous set of object types that an application maintains, proper usage of object pools requires you to have one pool per type that experiences high-churn during your application’s runtime.

var newEntity = gEntityObjectPool.allocate();
newEntity.pos = {x: 215, y: 88};

//..... do some stuff with the object that we need to do

gEntityObjectPool.free(newEntity); //free the object when we’re done
newEntity = null; //free this object reference

For the large majority of applications, you’ll eventually hit some level-off in terms of needing to allocate new objects. Over multiple runs of your application, you should be able to get a great feel for what this upper limit is, and can pre-allocate that number of objects at the start of your application.

Pre-allocating objects

Implementing object pooling into your project will give you a theoretical maximum for the number of objects required during the runtime of your application. Once running your site through various testing scenarios, you can get a good sense of the types of memory requirements that will be needed, and can catalog that data somewhere, and analyze it to understand what the upper limits of memory requirements are for your application.

Then, in the shipping version of your app, you can set the initialization phase to pre-fill all the object pools to a specified amount. This act will push all the object initialization to the front of your app, and reduce the amount of allocations that occur dynamically during its execution.

function init() {
//preallocate all our pools.
//Note that we keep each pool homogeneous wrt object types
gEntityObjectPool.preAllocate(256);
gDomObjectPool.preAllocate(888);
}

The amount you choose has a great deal to do with the behavior of your application; sometimes the theoretical maximum isn’t the best option. For instance, choosing the average maximum may give you a smaller memory footprint for non power-users.

Far from a silver bullet

There’s a whole classification of apps in which static memory growth patterns can be a win. As fellow Chrome DevRel Renato Mangini points out however, there are a few drawbacks.

Conclusion

One of the reasons that JavaScript is ideal for the web relies on the fact it’s a fast, fun and easy language to get started with. This is mainly due to its low barrier to syntax restrictions and its handling of the memory issues on your behalf. You can code away and let it take care of the dirty work. However for high-performance web applications, like HTML5 games, the GC can often eat away at critically needed frame rate, reducing the experience for the end user. With some careful instrumentation and adoption of object pools, you can reduce this burden on your frame rate, and reclaim that time for more awesome things.

Source Code

There are lots of implementations of object pools floating around on the web, so I won’t bore you with yet another one. Instead, I’ll direct you to these, each of which has specific implementation nuances; which is important, considering that each application usage may have specific implementation needs.

References

原文链接：http://www.html5rocks.com/en/tutorials/speed/static-mem-pools/ （本内容由互联网资料整理而成）

Web Fonts and the Critical Path

This blog corresponds to my May 2013 talk @frontendlondon. The slides for that talk can be found on slideshare.

The story behind FOUT

CSS is justified critical due to the flash of unstyled content which would ensue if we deferred it. This is the main reason why web fonts are deemed critical to web pages: to avoid the flash of unstyled text which is then later repainted.

When font-face landed we had this new tool at our disposal. It was shiny, fancy and it brought with it its own challenges: namely that in certain browsers there would be a flash of the fallback font until the browser had finished downloading the resource. We had a problem and, as front end developers love to do, we set about to race to be the fastest to fix it.

Somewhere along that path it became a best practice to place web fonts on the critical path. If your site had a Flash of Unstyled Text it was considered a poor implementation of font-face. It still is, for that matter.

But how critical are web fonts?

How often do we stop to reconsider our best practices? We solve a problem but does it really benefit our users? Let’s talk about first world problems:

You’re on the london underground (we have free wifi at stations now) and you come across a link on twitter which looks interesting as you’re rocketing through the tunnel. You know that when you get to the station you have about 45 seconds to connect to the wifi, to hit the link, and for the content to load before you’re plunged back into the tunnel; instead you get a white screen because the site has put a 50k font on the critical path and you never get to read the content. At this point are web fonts critical to you as a user? Or would you have preferred the content straight up?

Another example, and one closer to home for me and the team at Lonely Planet, is that of internet cafes. You might be in Thailand trying to book a boat, transfer money, find a place to stay that night, and you’re sitting in an internet cafe sharing one DSL line with 50 other kids all playing online multiplayer games. You’re staring at white screens and invisible text. We’re forcing a design luxury on a user who just wants the content.

And those are just the first world problems.

The browser and the spec

I always advocate leveraging the browser to do the heavy lifting for you and we always try to avoid reimplementing browser features. This should be sound advice for most web developers. That said, you don’t always have to agree with browsers and their implementation.

With web fonts, browsers are forced to make a decision from two distinct options: block the render or repaint later. The spec leaves it wide open for implementation:

…user agents may render text as it would be rendered if downloadable font resources are not available or they may render text transparently with fallback fonts to avoid a flash of text using a fallback font.

In cases where the font download fails user agents must display text, simply leaving transparent text is considered non-conformant behavior.

As you would imagine, from a wide open spec like this, implementation is very varied:

Text rendered immediately then repainted later.

Invisible Text with a 3s Timeout

Invisible Text with no Timeout

Out of these, webkit is the only current implementation which is non-conformant. Firefox tries to hedge their bets with a clever timeout implementation but 3s is still a somewhat arbitrary number which is easily hit if you throttle your bandwidth even slightly. When that happens you’re hitting your users twice as hard with slower perceived speed and a flash of unstyled text. But at least the users will see the content eventually…

Webkit have been working on the timeout issue and how best to calculate where that threshold should fall. This is good progress but, as you can see from the below dates, we’re now four years into a decision:

https://bugs.webkit.org/show_bug.cgi?id=25207 ~ 2009 https://code.google.com/p/chromium/issues/detail?id=235303 ~ 2013

This may say more about the challenge than it does about priorities. There simply isn’t a correct answer that will satisfy all users: invisible text is considered a feature and a bug to many.

Alright I get it, but I still want to have fonts on my site.

So do I. Web fonts can look fantastic and should still be embraced as a great feature. What we need to work on is minimising their impact on the speed of the web.

Trimming the fat

Before you even have to think about font loading techniques you should first look at reducing the weight of the font by subsetting. This is the practice of removing superflous glyphs that you serve within the font. For example, we remove all the mathematical glyphs and accept that if they are required they will be served by the next font down in the stack. They will look different to their surrounding glyphs, if requested, but this is an edge case we are happy to deal with.

The savings for this kind of bespoke pruning will usually be fairly small. That said, if you are using an extended font and only serving characters in one language, there could be some really significant savings.

LP font before and after:

There is an open source program called FontForge (archaic but powerful) which can be used to achieve this, as well as commercial programs such as TypeTool, Glyphs and Glyphs mini.

It’s worth mentioning that there are generally legal requirements surrounding the modification of font files. Ensure that you check the terms and conditions of whichever foundry you are using before doing so.

Making the font work harder

If you have a design that requires heavy typography and liberal use of icons you might find performance optimisations in bundling the two together. Using one of the above programs you would be able to load your icons in vector format and place them in the private unicode area of your font.

By doing this you create a library of scalable, retina ready icons without the need for any extra requests.

The only downside to this approach I have found is it handcuffs you into coupling the same level of importance to your fonts as to your icons. If you decided that you wanted to progressively load your font after the page, the icons would come along for the ride.

Font Loading solutions

If you’re loading web fonts via a third party using JS you should be loading it asynchronously. This should really be a default setting as otherwise you’re creating a SPOF for your site. I would highly reccommend looking into the Google Web Font Loader and taking a look at these great slides by Richard Rutter on the subject.

If you’re self hosting there are a number of techniques available to your. Below are five different methods, the first two place the font on the critical path and block the rendering of the page whilst the latter ones showcase our options for deferring the font load.

1. Synchronous, external

@font-face {
font-family: 'MyWebFont';
src: url('webfont.eot'); /* IE9 Compat Modes */
src: url('webfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('webfont.woff') format('woff'), /* Modern Browsers */
url('webfont.ttf')  format('truetype'), /* Safari, Android, iOS */
url('webfont.svg#svgFontName') format('svg'); /* Legacy iOS */
}

This is your typical font-face loading technique. In this case you hand all the control to the browser and allow it to load the font using whichever technique they implement.

This example code is outputted by the FontSquirrel generator which is an invaluable tool for handling fonts cross-browser.

2. Synchronous, Inline

The support for .woff font files is approaching 100% these days, with only IE < 9 (.eot) and old Android (.ttf) requiring others.

Given that, and the ability to base64 encode woff files, we are capable of serving fonts inline to the majority of our users. Doing this means we can reduce the number of requests one further by combining the font with our css. This can be a serious win if latency is an issue for your users, but it comes with a couple of caveats:

1. Caching
If you’re deploying new revisions to your css regularly you’re going to be constantly causing your users to re-download an unchanged font. Not cool. To get around this you can split your css into two: rarely changed and often changed. For example you could bundle your font with your reset, your base styles, your abstractions and your header and footer styles which are likely to also remain unchanged.

2. Slower perceived speed
The big downside to the inline approach is you block the render of the entire chrome, not just the type you have styled. The user will see nothing but a white screen until the single asset has downloaded at which point the complete page will be rendered. Depending upon the latency of your users this approach can still end up painting to the screen faster than other approaches. You should probably avoid this technique if you are using web fonts in just a few places on your site.

The most important part of using this approach is ensuring that you don’t serve the woff to browsers that can’t render it. If your users are browsing your site on old version of Internet Explorer then the chances are they’re not too happy about it already; don’t punish them further by forcing them to download 30k + of assets they can’t use. You can handle this by simply using IE conditionals.

<!--[if (gt IE 8) | (IEMobile)]><!-->
<link href="common_core_with_base64.css" media="all" rel="stylesheet" type="text/css" />
<!--<![endif]-->

<!--[if (lt IE 9) & (!IEMobile)]>
<link href="common_core_without_base64.css" media="all" rel="stylesheet" type="text/css" />
<![endif]-->

3. Simple Asynchronous Loading

var f, x;

x = document.getElementsByTagName("script")[0];

f = window.document.createElement("link");

f.rel = "stylesheet";

f.href = "#{asset_path("woff.css")}";

window.setTimeout(function(){
x.parentNode.insertBefore(f, x);
},0)

This is the classic asynchronous script loader modified to be a stylesheet loader. With this approach you are guaranteeing a FOUT on the first load but on subsequent loads the font will be cached and there will be no FOUT.

This is the simplest way of taking the font off the critical path. In order to make this technique work well and minimise the impact of the repaint you need to ensure that you adjust the typographic treatment of the fallback font to closely match the web font. In order to do this you might want to add a class to the body after the font has loaded which you use to update the type treatment. This is a similar approach to how Google Web Font Loader works.

4. Asynchronous Loading with Local Storage

A similar approach to the one before, but one worth mentioning, is substituting Local Storage for the browser cache. This is a technique currently used by the Guardian on their responsive site and is validated by the theory that they can’t always trust the http cache on mobile to be available to them.

Essentially the technique is to check to see if the font is in Local Storage on load and, if so, inlcude it in the head in order to avoid any repaint. If it isn’t available in the cache then the font is loaded asynchronously and stored in Local Storage after checking whether or not there is enough free space. The type on the page is then repainted.

The only downside to this approach is the time taken to access Local Storage (minimal) and the fact that you are having to re-implement a browser feature. Still, it is a technique worth investigating if you have similar concerns.

https://github.com/guardian/frontend/blob/master/common/app/assets/javascripts/modules/fonts.js

5. Async & Defer

This is a neat solution proposed by Chris Coyier in his article on css-tricks (http://css-tricks.com/preventing-the-performance-hit-from-custom-fonts/) where the font is downloaded asynchronously but not rendered to the screen until the second page visit.

// ** Pseudo Ruby **

// HEADER
if fonts_are_cached do
<link href="woff.css" rel="stylesheet" />
end

// FOOTER
if !fonts_are_cached do
<script>
// Load in custom fonts
$.ajax({
url: '#{asset_path("woff.css")}',
success: function () {
// Set cookie
}
});
</script>
end

A cookie is used to determine whether or not to render the stylesheet inline or load it asynchronously further down the page.

What I like about this solution is that it eliminates the requirement for managing FOUT and forces you to not treat your fallback fonts as second class citizens. The downside to this approach is users who bounce straight from your site will download an asset that is never used so this technique should be used dependant upon your user behaviour.

It does raise the interesting question of how important a web font really is though: if you’re happy to serve the first view without one then is it really necessary at all?

The Future - Progressive Enhancement?

The issue of loading fonts really highlights the nuance of managing web performance. Rarely is there a holy grail solution to the problem; you need to balance the different performance costs and work out what is best for your user base. How much of your content is using fonts? How critical is that content? What’s the cost of a round trip?

In my opinion we need to stop thinking of web fonts as critical to the page and serve them only to users for whom it will enrich their experience. Making content unreadable for users on slow connections can’t be the sacrifice for other users not seeing a repaint. In order to come up with a real solution we need to be able to differentiate between the two groups.

At EdgeConf earlier this year there was a discussion around whether or not having access to the connection speed of the user would be beneficial, misused or even necessary. What would you use it for?

It could certainly be valuable in this situation, allowing us to only load fonts when we feel it would be in the user’s interest. Ideally this would not be a client-side solution.

If Client Hints were able to expose this information we could decide whether or not to include the font on the server side. Even better, we could send that font with a header which told the browser if the font should block the render or not. These are all wishful solutions though. In the meantime we may have to roughly determine the connection speed of the browser using timing APIs.

Progressive enhancement for web fonts does not need to be limited to performance issues either. There are other features we could be testing upon to determine whether or not to serve fonts: sub-pixel font rendering support, for example.

I would always favour a solution which leverages the browser where possible. Despite this, for the moment, if you want to control this part of your website’s performance you are going to have to work around the browser. Hopefully in the future we will have the ability to make better judgements using native capabilities, in the meantime we need to take a more thoughtful approach to including fonts on our web pages.

原文链接：http://ianfeather.co.uk/web-fonts-and-the-critical-path/ （本内容由互联网资料整理而成）

正则表达式30分钟入门教程

目录

跳过目录

本文目标

30分钟内让你明白正则表达式是什么，并对它有一些基本的了解，让你可以在自己的程序或网页里使用它。

如何使用本教程

最重要的是——请给我30分钟，如果你没有使用正则表达式的经验，请不要试图在30秒内入门——除非你是超人 :)

别被下面那些复杂的表达式吓倒，只要跟着我一步一步来，你会发现正则表达式其实并没有想像中的那么困难。当然，如果你看完了这篇教程之后，发现自己明白了很多，却又几乎什么都记不得，那也是很正常的——我认为，没接触过正则表达式的人在看完这篇教程后，能把提到过的语法记住80%以上的可能性为零。这里只是让你明白基本的原理，以后你还需要多练习，多使用，才能熟练掌握正则表达式。

除了作为入门教程之外，本文还试图成为可以在日常工作中使用的正则表达式语法参考手册。就作者本人的经历来说，这个目标还是完成得不错的——你看，我自己也没能把所有的东西记下来，不是吗？

清除格式 文本格式约定：专业术语 元字符/语法格式 正则表达式 正则表达式中的一部分(用于分析) 对其进行匹配的源字符串 对正则表达式或其中一部分的说明

隐藏边注 本文右边有一些注释，主要是用来提供一些相关信息，或者给没有程序员背景的读者解释一些基本概念，通常可以忽略。

正则表达式到底是什么东西？

字符是计算机软件处理文字时最基本的单位，可能是字母，数字，标点符号，空格，换行符，汉字等等。字符串是0个或更多个字符的序列。文本也就是文字，字符串。说某个字符串匹配某个正则表达式，通常是指这个字符串里有一部分（或几部分分别）能满足表达式给出的条件。

在编写处理字符串的程序或网页时，经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说，正则表达式就是记录文本规则的代码。

很可能你使用过Windows/Dos下用于文件查找的通配符(wildcard)，也就是*和?。如果你想查找某个目录下的所有的Word文档的话，你会搜索*.doc。在这里，*会被解释成任意的字符串。和通配符类似，正则表达式也是用来进行文本匹配的工具，只不过比起通配符，它能更精确地描述你的需求——当然，代价就是更复杂——比如你可以编写一个正则表达式，用来查找所有以0开头，后面跟着2-3个数字，然后是一个连字号“-”，最后是7或8位数字的字符串(像010-12345678或0376-7654321)。

入门

学习正则表达式的最好方法是从例子开始，理解例子之后再自己对例子进行修改，实验。下面给出了不少简单的例子，并对它们作了详细的说明。

假设你在一篇英文小说里查找hi，你可以使用正则表达式hi。

这几乎是最简单的正则表达式了，它可以精确匹配这样的字符串：由两个字符组成，前一个字符是h,后一个是i。通常，处理正则表达式的工具会提供一个忽略大小写的选项，如果选中了这个选项，它可以匹配hi,HI,Hi,hI这四种情况中的任意一种。

不幸的是，很多单词里包含hi这两个连续的字符，比如him,history,high等等。用hi来查找的话，这里边的hi也会被找出来。如果要精确地查找hi这个单词的话，我们应该使用\bhi\b。

\b是正则表达式规定的一个特殊代码（好吧，某些人叫它元字符，metacharacter），代表着单词的开头或结尾，也就是单词的分界处。虽然通常英文的单词是由空格，标点符号或者换行来分隔的，但是\b并不匹配这些单词分隔字符中的任何一个，它只匹配一个位置。

如果需要更精确的说法，\b匹配这样的位置：它的前一个字符和后一个字符不全是(一个是,一个不是或不存在)\w。

假如你要找的是hi后面不远处跟着一个Lucy，你应该用\bhi\b.*\bLucy\b。

这里，.是另一个元字符，匹配除了换行符以外的任意字符。*同样是元字符，不过它代表的不是字符，也不是位置，而是数量——它指定*前边的内容可以连续重复使用任意次以使整个表达式得到匹配。因此，.*连在一起就意味着任意数量的不包含换行的字符。现在\bhi\b.*\bLucy\b的意思就很明显了：先是一个单词hi,然后是任意个任意字符(但不能是换行)，最后是Lucy这个单词。

换行符就是'\n',ASCII编码为10(十六进制0x0A)的字符。

如果同时使用其它元字符，我们就能构造出功能更强大的正则表达式。比如下面这个例子：

0\d\d-\d\d\d\d\d\d\d\d匹配这样的字符串：以0开头，然后是两个数字，然后是一个连字号“-”，最后是8个数字(也就是中国的电话号码。当然，这个例子只能匹配区号为3位的情形)。

这里的\d是个新的元字符，匹配一位数字(0，或1，或2，或……)。-不是元字符，只匹配它本身——连字符(或者减号，或者中横线，或者随你怎么称呼它)。

为了避免那么多烦人的重复，我们也可以这样写这个表达式：0\d{2}-\d{8}。这里\d后面的{2}({8})的意思是前面\d必须连续重复匹配2次(8次)。

测试正则表达式

其它可用的测试工具:

- RegexBuddy

- Javascript正则表达式在线测试工具

如果你不觉得正则表达式很难读写的话，要么你是一个天才，要么，你不是地球人。正则表达式的语法很令人头疼，即使对经常使用它的人来说也是如此。由于难于读写，容易出错，所以找一种工具对正则表达式进行测试是很有必要的。

不同的环境下正则表达式的一些细节是不相同的，本教程介绍的是微软 .Net Framework 4.0 下正则表达式的行为，所以，我向你推荐我编写的.Net下的工具 正则表达式测试器。请参考该页面的说明来安装和运行该软件。

下面是Regex Tester运行时的截图：

现在你已经知道几个很有用的元字符了，如\b,.,*，还有\d.正则表达式里还有更多的元字符，比如\s匹配任意的空白符，包括空格，制表符(Tab)，换行符，中文全角空格等。\w匹配字母或数字或下划线或汉字等。

对中文/汉字的特殊处理是由.Net提供的正则表达式引擎支持的，其它环境下的具体情况请查看相关文档。

下面来看看更多的例子：

\ba\w*\b匹配以字母a开头的单词——先是某个单词开始处(\b)，然后是字母a,然后是任意数量的字母或数字(\w*)，最后是单词结束处(\b)。

好吧，现在我们说说正则表达式里的单词是什么意思吧：就是不少于一个的连续的\w。不错，这与学习英文时要背的成千上万个同名的东西的确关系不大 :)

\d+匹配1个或更多连续的数字。这里的+是和*类似的元字符，不同的是*匹配重复任意次(可能是0次)，而+则匹配重复1次或更多次。

\b\w{6}\b 匹配刚好6个字符的单词。

表1.常用的元字符

代码

说明

匹配除换行符以外的任意字符

匹配字母或数字或下划线或汉字

匹配任意的空白符

匹配数字

匹配单词的开始或结束

匹配字符串的开始

匹配字符串的结束

正则表达式引擎通常会提供一个“测试指定的字符串是否匹配一个正则表达式”的方法，如JavaScript里的RegExp.test()方法或.NET里的Regex.IsMatch()方法。这里的匹配是指是字符串里有没有符合表达式规则的部分。如果不使用^和$的话，对于\d{5,12}而言，使用这样的方法就只能保证字符串里包含5到12连续位数字，而不是整个字符串就是5到12位数字。

元字符^（和数字6在同一个键位上的符号）和$都匹配一个位置，这和\b有点类似。^匹配你要用来查找的字符串的开头，$匹配结尾。这两个代码在验证输入的内容时非常有用，比如一个网站如果要求你填写的QQ号必须为5位到12位数字时，可以使用：^\d{5,12}$。

这里的{5,12}和前面介绍过的{2}是类似的，只不过{2}匹配只能不多不少重复2次，{5,12}则是重复的次数不能少于5次，不能多于12次，否则都不匹配。

因为使用了^和$，所以输入的整个字符串都要用来和\d{5,12}来匹配，也就是说整个输入必须是5到12个数字，因此如果输入的QQ号能匹配这个正则表达式的话，那就符合要求了。

和忽略大小写的选项类似，有些正则表达式处理工具还有一个处理多行的选项。如果选中了这个选项，^和$的意义就变成了匹配行的开始处和结束处。

字符转义

如果你想查找元字符本身的话，比如你查找.,或者*,就出现了问题：你没办法指定它们，因为它们会被解释成别的意思。这时你就得使用\来取消这些字符的特殊意义。因此，你应该使用\.和\*。当然，要查找\本身，你也得用\\.

例如：deerchao\.net匹配deerchao.net，C:\\Windows匹配C:\Windows。

重复

你已经看过了前面的*,+,{2},{5,12}这几个匹配重复的方式了。下面是正则表达式中所有的限定符(指定数量的代码，例如*,{5,12}等)：

表2.常用的限定符

代码/语法

说明

重复零次或更多次

重复一次或更多次

重复零次或一次

{n}

重复n次

{n,}

重复n次或更多次

{n,m}

重复n到m次

下面是一些使用重复的例子：

Windows\d+匹配Windows后面跟1个或更多数字

^\w+匹配一行的第一个单词(或整个字符串的第一个单词，具体匹配哪个意思得看选项设置)

字符类

要想查找数字，字母或数字，空白是很简单的，因为已经有了对应这些字符集合的元字符，但是如果你想匹配没有预定义元字符的字符集合(比如元音字母a,e,i,o,u),应该怎么办？

很简单，你只需要在方括号里列出它们就行了，像[aeiou]就匹配任何一个英文元音字母，[.?!]匹配标点符号(.或?或!)。

我们也可以轻松地指定一个字符范围，像[0-9]代表的含意与\d就是完全一致的：一位数字；同理[a-z0-9A-Z_]也完全等同于\w（如果只考虑英文的话）。

下面是一个更复杂的表达式：\(?0\d{2}[) -]?\d{8}。

“(”和“)”也是元字符，后面的分组节里会提到，所以在这里需要使用转义。

这个表达式可以匹配几种格式的电话号码，像(010)88886666，或022-22334455，或02912345678等。我们对它进行一些分析吧：首先是一个转义字符\(,它能出现0次或1次(?),然后是一个0，后面跟着2个数字(\d{2})，然后是)或-或空格中的一个，它出现1次或不出现(?)，最后是8个数字(\d{8})。

分枝条件

不幸的是，刚才那个表达式也能匹配010)12345678或(022-87654321这样的“不正确”的格式。要解决这个问题，我们需要用到分枝条件。正则表达式里的分枝条件指的是有几种规则，如果满足其中任意一种规则都应该当成匹配，具体方法是用|把不同的规则分隔开。听不明白？没关系，看例子：

0\d{2}-\d{8}|0\d{3}-\d{7}这个表达式能匹配两种以连字号分隔的电话号码：一种是三位区号，8位本地号(如010-12345678)，一种是4位区号，7位本地号(0376-2233445)。

\(?0\d{2}\)?[- ]?\d{8}|0\d{2}[- ]?\d{8}这个表达式匹配3位区号的电话号码，其中区号可以用小括号括起来，也可以不用，区号与本地号间可以用连字号或空格间隔，也可以没有间隔。你可以试试用分枝条件把这个表达式扩展成也支持4位区号的。

\d{5}-\d{4}|\d{5}这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字，或者用连字号间隔的9位数字。之所以要给出这个例子是因为它能说明一个问题：使用分枝条件时，要注意各个条件的顺序。如果你把它改成\d{5}|\d{5}-\d{4}的话，那么就只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配分枝条件时，将会从左到右地测试每个条件，如果满足了某个分枝的话，就不会去再管其它的条件了。

分组

我们已经提到了怎么重复单个字符（直接在字符后面加上限定符就行了）；但如果想要重复多个字符又该怎么办？你可以用小括号来指定子表达式(也叫做分组)，然后你就可以指定这个子表达式的重复次数了，你也可以对子表达式进行其它一些操作(后面会有介绍)。

(\d{1,3}\.){3}\d{1,3}是一个简单的IP地址匹配表达式。要理解这个表达式，请按下列顺序分析它：\d{1,3}匹配1到3位的数字，(\d{1,3}\.){3}匹配三位数字加上一个英文句号(这个整体也就是这个分组)重复3次，最后再加上一个一到三位的数字(\d{1,3})。

IP地址中每个数字都不能大于255. 经常有人问我, 01.02.03.04 这样前面带有0的数字, 是不是正确的IP地址呢? 答案是: 是的, IP 地址里的数字可以包含有前导 0 (leading zeroes).

不幸的是，它也将匹配256.300.888.999这种不可能存在的IP地址。如果能使用算术比较的话，或许能简单地解决这个问题，但是正则表达式中并不提供关于数学的任何功能，所以只能使用冗长的分组，选择，字符类来描述一个正确的IP地址：((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)。

理解这个表达式的关键是理解2[0-4]\d|25[0-5]|[01]?\d\d?，这里我就不细说了，你自己应该能分析得出来它的意义。

反义

有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外，其它任意字符都行的情况，这时需要用到反义：

表3.常用的反义代码

代码/语法

说明

匹配任意不是字母，数字，下划线，汉字的字符

匹配任意不是空白符的字符

匹配任意非数字的字符

匹配不是单词开头或结束的位置

[^x]

匹配除了x以外的任意字符

[^aeiou]

匹配除了aeiou这几个字母以外的任意字符

例子：\S+匹配不包含空白符的字符串。

<a[^>]+>匹配用尖括号括起来的以a开头的字符串。

后向引用

使用小括号指定一个子表达式后，匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下，每个分组会自动拥有一个组号，规则是：从左向右，以分组的左括号为标志，第一个出现的分组的组号为1，第二个为2，以此类推。

呃……其实,组号分配还不像我刚说得那么简单：

- 分组0对应整个正则表达式

- 实际上组号分配过程是要从左向右扫描两遍的：第一遍只给未命名组分配，第二遍只给命名组分配－－因此所有命名组的组号都大于未命名的组号

- 你可以使用(?:exp)这样的语法来剥夺一个分组对组号分配的参与权．

后向引用用于重复搜索前面某个分组匹配的文本。例如，\1代表分组1匹配的文本。难以理解？请看示例：

\b(\w+)\b\s+\1\b可以用来匹配重复的单词，像go go, 或者kitty kitty。这个表达式首先是一个单词，也就是单词开始处和结束处之间的多于一个的字母或数字(\b(\w+)\b)，这个单词会被捕获到编号为1的分组中，然后是1个或几个空白符(\s+)，最后是分组1中捕获的内容（也就是前面匹配的那个单词）(\1)。

你也可以自己指定子表达式的组名。要指定一个子表达式的组名，请使用这样的语法：(?<Word>\w+)(或者把尖括号换成'也行：(?'Word'\w+)),这样就把\w+的组名指定为Word了。要反向引用这个分组捕获的内容，你可以使用\k<Word>,所以上一个例子也可以写成这样：\b(?<Word>\w+)\b\s+\k<Word>\b。

使用小括号的时候，还有很多特定用途的语法。下面列出了最常用的一些：

表4.常用分组语法

分类

代码/语法

说明

捕获

(exp)

匹配exp,并捕获文本到自动命名的组里

(?<name>exp)

匹配exp,并捕获文本到名称为name的组里，也可以写成(?'name'exp)

(?:exp)

匹配exp,不捕获匹配的文本，也不给此分组分配组号

零宽断言

(?=exp)

匹配exp前面的位置

(?<=exp)

匹配exp后面的位置

(?!exp)

匹配后面跟的不是exp的位置

(?<!exp)

匹配前面不是exp的位置

注释

(?#comment)

这种类型的分组不对正则表达式的处理产生任何影响，用于提供注释让人阅读

我们已经讨论了前两种语法。第三个(?:exp)不会改变正则表达式的处理方式，只是这样的组匹配的内容不会像前两种那样被捕获到某个组里面，也不会拥有组号。“我为什么会想要这样做？”——好问题，你觉得为什么呢？

零宽断言

地球人，是不是觉得这些术语名称太复杂，太难记了？我也有同感。知道有这么一种东西就行了，它叫什么，随它去吧！人若无名，便可专心练剑；物若无名，便可随意取舍……

接下来的四个用于查找在某些内容(但并不包括这些内容)之前或之后的东西，也就是说它们像\b,^,$那样用于指定一个位置，这个位置应该满足一定的条件(即断言)，因此它们也被称为零宽断言。最好还是拿例子来说明吧：

断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。

(?=exp)也叫零宽度正预测先行断言，它断言自身出现的位置的后面能匹配表达式exp。比如\b\w+(?=ing\b)，匹配以ing结尾的单词的前面部分(除了ing以外的部分)，如查找I'm singing while you're dancing.时，它会匹配sing和danc。

(?<=exp)也叫零宽度正回顾后发断言，它断言自身出现的位置的前面能匹配表达式exp。比如(?<=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分)，例如在查找reading a book时，它匹配ading。

假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了)，你可以这样查找需要在前面和里面添加逗号的部分：((?<=\d)\d{3})+\b，用它对1234567890进行查找时结果是234567890。

下面这个例子同时使用了这两种断言：(?<=\s)\d+(?=\s)匹配以空白符间隔的数字(再次强调，不包括这些空白符)。

负向零宽断言

前面我们提到过怎么查找不是某个字符或不在某个字符类里的字符的方法(反义)。但是如果我们只是想要确保某个字符没有出现，但并不想去匹配它时怎么办？例如，如果我们想查找这样的单词--它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样：

\b\w*q[^u]\w*\b匹配包含后面不是字母u的字母q的单词。但是如果多做测试(或者你思维足够敏锐，直接就观察出来了)，你会发现，如果q出现在单词的结尾的话，像Iraq,Benq，这个表达式就会出错。这是因为[^u]总要匹配一个字符，所以如果q是单词的最后一个字符的话，后面的[^u]将会匹配q后面的单词分隔符(可能是空格，或者是句号或其它的什么)，后面的\w*\b将会匹配下一个单词，于是\b\w*q[^u]\w*\b就能匹配整个Iraq fighting。负向零宽断言能解决这样的问题，因为它只匹配一个位置，并不消费任何字符。现在，我们可以这样来解决这个问题：\b\w*q(?!u)\w*\b。

零宽度负预测先行断言(?!exp)，断言此位置的后面不能匹配表达式exp。例如：\d{3}(?!\d)匹配三位数字，而且这三位数字的后面不能是数字；\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词。

同理，我们可以用(?<!exp),零宽度负回顾后发断言来断言此位置的前面不能匹配表达式exp：(?<![a-z])\d{7}匹配前面不是小写字母的七位数字。

请详细分析表达式(?<=<(\w+)>).*(?=<\/\1>)，这个表达式最能表现零宽断言的真正用途。

一个更复杂的例子：(?<=<(\w+)>).*(?=<\/\1>)匹配不包含属性的简单HTML标签内里的内容。(?<=<(\w+)>)指定了这样的前缀：被尖括号括起来的单词(比如可能是<b>)，然后是.*(任意的字符串),最后是一个后缀(?=<\/\1>)。注意后缀里的\/，它用到了前面提过的字符转义；\1则是一个反向引用，引用的正是捕获的第一组，前面的(\w+)匹配的内容，这样如果前缀实际上是<b>的话，后缀就是</b>了。整个表达式匹配的是<b>和</b>之间的内容(再次提醒，不包括前缀和后缀本身)。

小括号的另一种用途是通过语法(?#comment)来包含注释。例如：2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)。

要包含注释的话，最好是启用“忽略模式里的空白符”选项，这样在编写表达式时能任意的添加空格，Tab，换行，而实际使用时这些都将被忽略。启用这个选项后，在#后面到这一行结束的所有文本都将被当成注释忽略掉。例如，我们可以前面的一个表达式写成这样：

(?<=    # 断言要匹配的文本的前缀
<(\w+)> # 查找尖括号括起来的字母或数字(即HTML/XML标签)
)       # 前缀结束
.*      # 匹配任意文本
(?=     # 断言要匹配的文本的后缀
<\/\1>  # 查找尖括号括起来的内容：前面是一个"/"，后面是先前捕获的标签
)       # 后缀结束

贪婪与懒惰

当正则表达式中包含能接受重复的限定符时，通常的行为是（在使整个表达式能得到匹配的前提下）匹配尽可能多的字符。以这个表达式为例：a.*b，它将会匹配最长的以a开始，以b结束的字符串。如果用它来搜索aabab的话，它会匹配整个字符串aabab。这被称为贪婪匹配。

有时，我们更需要懒惰匹配，也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式，只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复，但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧：

a.*?b匹配最短的，以a开始，以b结束的字符串。如果把它应用于aabab的话，它会匹配aab（第一到第三个字符）和ab（第四到第五个字符）。

为什么第一个匹配是aab（第一到第三个字符）而不是ab（第二到第三个字符）？简单地说，因为正则表达式有另一条规则，比懒惰／贪婪规则的优先级更高：最先开始的匹配拥有最高的优先权——The match that begins earliest wins。

表5.懒惰限定符

代码/语法

说明

重复任意次，但尽可能少重复

重复1次或更多次，但尽可能少重复

重复0次或1次，但尽可能少重复

{n,m}?

重复n到m次，但尽可能少重复

{n,}?

重复n次以上，但尽可能少重复

处理选项

在C#中，你可以使用Regex(String, RegexOptions)构造函数来设置正则表达式的处理选项。如：Regex regex = new Regex(@"\ba\w{6}\b", RegexOptions.IgnoreCase);

上面介绍了几个选项如忽略大小写，处理多行等，这些选项能用来改变处理正则表达式的方式。下面是.Net中常用的正则表达式选项：

表6.常用的处理选项

名称

说明

IgnoreCase(忽略大小写)

匹配时不区分大小写。

Multiline(多行模式)

更改和的含义，使它们分别在任意一行的行首和行尾匹配，而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,的精确含意是:匹配\n之前的位置以及字符串结束前的位置.)

Singleline(单行模式)

更改的含义，使它与每一个字符匹配（包括换行符\n）。

IgnorePatternWhitespace(忽略空白)

忽略表达式中的非转义空白并启用由标记的注释。

ExplicitCapture(显式捕获)

仅捕获已被显式命名的组。

一个经常被问到的问题是：是不是只能同时使用多行模式和单行模式中的一种？答案是：不是。这两个选项之间没有任何关系，除了它们的名字比较相似（以至于让人感到疑惑）以外。

平衡组/递归匹配

这里介绍的平衡组语法是由.Net Framework支持的；其它语言／库不一定支持这种功能，或者支持此功能但需要使用不同的语法。

有时我们需要匹配像( 100 * ( 50 + 15 ) )这样的可嵌套的层次性结构，这时简单地使用\(.+\)则只会匹配到最左边的左括号和最右边的右括号之间的内容(这里我们讨论的是贪婪模式，懒惰模式也有下面的问题)。假如原来的字符串里的左括号和右括号出现的次数不相等，比如( 5 / ( 3 + 2 ) ) )，那我们的匹配结果里两者的个数也不会相等。有没有办法在这样的字符串里匹配到最长的，配对的括号之间的内容呢？

为了避免(和\(把你的大脑彻底搞糊涂，我们还是用尖括号代替圆括号吧。现在我们的问题变成了如何把xx <aa <bbb> <bbb> aa> yy这样的字符串里，最长的配对的尖括号内的内容捕获出来？

这里需要用到以下的语法构造：

- (?'group')

把捕获的内容命名为group,并压入
堆栈(Stack)

- (?'-group')

从堆栈上弹出最后压入堆栈的名为group的捕获内容，如果堆栈本来为空，则本分组的匹配失败

- (?(group)yes|no)

如果堆栈上存在以名为group的捕获内容的话，继续匹配yes部分的表达式，否则继续匹配no部分

- (?!)

零宽负向先行断言，由于没有后缀表达式，试图匹配总是失败

如果你不是一个程序员（或者你自称程序员但是不知道堆栈是什么东西），你就这样理解上面的三种语法吧：第一个就是在黑板上写一个"group"，第二个就是从黑板上擦掉一个"group"，第三个就是看黑板上写的还有没有"group"，如果有就继续匹配yes部分，否则就匹配no部分。

我们需要做的是每碰到了左括号，就在压入一个"Open",每碰到一个右括号，就弹出一个，到了最后就看看堆栈是否为空－－如果不为空那就证明左括号比右括号多，那匹配就应该失败。正则表达式引擎会进行回溯(放弃最前面或最后面的一些字符)，尽量使整个表达式得到匹配。

<                         #最外层的左括号
[^<>]*                #最外层的左括号后面的不是括号的内容
(
(
(?'Open'<)    #碰到了左括号，在黑板上写一个"Open"
[^<>]*       #匹配左括号后面的不是括号的内容
)+
(
(?'-Open'>)   #碰到了右括号，擦掉一个"Open"
[^<>]*        #匹配右括号后面不是括号的内容
)+
)*
(?(Open)(?!))         #在遇到最外层的右括号前面，判断黑板上还有没有没擦掉的"Open"；如果还有，则匹配失败

>                         #最外层的右括号

平衡组的一个最常见的应用就是匹配HTML,下面这个例子可以匹配嵌套的<div>标签：<div[^>]*>[^<>]*(((?'Open'<div[^>]*>)[^<>]*)+((?'-Open'</div>)[^<>]*)+)*(?(Open)(?!))</div>.

还有些什么东西没提到

上边已经描述了构造正则表达式的大量元素，但是还有很多没有提到的东西。下面是一些未提到的元素的列表，包含语法和简单的说明。你可以在网上找到更详细的参考资料来学习它们--当你需要用到它们的时候。如果你安装了MSDN Library,你也可以在里面找到.net下正则表达式详细的文档。这里的介绍很简略，如果你需要更详细的信息，而又没有在电脑上安装MSDN Library,可以查看关于正则表达式语言元素的MSDN在线文档。

表7.尚未详细讨论的语法

代码/语法

说明

报警字符(打印它的效果是电脑嘀一声)

通常是单词分界位置，但如果在字符类里使用代表退格

制表符，Tab

竖向制表符

换页符

换行符

Escape

\0nn

ASCII代码中八进制代码为nn的字符

\xnn

ASCII代码中十六进制代码为nn的字符

\unnnn

Unicode代码中十六进制代码为nnnn的字符

\cN

ASCII控制字符。比如\cC代表Ctrl+C

字符串开头(类似^，但不受处理多行选项的影响)

字符串结尾或行尾(不受处理多行选项的影响)

字符串结尾(类似$，但不受处理多行选项的影响)

当前搜索的开头

\p{name}

Unicode中命名为name的字符类，例如\p{IsGreek}

(?>exp)

贪婪子表达式

(?<x>-<y>exp)

平衡组

(?im-nsx:exp)

在子表达式exp中改变处理选项

(?im-nsx)

为表达式后面的部分改变处理选项

(?(exp)yes|no)

把exp当作零宽正向先行断言，如果在这个位置能匹配，使用yes作为此组的表达式；否则使用no

(?(exp)yes)

同上，只是使用空表达式作为no

(?(name)yes|no)

如果命名为name的组捕获到了内容，使用yes作为表达式；否则使用no

(?(name)yes)

同上，只是使用空表达式作为no

好吧,我承认,我骗了你,读到这里你肯定花了不止30分钟.相信我,这是我的错,而不是因为你太笨.我之所以说"30分钟",是为了让你有信心,有耐心继续下去.既然你看到了这里,那证明我的阴谋成功了.被忽悠的感觉很爽吧？

要投诉我,或者觉得我其实可以忽悠得更高明,欢迎来我的微博让我知道. 如果你有关于正则表达式的问题, 可以到 stackoverflow 网站上提问, 记得要添加 regex 标签. 如果你更习惯于用中文交流, 可以到微博上用 #正则# 标签提出问题.

网上的资源及本文参考文献

1. 2006-3-27 第一版

2. 2006-10-12 第二版

- 修正了几个细节上的错误和不准确的地方

- 增加了对处理中文时的一些说明

- 更改了几个术语的翻译（采用了MSDN的翻译方式）

- 增加了平衡组的介绍

- 放弃了对The Regulator的介绍，改用Regex Tester

3. 2007-3-12 V2.1

- 修正了几个小的错误

- 增加了对处理选项(RegexOptions)的介绍

4. 2007-5-28 V2.2

- 重新组织了对零宽断言的介绍

- 删除了几个不太合适的示例，添加了几个实用的示例

- 其它一些微小的更改

5. 2007-8-3 V2.21

- 修改了几处文字错误

- 修改/添加了对$,\b的精确说明

- 承认了作者是个骗子

- 给RegexTester添加了Singleline选项的相关功能

6. 2008-4-13 v2.3

- 调整了部分章节的次序

- 修改了页面布局，删除了专门的参考节

- 针对读者的反馈，调整了部分内容

7. 2009-4-11 v2.31

- 修改了几处文字错误

- 添加了一些注释说明

- 调整了一些措词

8. 2011-8-17 v2.32

9. 2013-1-10 v2.33

原文链接：http://deerchao.net/tutorials/regex/regex.htm （本内容由互联网资料整理而成）

[译]当Node.js遇上WebMatrix 2

前言

现在Node.js正是如火如荼,无疑它的出现为客户端和服务端捅破了厚厚的一层纸,使得前后端可以只通过javascript这一种语言就能完成一个完整的web应用程序，但是苦于一直没有一整套针对Node.js开发的工具，使得Node.js推广得比较慢，在实际项目中使用率比较低，大多都是停留在实验和小工具阶段。WebMatrix 是微软最新的 Web 开发工具，它包含了构建网站所需要的一切元素。您可以从开源 Web 项目或者内置的 Web 模板开始，也可以直接从无到有编写代码。简单并且完全是免费的，使得开发网站从来没有如此简单（关于WebMatrix更详细的信息可以移步这里）。随着WebMatrix版本的更新加之Node.js的火热，也加强了对Node.js以及相关的技术支持。

转载请注明来源地址：http://www.cnblogs.com/aNd1coder/archive/2012/06/17/2552037.html

正文

经过WebMatrix团队数月的努力，现在激动的介绍WebMatrix 2候选版本。WebMatrix 2 包含大量的新特性，但今天我想概述在WebMatrix 2下用Node.js创建应用我们所做的工作。
如果你想跳过此文而仅仅只是想要得到下载连接（免费），请点这里。

我们走了多远

不到一年前，我在卡耐基梅隆大学工作，尝试用Node.js和ASP.NET实现我们在线学习环境的实时组件。我们在运行Linux的客户的数据中心是行不通的，在cygwin里运行一个生产系统显得不够理想。在Windows上开发node更加不易 - 如果你想让node运行，让NPM工作是几乎不可能的。在Windows环境下使用node比登山还难。

在我加入微软之后过去的12个月里，我们已经看到Joyent和微软之间的各种合作关系，是的新版的node和npm在Windows上得到支持，以及在Windos Azure上支持Node的承诺。我们共同为开发者，IT管理员以及使用我们系统的最终用户建立更好的用户体验。

这些工作得到的其中一个成果是在Windows Azure上用Node.js构建应用体验得到了极大的改善。在SDK团队的Glenn Block极力称赞微软做了令人难以置信的举措使得Azure成为开发者开发Node.js应用一个很棒的环境。作为我们最喜欢的副总裁Scott Guthrie在他的博客上表示,(这些)满足新Windows Azure。

进入WebMatrix 2

如今开始使用node.js是一个相对简单的任务。安装node，npm（现在已经打包在了node安装程序里），用你最喜欢的文本编辑器就可以开始。但是在管理项目，编译CoffeeScript和LESS，配置产品设置，发布应用程序过程中充满各种各样可能性和配置（繁琐）。WebMatrix 2 提供我们另外一种构建node.js应用的方式：你只需要在一个环境下构建优秀的应用程序。

WebMatrix 2 首要是为构建Web应用程序而设计的。在起始屏，可以使用预制的模板，或者从Web Gallery中安装常见的开源应用程序来创建你租户的应用程序。目前模板支持用Node.js, PHP, 当然还包括ASP.NET Web Pages创建应用程序。除此之外，WebMatrix 2 还包含三种创建Node.js应用程序的模板：

- 空Node.js站点

- Express站点

- Node Starter站点

空Node.js网站提供使用http server一些非常基础的示例，跟nodejs.org官网提供的一致。

Express网站是用Node.js的Express框架脚手架工具生成的基础应用程序。

Node Starter网站是以Express MVC基础项目模版开始一个项目。样板文件被托管在GitHub上，演示如何实现包含jade父/子布局,LESS预编译css,用Twitter和Facebook登录,移动布局以及验证码的站点。当你用任意这些模板创建新的应用程序时，WebMatrix 2将会确保node，npm以及IISNode已经安装在你的系统里。如果他们没有被安装，WebMatrix 2将会自动安装任何缺少的依赖关系。如果你正在Windows下创建PHP/MYSQL应用程序，这一特性也特别有用。

Node Starter站点模板将会生成一个包含Express，Jade，LESS，使用socket.io实现聊天，使用EveryAuth实现登录，以及用jQuery Mobile支持移动设备的全功能的应用程序：

Node.js智能感知

WebMatrix 2其中一个目标就是降低开发人员在开始使用Node.js时的门槛。方法之一就是提供所有应用程序构建的核心模块智能感知。我们使用的文档实际上构建自node.js官网的文档。

在提供Node.js核心模块智能感知之外,WebMatrix 2还为你自己的Javascript代码以及通过NPM安装的第三方模块提供代码自动完成功能。有无数种方式来构建自己的应用程序，NPM的画廊最近超过了10000条。当开发者开始构建更加复杂的应用程序，将变得很难(甚至吓人)开始。WebMatrix 2 通过开源程序包将这一切变得更容易：

支持Jade和EJS

为创建Node.js应用程序提供更实用的工具，我们决定为Jade和EJS提供一流的编辑体验。WebMatrix 2 为Jade和EJS提供语法高亮，HTML验证，代码大纲，自动完成。

如果你键入包含尖括号的代码(EJS代码块),EJS体验表现得会更好,因为它基于我们的高级HTML编辑器之上:

星球上最好的LESS编辑器

因此我承认 —— 我有一点CSS预处理器极客。我不写CSS因为我爱它，但是因为我需要把事情做好，我得尽可能的编写更少的CSS代码。像LESS以及Sass之类的工具提供CSS程序员缺失的特性，像变量，混入，嵌套以及常用的内置方法。

WebMatrix的LESS编辑器不仅提供语法高亮，而且还提供LESS规范验证，变量和混入智能感知，以及LESS规范的格式化。许多node开发人员在服务器端使用npm模块来处理他们LESS，但是如果你想在本地编译LESS，你可以在设计时使用Orange Bits compiler来编译你的CSS。

CoffeeScript编辑器

跟LESS和Sass让书写CSS变得更容易一样，CoffeeScript简化了书写Javascript的方式。WebMatrix 2 提供语法高亮，代码大纲，自动完成来简化编辑体验。如果你想使用CoffeeScript但不用服务器上编译它，你可以在设计时使用Orange Bits compiler来编译你的CoffeeScript

移动模拟器

设计移动应用程序不能滞后，WebMatrix 2试图让这两种方法更容易。首先 - 视觉模板在主样式表中(以Node Starter Template为例)充分利用响应式布局的优势：

styles.less

这看起来非常牛逼如果你不需要改变你的网站内容,但缺乏令人更加复杂的场景。为了绕开它，node开始模块使用了一块连接中间件来检测用户是否来自移动设备，然后发送给他们基于jQuery Mobile的移动布局(另外一篇文章会详细介绍).基于单个视图约定允许您创建{viewName}_mobile.jade视图仅在移动设备上加载。

更强大的是，如果你需要在各种浏览器以及移动设备上查看你的网站表现?WebMatrix 2 提供一种扩展模型允许你在运行菜单添加移动以及桌面浏览器。

目前，我们提供Windows Phone模拟器, 以及 iPhone/iPad仿真器。我们都在寻找人员支持其他模拟器*咳嗽*android*咳嗽*，甚至构建网桥方便在线测试应用程序。

扩展以及开源

一款代码编辑工具仅对致力于该平台的开发者至关重要。我们想要与大家一起取得成功和成长。作为目标的一部分，我们开放了一个可扩展模型，允许开发者构建自定义扩展以及和其他开发者分享。扩展库可以通过http://extensions.webmatrix.com访问。我们计划转移大部分扩展到GitHub上，NodePowerTools扩展是第一个计划开源：

- Node Power Tools

- OrangeBits Compiler

接下来几个月你将可以从Microsoft官网看到更多的扩展以及开源。

参与

我想确保感谢所有帮助这个版本诞生的人，包括WebMatrix团队，Glenn Block, Claudio Caldato, our Node Advisory board, Isaac Schlueter,以及在Joyent的所有人。
更多的信息，请访问：

原文

http://jbeckwith.com/2012/06/07/node-js-meet-webmatrix-2/

附件(中英对照)

[译]当Node.js遇上WebMatrix2.rar

注:由于水平有限，有些地方翻译得不太妥当同时也难免存在错误之处，请评论指出，觉得有收获麻烦点下右下角的推荐-, -

参考

http://www.microsoft.com/web/webmatrix/

https://www.windowsazure.com/zh-cn/develop/nodejs/

http://weblogs.asp.net/scottgu/archive/2012/06/07/meet-the-new-windows-azure.aspx

http://extensions.webmatrix.com/packages/OrangeBits/

原文链接：http://www.cnblogs.com/aNd1coder/archive/2012/06/17/2552037.html （本内容由互联网资料整理而成）

Internet Explorer 11 preview

48 minutes agoIE11 standards css3 html5 es6 dom4 webgl spdy

The first preview of IE11 has just been released. Let’s see what is new so far. I’ll update this post as more information becomes available.

The user-agent string

The new user-agent string for IE11 is as follows:

Desktop:

Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko

Experience formally known as Metro:

Mozilla/5.0 (Windows NT 6.3; Win64; x64; Trident/7.0; Touch; rv:11.0) like Gecko

CSS

- The border-image shorthand and individual properties are now supported

- Flexbox support has been updated to the latest spec, and unprefixed

- The text-combine-horizontal property from CSS Writing-Modes is now recognised with the -ms- prefix. However, I’m not sure to get this to work. I assume it only works with glyphs that are upright in vertical text, but IE doesn’t support the text-orientation property. Perhaps this is work in progress?

- IE10 had a bug where the rem unit could not be used in the font-size component of the font shorthand. This has thankfully been fixed in IE11.

HTML5, DOM4 and associated APIs

The following are now supported:

- The hidden attribute

- Fullscreen API

- Custom Data Attributes API (element.dataset)

- Device Orientation Events

- The Screen Orientation API

- DOM4 Mutation Observers (replacement for DOM Mutation Events)

- Input Method Editor API (scripted access to an IME)

- Media Source Extensions

- Encrypted Media Extensions (this will prove controversial I’m sure)

- Web Cryptography API

- Tracking Preference Expression (DNT)

- Dynamic TextTracks (addTextTrack, addCue, and removeCue)

- TTML Simple Delivery Profile for Closed Captions

- Streaming XHR cache control (msCaching attribute)

- Pointer Events have been updated to the latest Candidate Recommendation

- devicePixelRatio

Web Graphics

The big news with IE11 is that WebGL is supported and enabled. Despite IE getting a lot of flack for not supporting WebGL, it looks like it beat Apple to the punch. WebGL is disabled by default in Safari.

Some new features of Canvas 2D Level 2 have been added, including image smoothing, the even-odd fill rule, and dashed lines.

Media

IE 11 supports the MPEG Dash (Dynamic Adaptive Streaming over HTTP).

Network

SPDY/3 is now supported. I was expecting it to be branded as HTTP 2, but this is not the case so far.

JavaScript/ES6

Support for the following ES6 features can be found in IE11 (via Kangax’s support tables:

- let

- const

- WeakMaps

- __proto__

- Block-level function declaration

- Non-standard __defineGetter__ and __defineSetter__

Performance

- More of IE11 is hardware accelerated, using DirectX 9

- Previous pages are cached for near instantaneous flipping through your browser history

- Pages are prefetched and pre rendered (like Chrome) for faster page loads (if the browser guesses right)

Windows Integration

- There are further live style sizes and further capabilities for what you can include in a live tile.

- Numbers in a web page can have click to call enabled. I don’t know if this is just done by heuristics, or if you can add something special to the markup.

Test scores

Test scores have to be taken with a huge bucket of salt, as they just cover a subset of features (for example HTML5 test doesn’t include many of the APIs above, and CSS3 test doesn’t cover CSS2.1, CSS Level 4, or many of the specs supported by IE like Grids, Regions, and Exclusions), and are sometimes incorrect (WebKit incorrectly parses things it doesn’t support like background-repeat). With that said, this is how IE11 preview performs on various popular tests:

HTML5 Test:

351 and 6 bonus points (up from 320)

CSS3 Test:

61% (up from 54%)

Rng.io:

Passed 476 tests (up from 465 passes)

Posted by dstorey, 48 minutes ago  /

Follow: Follow @dstorey
Share: Tweet

1. stezy likes this

2. dstorey posted this

Designed & developed by David Storey in California, USA. / Licensed under CC BY SA. / Follow me: Twitter | Facebook | Google+ | Dribbble

原文链接：http://generatedcontent.org/post/53943518693/ie11preview1 （本内容由互联网资料整理而成）