从Java程序员的视角看JavaScript | 程序师

我们无法在一篇博文里解释 JavaScript 的所有细节。如果你正或多或少地涉及了 web 应用程序开发,那么,我们的 Java 工具和技术范围报告揭示了,大多数(71%)Java 开发者被归到了这一类,只是你对 JavaScript 遇到了阻碍。

javascript_words-100159658-primary.idge.jpg

毫无疑问,你已经知道了 Java 和 JavaScript,不管它们有着多么类似的命名,彼此没有共享太多共通之处。Java 的静态类型、符合直接规律的简单语法和冗长,与 JavaScript 的动态、缺乏一致性原则和怪异,有着巨大的不同。

然而,JavaScript 是 web 的编程语言,最近由于 Node.js 和 JVM 自己的 Nashorn JavaScript 引擎的发展,在服务器端获得了相当的注意。

本文,我不想只是漫谈 JavaScript 的好与不好,或重复任何人都能免费找到的、不计其数的 JavaScript 教程。我想列出一些有助于理解 JavaScript 做为一种语言的技术点,并从接近 horse 的角度来理解。

我们将在本文包含下列语言级别的技术点:

  • JavaScript 的通用性
  • JavaScript 的函数编程问题
  • 不同于 Java 的继承

另外,你会找到一些工具方面的推荐,没有这些工具,你是不想着手 JavaScript 项目的,包含了构建系统的代码质量分析和测试框架方面的工具。

优点

编写一次,差不多处处运行!

毋庸置疑 JavaScript 是 web 编程语言,是很多其它语言的编译目标,也是用来证明有时候人们只是想拥有更多自由时间的终极方式。尽管如此,这不是一件坏事。每一台能够浏览现代网站的电脑都装备了具有性能和可用的 JavaScript 引擎。最重要的是,JavaScript 代码可以在后端运行。

内置到我们喜爱的 JVM 的、轻量级高性能 JavaScript 运行时 Nashorn,完全能够解释 JavaScript 脚本,还能够解释项目中带有 Java 代码的 JavaScript 脚本。

鉴于每台电脑运行时都可获得的自由,JavaScript 成为 Java 体验的完美延续。

函数式编程:一等公民是函数,而不是递归

JavaScript 中的函数是第一类公民,它们是值,可被存储在变量里、传递给其它函数、在适当的时候再执行。

这打开了函数式编程世界的大门,这是结构化 JavaScript 编程的完美方式。

注意,JavaScript 里的对象是任何东西的映射,对象的每个特性(attribute)都在同一个映射里:函数、属性(property)、构造器;易变性带来了更大的隐患,而对于 Java,你至少能够确保方法和字段结构在某种程度上是稳定的。

反过来,这使得函数式编程更加有利:涉及到小的、可理解函数和不变的数据结构是在 JavaScript 里运行的方式。

这不是没有依据的,下面是在 JavaScript 里定义一个 reduce 函数的例子,来自于《Eloquent JavaScript》一书。

function forEach (array, action) {
for (var i = 0; i < array.length; i++) {
action (array[i]); //apply action to every element of the arra. }
}
 
function reduce (combine, base, array) {
forEach (array, function (element) {
base = combine (base, element); // and here we apply function passed as ‘combine’ parameter to ‘base’ and ‘element’ });
return base;
}
 
function add (a, b) { // btw, this is how you define a function in JavaScript return a + b;
}
 
function sum (numbers) {
return reduce (add, 0, numbers);
}

注意:我们没有在这里使用 reduce 的递归版本。JavaScript 没有以尾调用【注1】为特色,这意味着每个函数的递归版本都将用到栈的深度,和 Java 一样,如果你递归太深,程序就崩溃。

继承:就像真实的世界

JavaScript 的继承是基于原型的。即,你没有扩展了其它类型的类型,而实际上,你拥有的实例从其它实例继承了功能。

想象一下,对象A就像一个映射,我们刚才稍微提到了一些、但是用了不同的视角,然后另一个类似映射的对象B从A继承了一切。

这说明B可以访问A所有部分:A的方法、字段等等。

在实践中,我从来没有看到有人实际使用简单的基于原型的继承。通常当某人需要继承时,他只是构造类,因此你可以用到所有广泛的技能,和基于类的继承的工作模式。

——Rene Saarsoo,XRebel 前端工程师

我不太确定 Java 开发者应该从中吸取什么,但是要当心继承方式的不同,对于父级对象要格外留意、而不要意外地改变整个程序的行为。

任何时候要避免的

列出不可靠的 JavaScript 设计上的决定比想象中要容易。在 JavaScript 程序中要避免的最明显的地方就是全局变量的声明

注意,在 JavaScript 里,无论什么时候,不使用 var 关键词定义变量,那么定义的变量被推到了它们被定义的作用域顶端。这意味着,每个用这种方式定义的变量将跑到全局范围顶部,这会引发冲突以及你和同事不可预期的头痛。

可以开启 strict 模式。只需在脚本文件顶部写上“use strict”,那么不经意编写的全局变量声明将显示错误。

JavaScript 与 Java 另一个重要的不同点在于,前者是动态类型语言,其真谛是所有东西都可以是任何类型。这很明显了,实在不能再强调了:不要针对不同类型的值,去复用相同的变量

跟踪刚开始是个 string 类型的变量,但是现在它成了浮点数、或者函数了,相信我!

还有,我不想太深入类型和布尔值的讨论,但是要警惕 JavaScript 引擎扔给你的隐式类型转换。

搞定工作的小提示

正如我上面提到的,在编程上要更加注意这种语言的语法和怪癖,而不仅仅是知道。项目很少由于语言的不足而失败,更多的失败是与总体项目框架不足有关。下面是有助于你交付项目的一些工具。

静态代码分析

大部分项目是不同的,其复杂度和需求导致了大量的细节,你该如何着手代码库呢。尽管如此,在所有地方都有一致性的目标,那就是代码质量

是的,代码质量,对于任何开发者来说,最重要的工作就是交付。但是不要在质量上妥协,不要对你提交的代码感到不自信就不情愿与同事分享。

幸运的是,JavaScript 有一套得体的解决方案——JSHint。JSHint 是为 JavaScript 量身打造的静态分析工具,与应用于 Java 代码的 FindBug 类似。JSHint 可以在你的代码库运行,并高亮出可疑的或有问题的地方,即使你不会马上产生 bug,但这些地方将来变得难以维护。在项目中支持它相当简单。帮自己一个忙——如果你在写 JavaScript 代码,就用 JSHint 让它更安全、少一些尴尬。

REPL

REPL 代表“读取-求值-输出”循环(Read-Eval-Print Loop)【注2】,是很多动态语言的强大工具。如果你看过 Scala 或 Groovy,你一定能够理解这个概念。

激活 JavaScript REPL 的一种途径是打开浏览器的控制台,它产生了对 JavaScript 代码求值的界面。

浏览器控制台调试 JavaScript

另一个比较方便的工具是 jjs,它捆绑在 JDK1.8。

jjs 的演示

它是命令行工具,允许你访问 JDK 中的 Nashorn JavaScript 引擎,完全有能力执行那些甚至最为严格的 JavaScript 脚本。

测试

对于任何一个项目,你都想运行一些测试。测试对于动态类型的语言尤为重要,最好选择一种测试框架。我推荐 Jasmine,它是用于测试 JavaScript 的行为驱动开发框架。

Jasmine 示例代码

在 Jasmine,你用 describe 描述测试套件,它阻止了你想测试的代码访问。在测试中的代码完成后,你 expect 一些结果。

很明显这里不是要给出教程,但是我想让你一瞥 JavaScript 代码看起来是多么地优雅。Jasmine 是 JavaScript 项目最好的实践之一,我们私下在产品开发中应用到了 ZeroTurnaround 项目,尤其是对于富含 JavaScript 的不间断运行的交互分析器 XRebel

构建工具

最后,你的项目将需要的、比较重要的是构建工具。如果你在 Java 项目中使用 JavaScript,请确保你可以避开 Java 构建工具,这就差不多足够了。但是,对于独立的 JavaScript 项目,没有必要引入庞然大物—Maven【注3】。

可以考虑的 JavaScript 项目用到的构建工具是 GulpJS【注4】。它是基于插件的构建系统,你可以为其指定任务。任务可以是“拷贝 src 目录下的 .js 文件到 dest”、或“压缩我的 JavaScript 代码用于生产环境”。让人受到震动的是,GulpJS 把任务相关的文件流加入过滤器,因此你可以把上面的两个任务加入一次有效的清扫中。

还有大量的可用插件,借助适当的构建系统,你将发现项目中的协作会轻松很多。

结论

我们只是看到了 JavaScript 的冰山一角,并尽量介绍一些 Java 开发者在解决 JavaScript 时应该知道的概念和工具。自然地,这里没有提供要学习的完整的技术清单,但是如果你正准备义无反顾地深入 JavaScript 项目,这会帮助你起步,拥抱 JavaScript 的怪癖将有助于你不会频繁地沮丧。

你了解让 JS 开发者走向快乐的秘密或最佳实践吗?毫无疑问应该去分享!在下面评论或在 Twitter:@shelajev 上与我交谈。我乐于听到你的想法!

  • 注1:在计算机科学里,尾调用是指一个函数里的最后一个动作是一个函数调用的情形:即这个调用的返回值直接被当前函数返回的情形。这种情形下称该调用位置为尾位置。若这个函数在尾位置调用本身(或是一个尾调用本身的其他函数等等),则称这种情况为尾递归,是递归的一种特殊情形。尾调用不一定是递归调用,但是尾递归特别有用,也比较容易实现。http://zh.wikipedia.org/wiki/尾调用
  • 注2:REPL 是一个简单的,交互式的编程环境。这个词常常用于指代一个 Lisp 的交互式开发环境,但也能指代命令行的模式和例如 APL, BASIC, Clojure, F#, Haskell, J, Julia, Perl, PHP, Prolog, Python, R, Ruby, Scala, Smalltalk, Standard ML, Tcl, Javascript 这样的编程语言所拥有的类似的编程环境。这也被称做交互式顶层构件(interactive toplevel)。http://zh.wikipedia.org/wiki/%E8%AF%BB%E5%8F%96%EF%B9%A3%E6%B1%82%E5%80%BC%EF%B9%A3%E8%BE%93%E5%87%BA%E5%BE%AA%E7%8E%AF
  • 注3:Maven 除了以程序构建能力为特色之外,还提供 Ant 所缺少的高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性,所以常常用两三行 Maven 构建脚本就可以构建简单的项目,而使用 Ant 则需要十几行。事实上,由于 Maven 的面向项目的方法,许多 Apache Jakarta 项目现在使用 Maven,而且公司项目采用 Maven 的比例在持续增长。http://www.oschina.net/p/maven
  • 注4:从头编写 HTMLCSSJavascript 是上个世纪的事情了,如今的 JavaScript 都是通过 CoffeeScript 这样的支持句法缩写的编辑器写成的。如果你希望写完 JavaScript 能够一个工具完成代码清理优化工作,Gulp 就是你的不二之选,GulpJS 类似 Ant 或 Maven 之于 Java。http://www.oschina.net/p/gulp

— END —
英文原文:JavaScript: Explain It Like I’m a Java Developer

阅读详情 -> 从Java程序员的视角看JavaScript | 程序师.

Categories: JavaScript

JavaScript简易教程

这是我所知道最完整最简洁的JavaScript基础教程。

本文将带你尽快走进JavaScript的世界——前提是你有一些编程经验的话。本文试图描述这门语言的最小子集。我给这个子集起名叫做“JavaScript简易教程”,并推荐那些准备深入阅读细节和高级技巧之前的新手阅读。合抱之木生于毫末,九层之台起于垒土,欲速则不达。本文的最后会提出如何进一步学习。

警告:下面是我所描述的规则集和最佳实践。我喜欢整洁清晰(例如,你可以随时通过下面的目录快速导航)。横看成岭侧成峰,远近高低各不同,虽然规则是无懈可击的,但不可避免——每个人的理解会各不相同。

Categories: JavaScript

Chartist.js – 简单的响应式图表JS库


Big welcome by the Chartist Guy

The Chartist Guy

Checkout the documentation site at http://gionkunz.github.io/chartist-js/

Checkout this lightning talk that gives you an overview of Chartist in 5 minuteshttps://www.youtube.com/watch?v=WdYzPhOB_c8

Guest talk of the Chartist.js Guy at the Treehouse Show https://www.youtube.com/watch?v=h9oH0iDaZDQ&t=2m40s

Chartist.js is a simple responsive charting library built with SVG. There are hundreds of nice charting libraries already out there, but they are either:

  • not responsive
  • use the wrong technologies for illustration (canvas)
  • are not flexible enough while keeping the configuration simple
  • are not friendly to your own code
  • are not friendly to designers
  • have unnecessary dependencies to monolithic libraries
  • more annoying things

That’s why we started Chartist.js and our goal is to solve all of the above issues.

What is it made for?

Chartist’s goal is to provide a simple, lightweight and unintrusive library to responsively craft charts on your website. It’s important to understand that one of the main intentions of Chartist.js is to rely on standards rather than providing it’s own solution to a problem which is already solved by those standards. We need to leverage the power of browsers today and say good bye to the idea of solving all problems ourselves.

Chartist works with inline-SVG and therefore leverages the power of the DOM to provide parts of its functionality. This also means that Chartist does not provide it’s own event handling, labels, behaviors or anything else that can just be done with plain HTML, JavaScript and CSS. The single and only responsibility of Chartist is to help you drawing “Simple responsive Charts” using inline-SVG in the DOM, CSS to style and JavaScript to provide an API for configuring your charts.

Example site

You can visit this Site http://gionkunz.github.io/chartist-js/ which is in fact a build of the current project. We are still developing and constantly add features but you can already use Chartist.js in your projects as we have reached a stable and reliable state already.

Version notes

We are currently still heavily developing in order to make Chartist.js better. Your help is needed! Please contribute to the project if you like the idea and the concept and help us to bring nice looking responsive open-source charts to the masses.

Important missing stuff

  1. Jasmine Tests!
  2. Documentation: JSDoc, Getting started documentation and landing page
  3. Better accessibility using ARIA and other optimizations
  4. Better interfaces to the library (i.e. jQuery with data-* attributes for configuration), Angular.js directive etc.
  5. Richer Sass / CSS framework
  6. Other charts types (spider etc.)

Contribution

We are looking for people who share the idea of having a simple, flexible charting library that is responsive and uses modern and future-proof technologies. The goal of this project is to create a responsive charting library where developers have their joy in using it and designers love it because of the designing flexibility they have.

Contribute if you like the Chartist Guy!

阅读详情 -> gionkunz/chartist-js.

Categories: css3, html5, JavaScript, 前端资讯

W3C HTML JSON form submission

Abstract

This specification defines a new form encoding algorithm that enables the transmission of form data as JSON. Instead of capturing form data as essentially an array of key-value pairs which is the bread and butter of existing form encodings, it relies on a simple name attribute syntax that makes it possible to capture rich data structures as JSON directly.

Status of This Document

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.

This specification is an extension specification to HTML.

This document was published by the HTML Working Group as a First Public Working Draft. This document is intended to become a W3C Recommendation. If you wish to make comments regarding this document, please send them to public-html@w3.org (subscribearchives). All comments are welcome.

Publication as a First Public Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the 5 February 2004 W3C Patent PolicyW3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

阅读详情 -> W3C HTML JSON form submission.

Categories: html5, JavaScript

固定(Fixed) vs. 流动(Fluid) vs. 弹性(Elastic):哪种布局更适合你? – blog.moocss.com

有一个问题已经困扰网页设计师们很久了:该使用固定、流动、弹性,还是混合布局呢?它们各有优缺点。最终的决定取决于网站的可用性,单用某一种布局就想达到目的,可能没那么容易。那么,既然如此令人困惑,是否有做出正确决定的诀窍呢?考虑好几个问题,恰当地设定目标结果,你也能做出融合各方优点的成功布局设计。

本文将讨论每种布局方案的利与弊。其实,只要你时刻注意可用性,每种方案都能实现成功的网站布局。

您也可以参考一下我们以前的文章:

为什么要争论这些?网页设计受可用性的大棒指引,而由于网站用户的多样性,已经很难做出对不同用户都有足够可用性的网站。

当设计的网站会面向众多用户时,设计师必须考虑访客之间的下列潜在差异

  • 屏幕分辨率
  • 用的哪款浏览器
  • 浏览窗口是否最大化
  • 是否启用占位置的浏览器的额外组件(如历史、书签、Google工具栏等等)
  • 乃至操作系统和硬件情况

由于并无标准规定网页大小,网页设计师工作时就需要解决不计其数的问题。

1. 固定布局和流动布局的差异

尽管大部分设计师和开发者都对固定和流动网页布局有基本的了解,我们还是简单明确一下概念。

固定网页布局

固定网页布局指网站内容被一个固定宽度的容器包裹,容器内的区块都有固定的百分比或者像素宽度值。最重要的一点——容器是不能移动的。不管屏幕分辨率如何变化,访客看到的都是固定宽度的内容。

Fixed Website Layout

上图显示了固定宽度网页布局大体上的实现方式。内部组件被分别设定为固定的520、200、200像素宽。960像素宽度已经成了现代网页设计的一项标准,因为大多数用户的屏幕分辨率都在1024×768及以上。

流动网页布局

流动网页布局,也称为流体网页布局,其实现方法则是大多数组件(包括主容器)都设成百分比宽度,并且根据用户的屏幕分辨率自适应。

Fluid Website Layout

上图展示了一个流动网页布局。尽管大多数设计师会给流动布局内某些特定元素(如外边距和内留白)以固定宽度,整个布局大体上还是使用百分比宽度,并根据用户不同而自动调整实际宽度。

2. 固定布局的网页设计

很多设计师都更喜欢固定布局,因为他们觉得固定的比较保险:设计师看到什么,用户看到的就是什么。不过,说到其利与弊,则同流动布局一样让人揪心。

  • 固定宽度布局的设计更简便,更容易自定义。
  • 任意浏览器下的显示宽度都一样,对于图像、表单、视频等宽度固定的内容,潜在的冲突更少。
  • 不用设定min-width(最小宽度)和max-width(最大宽度),这两个属性并不被所有浏览器支持。
  • 即使网页被设计成兼容最小屏幕分辨率800×600的大小,在大分辨率显示器下,内容仍然足够易读。

  • 固定宽度的布局可能会给高分辨率屏幕用户带来巨大的页面空白,从而破坏“神圣比例”、“三分割法则”、整体平衡,乃至其他设计原则。
  • 小屏幕上可能会出现水平滚动条,影响用户体验。
  • 无缝材质拼图,纹样和其他连续图像需要针对大分辨率做出优化。
  • 总体来说,固定宽度的可用性更低。

固定布局的设计实例

下列五个网页的设计师都充分利用了固定布局网页的特征。这些网站无不融合了大量设计元素,利用固定布局创建出完美的场景。在固定宽度的助益下,设计师方能更好地控制站点内容周边额外的设计元素,从而更为精准地调节内容和导航的宽度。

Lebloe.Com

Corvus Art Design Studio

Nathan-Sanders.Com

Nine Lion Design

Colour Pixel

请特别注意设计师们是如何针对宽屏幕设计连续图像的(不妨把你的屏幕分辨率调高一点试试)。

3. 规避固定布局的坏处

如果你已经决定要用固定布局,下面这些小技巧你可就不得不知。它们帮你弱化固定布局的坏影响,助你做出成功的设计。

译注:下面这段有凑字数赚稿费之嫌,点此跳过这段

先看下统计数据

现在大部分设计师都是假定大部分互联网用户都使用的1024×768或更高的分辨率。 W3Schools公布的一份投票结果显示,事实并非如此(请注意W3Schools的数据并不能完全相信,后面会有详细解释):

Screen Resolution Pie Chart

如您所见, 640×480 甚至不够格在这张表上出现。W3Schools的数据表明这个分辨率似乎已经完全被用户抛弃了。而事实上,确实还有用户在使用这个分辨率,只不过用户数量太少,设计师完全把他们忽略掉,去做一些更合适、对较高分辨率有更佳可用性的设计。

即使对于使用这种分辨率的用户来说,他们也可能只是在一些方便携带的小型电脑商使用,并不是他们平常使用的主要屏幕分辨率。

不过,这里的统计数据可能也没有大家期待的那么准确。因为W3Schools的访客基本上都是一个特定群体(设计师和网页开发者),结果会和普通公众有点偏差。不过,其他调查也都大同小异。根据一些独立公司在2009年的调查显示,800×600的分辨率使用者比例在10%以下。(译注:根据笨活儿的网站统计数据,这个数值在2%以下)

下面这张有趣的表格来自SohTanaka.com,他们研究了一些大型网站对屏幕分辨率的兼容情况:Screen Resolution Accommodations of some top websites.

调查中涉及到的所有网站,最终都完成了华丽大变身。即使是最大的互联网公司,也都确定他们的主要受众是拥有较大屏幕分辨率的用户。

关于屏幕分辨率的其他研究,您还可以参考下面的资源:

960px 还是 760px?

综上所述,大多数设计师都是要么选择960,要么选择760作为总的像素宽度。前者更适合1024×768以及更高分辨率的屏幕,还能有一点留白。后者则是800×600分辨率下的最佳显示宽度,设置成这一宽度能够照顾到那10%,而较大屏幕上看起来也还不赖。

总是将布局整体居中对齐

如果要使用固定宽度设计,务必保证主容器居中对齐,以保持平衡(一般利用margin: 0 auto;就可以了)。不然,遇上宽屏用户,你的内容就会被挤到某个角落,很不好看。

4. 流动页面布局

设计师有很多理由不使用流动布局,不过大家很多时候也看不到流动布局的好。下面列出有运用流动布局时的打算时需要考虑的利与弊:

  • 流动网页布局拥有更强的亲和力,因为它能根据客户端的情况自适应。
  • 在不同浏览器和屏幕分辨率下的额外空白量都差不多,更符合视觉吸引力要求。
  • 如果设计得当,流动布局能避免在小屏幕上的水平滚动条。

  • 设计师对客户端的显示效果更难以控制,由于他们使用特定大小的屏幕,也更不容易发现潜在问题。
  • 图片、视频以及其他拥有固定宽度的内容不得不被设置上不同宽度,以配合不同的屏幕分辨率。
  • 对于特别大的显示屏,内容不够多的话就会造成过量空白,破坏美感。

流动布局的实例

下面两例都使用了百分比宽度来适应不同屏幕分辨率。第一个例子通过调整内容区块的宽度来适应,第二个例子则调整空白区域大小。

Simple Bits

Simple Bits

Blossom Graphic and Web Design Boutique

Blossom Graphic and Web Design Boutique

5. 设计适用的流动网页布局

尽管流动布局会带来某些问题,但这些问题其实能通过一点小把戏解决。

采用简单设计

应用到流动网页布局的图案和复杂技巧越少,其建立和维护也就越容易。同时也能更方便地适应不同屏幕分辨率。有了更加精炼的代码和设计,就能更好得避免、发现和解决兼容问题。

Smashing Magazine为例,他们就采用了流动布局。设计非常简单,只有顶部的黑色+橘色导航条是延伸开的,各内容区域的宽度会根据情况有一定的改变。利用CSS兼容了所有可能的情形,杜绝了侧边栏和内部内容发生错位。

最小宽度(min-width)和最大宽度(max-width)

这两个CSS属性,min-width 和 max-width,可以用来为过大或过小屏幕的用户指定一个固定宽度。屏幕过小的时候,内容区块固定成指定宽度,屏幕下方也出现一个水平滚动条;屏幕过大的时候,内容也固定到最大宽度,以免延展得太开,影响文字的可读性。更多细节请参考:

不幸的是,大多数版本的IE浏览器都不支持这两个属性值。这一问题可以通过IE特有的expression来解决:Maximum and Minimum Height and Width in Internet Explorer(另:中文参考)。

6. 弹性设计

其实设计网页布局时还有第三种选择。部分设计师更喜欢采用糅合了两种主要布局类型特点的所谓“弹性布局(elastic layout)”。其要点就在于使用单位em来定义元素宽度。下面的引言介绍了何谓em,而它又是如何发挥作用的:

“电脑屏幕上的‘像素’是一个不可缩放的点,而em则是相对于字体大小的单位宽度。它随着字体大小的变化而变化,反应用户对字体大小的设定。” 
– Patrick Griffiths, A List Apart

尽管弹性设计貌似会带来很多好处,它仍然像前两种布局一样有利有弊。

  • 如果合理运用,这种布局设计能带来非常友好的用户界面。目标效果是所有东西都能根据用户的偏好增大或缩小尺寸。
  • 弹性布局更适合面对流动和固定布局难以抉择的设计师,因为二者的优点弹性布局都有。

  • 尽管第一条“利”说得没错,弹性布局还是为可用性埋下了很多地雷。得需要十分的聪明才智和不断测试才能让布局适合所有用户。
  • 这种布局比前述两种要难实现得多,可能那一小点的可用性并不值得你花这么多功夫。
  • 由于这种布局的特殊性,有些弹性布局设计可能需要额外的样式表,并针对IE6做些特别的调整

弹性布局的实例

弹性布局的流动布局表面上看起来十分相似,因为大部分时候大家都把它们混淆了。其根本区别在于,弹性布局的长宽单位是em,而流动布局使用百分比,并且弹性布局的尺寸主要根据字体大小而变化。这类设计根据用户浏览器中的字体大小来做出自适应。

Clear Left

Clear Left

Mirella Furlan

Mirella Furlan

7. 哪一种布局更适合你?

选择何种布局应该由网站的性质决定。权衡上述利弊,根据你的网站需求找到合适的解决方案

以作品集网站为例,这种网站可能固定宽度布局最为适用。这样你就能做出更有设计感的东西。你不仅能更好地控制设计中的单个元素,作品的图像展示也变得更易处理。对很多设计师来说(包括那些非作品集站点的设计师),固定布局就是一个既容易相处,又能给人安全感的好朋友。

而那些要追求100%的兼容性的设计师最好就考虑一下花点时间在流动布局上。最大的挑战不在于宽屏上的可能出现的过多留白,而是那一小撮小屏幕上的显示效果。对于有大量用户的网站来说,百分比很小的用户群,绝对数目也相当可观。就算不考虑这点,大网站也应该有简洁干练的设计感,而这可以利用流动布局高效率地实现。

还是做不了决定?别担心,还有弹性或部分弹性的布局设计可供选择。如果运用得当,弹性布局能完全整合两大主要布局的优点。聪明的设计师懂得如何利用弹性设计的原则,在字体和容器大小上使用em单位,然后混合运用百分比和像素宽度来设定其他布局元素。

其他设计师怎么说

Heidi Cool 在帖子 Fixed vs. Liquid vs. Elastic Layout 上的回复

这位设计师的发言针对与他人合作运用布局的情况,而这些人可能对网页设计了解得并不多:

“我反复思考过这一问题。在case.edu上我们最终采用了固定布局,因为:

  1. 流动布局更复杂,我们为那些有不同技能的用户提供了模板化的设计,而他们的工作非常容易破坏流动布局(模板只是一些普通的HTML文件,并不是Dreamweaver模板)。
  2. 我们不想看到网站维护者们做出太宽的页面——那种文本行很长,非常难以阅读的页面。
  3. 我们想限制那些总是想填满所有空白的人所面对的空白量。如果他们用的是大屏幕显示器,就很容易把页面填满,而忽略了在小屏幕上其显示效果是多么糟糕。

大家都看得出来,最主要的问题还是集中在我们的网站是由拥有不同技能水平的人所维护、构建、增删内容这一事实上。如果是我一个人做网站,写代码的时候我可能就会更多地根据目标、内容等等来做决定。”

madr 在 Where Have All the Flexible Designs Gone? 上的回复

他提出了固定宽度布局的另外两个优点:

barner和广告通常都是用图像和Flash来实现的,这些内容让弹性或灵活的布局更难制作。我曾在newspaper world工作过一年半,广告给区块真的特别难伺候。文章配图也是,如果用上弹性布局,阅读区就可能变得过大,相对顶部图片而言。

除了Safari 3及以下(Safari 4马上就要来了[笨活儿:已经来了…])、Firefox 2及以下、IE6及以下(马上就要被淘汰了…)的所有浏览器都支持了按照页面整张缩放,而不是只缩放字体。这种情况让设计灵活的弹性布局显得更无实用性,大部分用户甚至都注意不到你的一片好心。”

jphilapy 在 Where Have All the Flexible Designs Gone?? 上的回复

流动布局的两个值得支持的地方:

“流动布局的网站可以适应很多分辨率。这样你就不用去调查讨论用户的屏幕大小。况且,屏幕分辨率的统计数据始终是个谜;几乎没人在全屏模式运行浏览器,然后还有很多工具栏、边栏、小工具之类的东西,造成了不计取数的屏幕状况。

移动电话(就说iPhone吧),游戏机等也渐渐成为网页浏览器家族的一大成员。总之,这类设备的屏幕分辨率都很小,能够从灵活的网页布局设计中获益。

Calrion 在 About Fluid- and Fixed-Width Layouts 上的回复

明确说明了运用弹性布局的情况:

“我觉得‘弹性’布局是最佳选择。某种程度上是流动的,但又有固定宽度来保证文本行不会变的过长。

我是Windows用户,一般情况下都最大化窗口。

之所以要最大化,是因为这样我能更好的关注我正在使用的应用程序。要知道我桌面上总是有很多东西。另外,最大化我的浏览器(Firefox)能给界面元素提供最多空间,尤其是书签工具栏和标签卡区域。

说到可用性,流动布局对有经验的用户可能最好用了。因为他们会主动控制浏览窗口尺寸。对于经验较少的用户,弹性布局可能最好用,因为它能自发的阻止自己变得过分宽大。

Georg 在 About Fluid- and Fixed-Width Layouts 的回复

为什么混合运用三种布局能获得最佳结果:

我更喜欢主区域流动,侧边栏固定,(也可以)再加一点弹性部分。我也总是为文本区设定600像素的最大宽度。

使用min/max来设定整个页面,宽度保持在600至1200像素之间,并且居中对齐。

在600到2400宽度的屏幕上全面测试,其他宽度就等用户自己解决吧。文本行从不会太宽(600就是最大宽度了),页面也不会在挤压下过早错位。

我收获的大部分反馈是,用户几乎没注意到有什么东西让他们困惑。网页很易读。说明我的做法是一项有用的妥协

你的站在我这儿看起来不错,所以我觉得它是有用的妥协。我年迈的双眼觉得文字实在太小了,那我就在1280宽屏上的Opera里把页面放大至120%。始终不会有问题。”

来源 :

英文原文:Fixed vs. Fluid vs. Elastic Layout: What’s The Right One For You?

译文原文:固定 vs. 流动 vs. 弹性:哪种布局更适合你?

译后感:老外废话真多啊。严重怀疑他在凑字数赚稿费!唉呀妈呀,怎么没人按字数给我稿费!

阅读详情 -> 固定(Fixed) vs. 流动(Fluid) vs. 弹性(Elastic):哪种布局更适合你? – blog.moocss.com.

Categories: css3, html5

interact.js – JavaScript 拖放,缩放,支持现代浏览器的多点触摸手势库

项目推荐interact.js:interact.js是一个随意改变形状插件,它非常强大的,灵活拖放,缩放,支持现代浏览器的多点触摸手势,基于SVG的运用,能运行在包括在IE8+的浏览器。

阅读详情 -> interact.js – JavaScript drag and drop, resizing and gestures with inertia and snapping.

Categories: JavaScript, 项目精选

gulp入門指南

Original article: Getting started with gulp by Mark Goodyear

This is a translated version in Traditional Chinese.

Grunt靠邊,全新的建構工具來了。Gulp的code-over-configuration不只讓撰寫任務(tasks)更加容易,也更好閱讀及維護。

Glup使用node.js串流(streams)讓建構更快速,不須寫出資料到磁碟的暫存檔案/目錄。如果你想了解更多有關串流–雖然不是必須的–你可以閱讀這篇文章。Gulp利用來源檔案當作輸入,串流到一群外掛(plugins),最後取得輸出的結果,並非配置每一個外掛的輸入與輸出–就像Grunt。讓我們來看個範例,分別在Gulp及Grunt建構Sass:

Grunt:

sass: {  
  dist: {
    options: {
      style: 'expanded'
    },
    files: {
      'dist/assets/css/main.css': 'src/styles/main.scss',
    }
  }
},

autoprefixer: {  
  dist: {
    options: {
      browsers: [
        'last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'
      ]
    },
    src: 'dist/assets/css/main.css',
    dest: 'dist/assets/css/main.css'
  }
},

grunt.registerTask('styles', ['sass', 'autoprefixer']);  

Grunt需要各別配置外掛,指定其來源與目的路徑。例如,我們將一個檔案作為外掛Sass的輸入,並儲存輸出結果。在設置Autoprefixer時,需要將Sass的輸出結果作為輸入,產生出一個新檔案。來看看在Gulp中同樣的配置:

Gulp:

gulp.task('sass', function() {  
  return gulp.src('src/styles/main.scss')
    .pipe(sass({ style: 'compressed' }))
    .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
    .pipe(gulp.dest('dist/assets/css'))
});

在Gulp中我們只需要輸入一個檔案即可。經過外掛Sass處理,再傳到外掛Autoprefixer,最終取得一個檔案。這樣的流程加快建構過程,省去讀取及寫出不必要的檔案,只需要最終的一個檔案。

所以,有趣了,現在要?讓我們開始安裝gulp並建立一個基本的gulpfile,包含幾個核心任務來作為入門吧。

安裝gulp

深入設置任務之前,需先安裝gulp:

$ npm install gulp -g

這會將gulp安裝到全域環境下,讓你可以存取gulp的CLI。接著,需要在本地端的專案進行安裝。cd到你的專案根目錄,執行下列指令(請先確定你有package.json檔案):

$ npm install gulp --save-dev

上述指令將gulp安裝到本地端的專案內,並紀錄於package.json內的devDependencies物件。

安裝gulp外掛

接著安裝一些外掛,完成下列任務:

執行下列指令來安裝這些外掛:

$ npm install gulp-ruby-sass gulp-autoprefixer gulp-minify-css gulp-jshint gulp-concat gulp-uglify gulp-imagemin gulp-clean gulp-notify gulp-rename gulp-livereload gulp-cache --save-dev

指令將會安裝必要的外掛,並紀錄於package.json內的devDependencies物件。完整的gulp外掛清單可以在這裡找到。

載入外掛

接下來,我們需要建立一個gulpfile.js檔案,並且載入這些外掛:

var gulp = require('gulp'),  
    sass = require('gulp-ruby-sass'),
    autoprefixer = require('gulp-autoprefixer'),
    minifycss = require('gulp-minify-css'),
    jshint = require('gulp-jshint'),
    uglify = require('gulp-uglify'),
    imagemin = require('gulp-imagemin'),
    rename = require('gulp-rename'),
    clean = require('gulp-clean'),
    concat = require('gulp-concat'),
    notify = require('gulp-notify'),
    cache = require('gulp-cache'),
    livereload = require('gulp-livereload');

呼!看起來比Grunt有更多的事要做,對吧?Gulp外掛跟Grunt外掛有些許差異–它被設計成做一件事並且做好一件事。例如;Grunt的imagemin利用快取來避免重複壓縮已經壓縮好的圖片。在Gulp中,這必須透過一個快取外掛來達成,當然,快取外掛也可以拿來快取其他東西。這讓建構過程中增加了額外的彈性層面。蠻酷的,哼?

我們也可以像Grunt一樣自動載入所有已安裝的外掛,但這不在此文章目的,所以我們將維持在手動的方式。

建立任務

編譯Sass,Autoprefix及縮小化

首先,我們設置編譯Sass。我們將編譯Sass、接著通過Autoprefixer,最後儲存結果到我們的目的地。接著產生一個縮小化的.min版本、自動重新整理頁面及通知任務已經完成:

gulp.task('styles', function() {  
  return gulp.src('src/styles/main.scss')
    .pipe(sass({ style: 'expanded' }))
    .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
    .pipe(gulp.dest('dist/assets/css'))
    .pipe(rename({suffix: '.min'}))
    .pipe(minifycss())
    .pipe(gulp.dest('dist/assets/css'))
    .pipe(notify({ message: 'Styles task complete' }));
});

繼續下去之前,一個小小的說明。

gulp.task('styles', function() { ... )};  

這個gulp.taskAPI用來建立任務。可以透過終端機輸入$ gulp styles指令來執行上述任務。

return gulp.src('src/styles/main.scss')  

這個gulp.srcAPI用來定義一個或多個來源檔案。允許使用glob樣式,例如/**/*.scss比對多個符合的檔案。傳回的串流(stream)讓它成為非同步機制,所以在我們收到完成通知之前,確保該任務已經全部完成。

.pipe(sass({ style: 'expanded' }))

使用pipe()來串流來源檔案到某個外掛。外掛的選項通常在它們各自的Github頁面中可以找到。上面列表中我有留下各個外掛的連結,讓你方便使用。

.pipe(gulp.dest('dist/assets/css'));

這個gulp.dest()API是用來設定目的路徑。一個任務可以有多個目的地,一個用來輸出擴展的版本,一個用來輸出縮小化的版本。這個在上述的styles任務中已經有展示。

我建議閱讀gulp的API文件,以了解這些函式方法。它們並不像看起來的那樣可怕!

JSHint,拼接及縮小化JavaScript

希望你現在對於如何建立一個新的gulp任務有好想法。接下來,我們將設定腳本任務,包括lint、拼接及醜化:

gulp.task('scripts', function() {  
  return gulp.src('src/scripts/**/*.js')
    .pipe(jshint('.jshintrc'))
    .pipe(jshint.reporter('default'))
    .pipe(concat('main.js'))
    .pipe(gulp.dest('dist/assets/js'))
    .pipe(rename({suffix: '.min'}))
    .pipe(uglify())
    .pipe(gulp.dest('dist/assets/js'))
    .pipe(notify({ message: 'Scripts task complete' }));
});

一件事提醒,我們需要指定JSHint一個reporter。這裡我使用預設的reporter,適用於大多數人。更多有關此設定,你可以在JSHint網站取得。

圖片壓縮

接著,我們將設定圖片壓縮:

gulp.task('images', function() {  
  return gulp.src('src/images/**/*')
    .pipe(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true }))
    .pipe(gulp.dest('dist/assets/img'))
    .pipe(notify({ message: 'Images task complete' }));
});

這會將對所有來源圖片進行imagemin處理。我們可以稍微更進一步,利用快取保存已經壓縮過的圖片,以便每次進行此任務時不需要再重新壓縮。這裡只需要gulp-cache外掛–稍早已經安裝。我們需要額外設置才能使用這個外掛,因此修改這段程式碼:

.pipe(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true }))

成為這段:

.pipe(cache(imagemin({ optimizationLevel: 5, progressive: true, interlaced: true })))

現在只有新的或更動的圖片會被壓縮。乾淨俐落!

收拾乾淨!

在我們進行佈署之前,清除目的地目錄並重建檔案是一個好主意–以防萬一任何已經被刪除的來源檔案遺留在目的地目錄之中:

gulp.task('clean', function() {  
  return gulp.src(['dist/assets/css', 'dist/assets/js', 'dist/assets/img'], {read: false})
    .pipe(clean());
});

我們可以傳入一個目錄(或檔案)陣列到gulp.src。因為我們不想要讀取已經被刪除的檔案,我們可以加入read: false選項來防止gulp讀取檔案內容–讓它快一些。

預設任務

我們可以建立一個預設任務,當只輸入$ gulp指令時執行的任務,這裡執行三個我們所建立的任務:

gulp.task('default', ['clean'], function() {  
    gulp.start('styles', 'scripts', 'images');
});

注意額外傳入gulp.task的陣列。這裡我們可以定義任務相依(task dependencies)。在這個範例中,gulp.start開始任務前會先執行清理(clean)任務。Gulp中所有的任務都是並行(concurrently)執行,並沒有先後順序哪個任務會先完成,所以我們需要確保clean任務在其他任務開始前完成。

注意: 透過相依任務陣列來執行clean而非gulp.start是經過考慮的,在這個情境來看是最好的選擇,以確保清理任務全部完成。

看守

為了能夠看守檔案,並在更動發生後執行相關任務,首先需要建立一個新的任務,使用gulp.watchAPI來看守檔案:

gulp.task('watch', function() {

  // 看守所有.scss檔
  gulp.watch('src/styles/**/*.scss', ['styles']);

  // 看守所有.js檔
  gulp.watch('src/scripts/**/*.js', ['scripts']);

  // 看守所有圖片檔
  gulp.watch('src/images/**/*', ['images']);

});

透過gulp.watch指定想要看守的檔案,並且透過相依任務陣列定義任務。執行$ gulp watch來開始看守檔案,任何.scss.js或圖片檔案一旦有了更動,便會執行相對應的任務。

即時重整(LiveReload)

Gulp也可以處理檔案更動後,自動重新整理頁面。我們需要修改watch任務,設置即時重整伺服器。

gulp.task('watch', function() {

  // 建立即時重整伺服器
  var server = livereload();

  // 看守所有位在 dist/  目錄下的檔案,一旦有更動,便進行重整
  gulp.watch(['dist/**']).on('change', function(file) {
    server.changed(file.path);
  });

});

為了讓這個功能有效,除了伺服器之外,還需要安裝並啟用LiveReload的瀏覽器外掛。或者你也可以手動加上這個片段程式碼

全部在一起

這裡是完整的gulpfile:

// 載入外掛
var gulp = require('gulp'),  
    sass = require('gulp-ruby-sass'),
    autoprefixer = require('gulp-autoprefixer'),
    minifycss = require('gulp-minify-css'),
    jshint = require('gulp-jshint'),
    uglify = require('gulp-uglify'),
    imagemin = require('gulp-imagemin'),
    rename = require('gulp-rename'),
    clean = require('gulp-clean'),
    concat = require('gulp-concat'),
    notify = require('gulp-notify'),
    cache = require('gulp-cache'),
    livereload = require('gulp-livereload');

// 樣式
gulp.task('styles', function() {  
  return gulp.src('src/styles/main.scss')
    .pipe(sass({ style: 'expanded', }))
    .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
    .pipe(gulp.dest('dist/styles'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(minifycss())
    .pipe(gulp.dest('dist/styles'))
    .pipe(notify({ message: 'Styles task complete' }));
});

// 腳本
gulp.task('scripts', function() {  
  return gulp.src('src/scripts/**/*.js')
    .pipe(jshint('.jshintrc'))
    .pipe(jshint.reporter('default'))
    .pipe(concat('main.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe(notify({ message: 'Scripts task complete' }));
});

// 圖片
gulp.task('images', function() {  
  return gulp.src('src/images/**/*')
    .pipe(cache(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true })))
    .pipe(gulp.dest('dist/images'))
    .pipe(notify({ message: 'Images task complete' }));
});

// 清理
gulp.task('clean', function() {  
  return gulp.src(['dist/styles', 'dist/scripts', 'dist/images'], {read: false})
    .pipe(clean());
});

// 預設任務
gulp.task('default', ['clean'], function() {  
    gulp.start('styles', 'scripts', 'images');
});

// 看手
gulp.task('watch', function() {

  // 看守所有.scss檔
  gulp.watch('src/styles/**/*.scss', ['styles']);

  // 看守所有.js檔
  gulp.watch('src/scripts/**/*.js', ['scripts']);

  // 看守所有圖片檔
  gulp.watch('src/images/**/*', ['images']);

  // 建立即時重整伺服器
  var server = livereload();

  // 看守所有位在 dist/  目錄下的檔案,一旦有更動,便進行重整
  gulp.watch(['dist/**']).on('change', function(file) {
    server.changed(file.path);
  });

});

你也可以在gist看整個gulpfile。我也將達到相同任務的Gruntfile放在同一個gist,方便做比較。

如果你有任何疑問或議題,請在文章下方留下評論或者可以在Twitter找到我。

阅读详情 -> gulp入門指南.

Categories: JavaScript, 前端工具