ppk on JavaScript第二章:背景(完结篇)

无障碍规则
尽管无法预见可能损害一个有脚本网站的可用性的所有情形,但我已经总结出一些可以帮助您在基础上不犯错的规则。不要把它们当作JavaScript和无障碍的终极规则,这只是能防止一些常见低级错误的规则集,别怀疑它们可能会增增删改一旦某些规则在某些场合下不凑效。

在检验这些规则时别忘了加上您的思考。

逻辑上的HTML
在一个有脚本的环境中保持无障碍的最明显的方式莫过于确保平白的HTML页面包含所有必须的骨架,来保证成功的浏览。

内容、导航和重要的表单应该硬编码(hard-coded, 表示非脚本生成的代码)进您的HTML中,用户将能访问和使用它们。

合用表单(书中例子)就是一个好例子。当浏览器不支持JavaScript,表单依然可访问因为所有的表单字段和标签都硬编码进HTML中去了。尽管更少可用性,但如我们所见,这是不可避免的。

硬编码连接和href
您的HTML中所有硬编码连接都应该有一个href属性,并指向一个有用的页面或者其他文件。所以,这是错误的:

<a href="#" onclick="showPopup('niceimage.jpg')">Nice image!</a>当一个无脚本用户点击连接,什么也没发生,因此这页面是有障碍的。此外,我们前面也讨论过,不应该再使用内联事件句柄。

相反,unobtrusive JavaScript编程者会这样做:

<a href="niceimage.jpg" id="nice">Nice image!</a>
document.getElementById('nice').onclick = function () {
    showPopup(this.href);
}现在,无脚本用户能够访问到硬编码的href属性了,同时脚本用户打开一个新窗口。网站能够保持无障碍,行为也从结构中分离出来了。

生成内容意味着只有脚本用户才能访问
某些场合下,由JavaScript生成内容(generating content)让一个站更有障碍。

触发先进脚本的连接
假设您有一个连接,用于触发时髦的Ajax脚本来获取内容并大大增强可用性,但没有一个HTML页面可供连接。我们刚刚看到的,这是错误的:

<a href="#" onclick="startUpAjaxStuff()">Commence coolness!</a>但我们不能应用上一条规则了。我们该把哪个页面的连接放进href里呢,如果我们压根就没有一个跟Ajax脚本等价的无脚本页面?

如果要为连接增加一个没啥道理的href,那么交给JavaScript来生成吧:

var link = document.createElement('a');
link.href = '#';
link.onclick = startUpAjaxStuff;
var linkText = document.createTextNode('Commence coolness!');
link.appendChild(linkText);
document.body.appendChild(link);现在,无脚本用户根本看不到这个连接了。很好,因为它不会干任何事情如果被点击,还会制造困扰。

注意该例子脚本为link.href设置了”#”,尽管我们看到了使用”#”并不是什么好主意。但我们需要它:大部分浏览器把连接定义成一个a加上一个href属性。

幸运的是,前一条规则不会在这种情况下应用,因为该连接没有硬编码进HTML,只是由JavaScript生成的。我们可以确保只有有脚本的用户才能邂逅这个连接,同时也可以运行事件句柄。因此, href="#"在此是被允许的。

在JavaScript中隐藏内容
隐藏内容是危险的。一般上,您隐藏内容是因为您不想把所有东西一下子展示给用户以提高可用性。您等待用户点击连接然后通过运行脚本来展示内容。

没有JavaScript的话,内容将永远不会展示出来,页面就变得有障碍起来。如果您创建一个必须由用户激活脚本才能展示内容的页面,您应该把“隐藏内容”的命令交给JavaScript而不是CSS。

比如,合用表单初始隐藏所有的带rel属性的tr。这可用CSS来达到,但这完全是错误的:

tr[rel] {
     display: none;
   }如果一个无脚本用户访问到您的页面,他看不到这些tr,而且没有任何方式让它们展示出来。因此页面也是有障碍的。

相反,合用表单使用JavaScript来隐藏tr(事实上,从文档中完全删除了)。如果JavaScript没有启用,它们不会隐藏,因此保持了无障碍。

重定向
偶尔,处理无障碍问题的最佳方式是为网站同时创建脚本和无脚本版本。尽管我不喜欢这个解决方案并试着避免,但是无论如何在实践中有它的价值。

如果您使用这种方法,您应该遵循两条规则。首先,站点入口页应该使用无脚本页面,因此,所有的浏览器,就算只支持HTML而已,也能获取它们能用的页面。

然后,一旦浏览器载入了页面,运行脚本来检测浏览器是否支持您的先进脚本,如果支持,重定向一个脚本页面,使用replace()方法。

<head>
<title>Noscript page</title>
<script type="text/javascript">
var isSupported = [check JavaScript support];
if (isSupported)
    location.replace('scriptpage.html');
</script>
</head>永远不要在这种情形下使用location.href,因为它将创建新的浏览器历史记录。如果用户载入了无脚本页面,她被重定向到有脚本页面。一旦她按“后退”键就会回退到无脚本页面,但是脚本又会触发把她带回到有脚本页面。“后退”键在种情形下成了可用性的罪魁祸首。

location.replace()也会载入新页,但它不会历史记录中留下痕迹。当用户按“后退”键,她被带回到载入无脚本页面之前的页面。从用关注的角度来说,“后退”键功能依然正常。

键盘用户
我们已经了解到键盘用户没有鼠标事件(除非他们使用屏幕阅读器)。因此,您应该定义鼠标事件的可替换方案。有时这很简单,比如,使用聚焦事件匹配鼠标悬停事件;有时是很困难的,比如,拖拽脚本,您必须写更多的额外功能来特殊照顾键盘用户。

可点击项目
就算您创建了键盘可访问的脚本,如果用户不能聚焦于您定义事件句柄的元素上,也是无用的。

比如下拉菜单(书中例子)。它使用鼠标悬停来触发下拉,根据前面的规则,我为键盘用户增加聚焦事件。但是,为了能触发聚焦事件,键盘用户必须能够聚焦下拉菜单。如果这不可能,那么脚本依然有障碍。

所有浏览器中可信赖的能够获取焦点的元素是连接,表单字段和按钮。因此,任何键盘友好的事件或者脚本都应该在这些HTML元素上设置。

下拉菜单也这么做,聚焦事件都被赋予连接上。因为键盘用户可以聚焦连接,脚本依然对他们无障碍。

noscript标签
浏览器厂商知道web开发者可能需要为无脚本的用户提供特别的内容,所以发明了noscript标签。

它如此工作:

不支持任何JavaScript的浏览器不支持这个标签。因为非支持的标签会被HTML解析器忽略,这些浏览器显示这个标签的内容:无脚本内容。
支持JavaScript的浏览器检查浏览是否启用了JavaScript。如果是,它们隐藏noscript标签和其内容;如果不,浏览器显示该标签内容。
不幸的是,在当代无障碍开发中noscript标签并不会扮演很重要的角色。大量的浏览器支持过时版本的没有W3C DOM, XMLHttpRequest或者其他的当代特点的JavaScript。这些浏览器不会显示noscript内容因为他们支持部分的JavaScript。因此其用户就像无脚本用户,不会看到脚本化的界面,但同时也看不到额外的无脚本内容。

所以,能不用noscript就不用。

更新:ppk on js的读书笔记暂告一段落,有兴趣的读者请读原版或者等待中文版的上市。另,推荐{|ihower.idv.tw| blog }上的javascript资源,他那里也有ppk相关的读书笔记。

ppk on JavaScript第二章:背景(二)December 27, 2006

ppk on JavaScript 学习笔记 固定连接 8条留言

这一章讲的太多是开发观念,为其他书所不或很少提及的。所以我基本上全译而不是精简笔记。以后的技术章节我可能只记录一些需要注意的问题,否则我就是在翻译这本书而不是作读书笔记了。因为是全译,所以有点长,故这一章还未完结,请耐心等待第三部分,如果您真的在等的话。以下是正文:

分离行为和表现
第三层分离,行为和表现,恐怖要比前两种分离更复杂。别期待我会给您清晰的答案,该分离还属于当代JavaScript编程领域中尚未能够明确化到容易学习和理解规则的范围内。现在我们的问题比答案还多。

最基本的问题是:哪种效果您应该定义到CSS中,哪种应该定义到JavaScript中?尽管表现应定义在CSS中而行为应定义在JavaScript中的问题很明显,但是它们存在一个交错的灰色地带,某些效果是属于表现还是行为并不清晰。

下拉菜单: hover还是mouseover/out?
下拉菜单的目的是,当用户鼠标悬停时显示次级菜单,移开时隐藏,从远古时代(精确地算的话,1997年)起我们就用JavaScript获得这种效果。那时我们没有其他选择,如果您要下拉菜单,您只能用JavaScript。

尽管如此,时代的进步让您现在可以使用CSS来实现,无须任何JavaScript:

<li><a href="#">News</a>
  <ul>
    <li><a href="#">Press Releases</a></li>
    <li><a href="#">News Articles</a></li>
    ... ...
  </ul>
</li>

// in .css file
li ul {display: none;}
li:hover ul {display: block}
在li内的ul次级菜单,初始隐藏(display: none),当鼠标悬停li上,通过li:hover,次级菜单即可展示出来(display:block)。

哪种方案更可取?大部分人将选择JavaScript因为IE6及更早版本并不支持li:hover。

但是,这个现实的答案并未能回答到根本。我们来假设下当所有浏览器都完美支持:hover时(别怀疑,IE7已经实现),CSS和JavaScript方案都兼容浏览器了。我们选择谁?

CSS代码比JavaScript简单多了,理由当然有其优越性。我们会在后面的章节看到,JavaScript鼠标移开事件,特别令人憎恶,要玩得起它,必须有一手过硬的技术。相比之下,CSS :hover 选择器……真的跑起来了。

此外,CSS可以在JavaScript“残掉”的时候继续工作。不过,这并不意味着CSS必定比JavaScript更具无障碍。

有些人用键盘代替鼠标。他们使用按键(一般是Tab键)捕获HTML元素(通常是连接),然后按回车来激活已捕获元素。键盘用户没法使用CSS下拉菜单,因为li:hover仅仅是一个鼠标选择器,没有对应的键盘。此外,没法捕获li因为键盘仅能捕获连接,按钮和表单域。

反之,JavaScript能通融键盘用户。因此CSS下拉菜单未必本来就比JavaScript版更无障碍。键盘用户更喜欢JavaScript版本下拉菜单。

实际上,它们都有各自的问题。下拉菜单是表现还是行为?该效果只在用户行为下才触发,这表明它是行为。另一方面,该效果是关于展现次级菜单的,这表明它是表现。

尽管个人倾向于行为答案,但问题允许有多个答案,每个web开发者都应招到自己的解决方案,忽略这些理论假设吧。

总之,CSS :hover方案比起JavaScript mouseover/out的来明显的得分点只在于更少的代码和维护。但这是CSS方案比JavaScript方案好的充分理由吗?还是要取决于个人的选择。

相同效果 vs. 相似效果
在下拉菜单中,您需要给每个被选中的li部署相同的效果。“如果li内有一个嵌套的ul,当鼠标悬停li时显示它”。如我们所见,这很容易折合归纳成以下两行CSS:

li ul {display: none}
li:hover ul {display: block}太简单了,因为所有的li效果都一样。

现在我们来个不一样的例子:a鼠标悬停。当用户鼠标停在图片上,图片改变,鼠标移开,图片变回原来的。

之前,所有的鼠标悬停效果都用JavaScript来实现,这是传统。JavaScript鼠标悬停效果是最受欢迎的宠物自从1996年诞生以来,并且是WWW中被拷贝最多的脚本。因为已经存在银河沙数的脚本例子,没人移植到CSS上。

即使如此,理论上,创建CSS鼠标悬停效果是可以的:

<a href="somewhere.html" id="somewhere">Somewhere</a>
<a href="somewhere_else.html" id="somewhere_else">Somewhere else</a>
a#somewhere {
    background-image: url(pix/somewhere.gif);
}
a#somewhere_else {
    background-image: url(pix/somewhere_else.gif);
}
a:hover#somewhere,
a:focus#somewhere,
a:active#somewhere {
    background-image: url(pix/somewhere_hover.gif);
}

a:hover#somewhere_else,
a:focus#somewhere_else,
a:active#somewhere_else {
    background-image: url(pix/somewhere_else_hover.gif);
}您会注意到每个鼠标悬停效果都需要两条CSS语句,一条定义普通状态,另一条定义鼠标悬停状态。原因很简单:每个连接都有起独自的普通状态和鼠标悬停状态图片,这些不同的图片需要在CSS中定义。

在这个案例中我们不能为所有的连接部署相同的效果,但它们效果很相似。所有的连接都会在鼠标悬停时改变图片,但每个连接都需要属于其自身的图片集合。每添加一条新连接我们都必须增加两条CSS语句,而且必须是手工的。无法改变的事实是,一个单纯的CSS鼠标悬停很快就会变成维护地狱,尤其是在几打连接上使用时。

这只不过是一条常规罢了。当您需要给一些元素部署相同的效果时CSS特别高效,就像上面的下拉菜单例子,然而在一些类似的效果上,CSS显得低效,就像刚才那个鼠标悬停例子。

而JavaScript允许您写一个管理您不愿意计算有多少的连接的脚本:

<a href="somewhere.html"
id="somewhere"><img src="pix/somewhere.gif" /></a>
<a href="somewhere_else.html"
id="somewhere_else"><img src="pix/somewhere_else.gif" /></a>
function initMouseOvers() {
     var links = document.getElementsByTagName('img');
     for (var i=0;i<links.length;i++) {
             var moSrc = links[i].src.substring(0, links[i].src.lastIndexOf('.'));
             moSrc += '_hover.gif';
             links[i].moSrc = moSrc;
             links[i].origSrc = links[i].src;
             links[i].onmouseover = function () {
                    this.src = this.moSrc;
             }
             links[i].onmouseout = function () {
                    this.src = this.origSrc;
             }
     }
}起初,这个方案需要比CSS更多的代码行,但它的强大远远抵消这个坏处。如果您需要另一个悬停,您只需把连接加上,ok,它自己自动工作了。

因此,当创建这些类似但不相同的效果时,JavaScript方案更高效。当您面临选择CSS还是JavaScript时请记得这点。

现在还不可能得出一个关于表现和行为分离绝对的结论,有待更多的调研,现在我更希望您花些时间考虑一下这个问题,无论您是否遭遇类似问题,一旦您发现有更好的规则,分享出来吧!说不定您就是第三种分离的规则领导者。

无障碍概览
我已经不止一次提及无障碍了,而且是通常伴随着讽评普遍缺乏它的JavaScript开发中。是时候来个概览了,同时给我们的例子来个无障碍测试。

什么是无障碍
无障碍是指在大部分情况下,尤其在用户不可改变的某些条件,比如视力衰减,或者使用一个不支持(足够)JavaScript的浏览器,您的网页依然可以使用。

在JavaScript情景中“依然可以使用”是什么意思?它表示,用户必须可读站点内容,使用导航,并且能进行一般的操作比如提交表单。少不了,也不多。

在任何情况下都完美无障碍是一宗大案,我们可以看到,在著书的这段时期,屏幕阅读器某些繁杂的技术问题更是让完美是难以企及。但是,我们应该从现在就开始,因为我们能够,所以我们就应该解决某些无障碍问题。

无脚本
最明显不过的无障碍问题,任何人都可指控的,就是某些浏览器不支持(足够)JavaScript. 您小心翼翼打造的脚本这些浏览器并不买帐,用户看到的是未经脚本处理过的页面。

编写无障碍脚本的天字第一号准则是,理所当然,是确保没有JavaScript页面功能依然。稍后我们会继续讨论这些骇人听闻的细节,但现在我更想先讨论两条不太为人所知但很严重的无障碍问题。

无鼠标
某些用户不用鼠标,使用击键来操纵页面。有的用键盘,有的用小物件比如屏幕触摸键盘,或者是其他模拟键盘的设备。

使用击键代替鼠标的原因可能有多种。我自己偶尔情况下会使用键盘来实现某些快速操作,显然这是我自己的选择。我可以用鼠标,但有时我很懒。

但,其他用户,可能只能一直使用键盘,有些条件是他们改变不了的。最可能的场景是,这些用户的手(部分)残障或者不能精确地移动鼠标。击键给他们提供了另外更好的选择,除非JavaScript开发者忽视了他们。

通常这些用户的浏览器能够执行先进的脚本,并且他们能够看到屏幕上的反馈结果。所以并没有什么大问题,除非脚本对键盘输入无反应。

为了让您的脚本兼容键盘,除了鼠标事件之外,您应该增加定义额外的事件。比如,如果您使用鼠标悬停事件就应该使用聚焦(focus)事件,因为没有鼠标就不会有鼠标悬停事件的发生。

屏幕阅读器
有些人不能使用普通的浏览器。比较典型的是盲人或者视力严重损害得阅读不了电脑屏幕的任何东西。反而,他们需要一个能够大声朗读页面内容的程序。这些程序就是屏幕阅读器。

JavaScript开发者通常认为屏幕阅读器根本就是不支持脚本的浏览器,因此屏幕阅读器的无障碍只不过是无脚本用户的扩展而已。无JavaScript的页面只要工作,盲人用户就不会遭遇有关JavaScript的问题(尽管大量的其他问题像缺少alt依然存在)。

不幸的是,这是个神话。大部分屏幕阅读器都运行在已有的有时是IE有时是Mozilla的浏览器上。因为它们使用普通的浏览器来获取数据,它们也支持JavaScript。当基础的浏览器碰到脚本,它一般会试着去执行。

似乎是个好消息。如果屏幕阅读器也支持JavaScript,那就没有问题了,对不?很不幸,有两大严重的问题:屏幕阅读起的线性性质,及其混乱的事件支持。

屏幕阅读器只支持线性处理页面。当一个视力明朗的用户使用一个图形浏览器访问网站,她简单一瞥就能获得网站的总览。左边那些古怪颜色可能就是主导航,中间的文本就是主要内容,等等。因此用户能够迅速地决定哪些是她需要的,并于这些交互。此外,一旦脚本改变了文档结构或者表现,她的眼睛能被吸引过去并能揣测其含义。

但屏幕阅读器用户不会如此。屏幕阅读器从头到脚把页面读个遍,一般是按照源代码的顺序。这是一个严重的问题,对当代JavaScript来说。就算所有屏幕阅读器完美支持JavaScript,我们怎样才能提示其用户页面部分已改变,尤其是屏幕阅读器已经读过这些部分?

拿表单验证(本书有几个例子贯穿始终,这是其中一个)的例子来说,假设它运行在一个完美支持JavaScript的屏幕阅读器中,允许用户填写和提交表单。因为JavaScript工作完美,一旦用户激活提交按钮,表单验证程序就会运行。如果有错,脚本就会提示“出错”,并停止提交。

问题在于,屏幕阅读器可能(但不总是)会听到提示并得到问题的某些暗示,但是阅读器已经读过表单域,他不会听得到错误。

为了帮助屏幕阅读器用户,表演验证回滚到表单的开头:

<form id="startOfForm">
if (!validForm) {
    alert("Errors have been found");
    location.hash = '#startOfForm';
}这对视力未损或者已损的用户都有好处,他们都会觉察到返回表单的开头,所以能够以其方式修正错误。但是,需要注意的是,这对视力良好的用户来说是一个额外的特色,但对视力有损的用户来说是一个绝对的必须!

屏幕阅读器和事件
不幸的是,屏幕阅读器的事件支持非常混乱与无序。理论上您希望它们能支持界面事件如聚焦和模糊,但不支持鼠标悬停与离开,因为屏幕阅读器用户使用键盘(或者等价的设备)来输入。

更不幸的是,有些屏幕阅读器厂商不管怎么还是把鼠标事件引入。理由是,大部分网站只使用鼠标事件因为制作者永远不考虑键盘的可访问性。厂商们需要他们的程序能够正确处理这些页面,因此增加鼠标事件。当然这会产生严重的问题,当一个关注无障碍的web开发者需要小心区分屏幕阅读器和图形浏览器来给予不同的处理。

我不想继续讨论细节了,它们让您迷惑(我也是),屏幕阅读器的事件支持在新版本发布时可能会改变。假如您不能预测屏幕阅读器的事件支持,那就罢了吧。

现实情形太差了,我担心目前屏幕阅读器的无障碍并不会有更新换代的革命性发展。Derek Featherstone无情但正确的结论是:我们可以处理JavaScript的开或关,但不能处理中间状态,因此他感到旧屏幕阅读器让用户选择完全禁止JavaScript的方式更好。如果这样,他们会回到一个没有脚本的页面,这个问题我们可以处理的。

此时,根据我们对屏幕阅读器的JavaScript支持的认知程度,我只能同意Derek Featherstone,尽管是勉强的。无脚本屏幕阅读器比启动了脚本的屏幕阅读器更好照顾。

无障碍和可用性
回到起点:任何网页都无障碍在浏览器不支持(足够的)JavaScript的情况下。我们来讨论一些通用的规则。

我们应该三思JavaScript的目的,就是增加网站额外的一层可用性。一旦JavaScript失效,网站的可用性必经会受损害,整层都消失了。但该层的缺席不应该损害页面最基本的无障碍。

拿合用表单(另一个例子)来说。当脚本运行时,毫无疑问用户会看到他所需要的特定表单字段。当脚本不能执行时,用户会看到他可能需要的所有表单字段。从可用性角度来看,这确实是令人讨厌的:用户看到的表单字段阅读,他可能越迷惑和恼怒,并且很有可能决定不去理会这些表单了。

但是,页面保持了完美的无障碍,我已经尽了我作为web开发者的责任。用户依然可以填写表单并提交到服务器,即使没有我便利的脚本来处理过的过程会变得耗时和困惑。用户可能不愿填表因为太长和困惑,但这是我们力不能及的地方了。当JavaScript不被支持,可用性受损。

别限制了可用性
无障碍不应该限制可用性。如果您有一个JavaScript必不可少的精彩绝妙的主意来增加网站的可用性,请使用它,但尽可能(但不是必须)确保页面能用。

完美的无障碍并不是由为有脚本和无脚本用户提供相同的功能组成的。有时就是直截了当的不可能。

比如,让我们来尝试不用JavaScript来创建合用表单(还是前面提到的例子)。您可以先提供一个没有可选项的表单,让用户提交到服务器,根据用户的选择让服务器返回其他的选项。技术上,这是可行的。

但是,从用户体验的观点来看,它比我们刚才研究的无脚本表单更糟糕。尽管那可能迷惑并且没有比脚本化的版本有用,但至少不需要额外的下载和字段,而用户也可能误认为自己已经成功提交了表单。

总而言之,最好接受可用性缩减了的无脚本页面,总比费心思补救好。

ppk on JavaScript第二章:背景(一)December 21, 2006

ppk on JavaScript 学习笔记 固定连接 22条留言

JavaScript为网页而存在,它会被嵌入到一个同时使用HTML和CSS的环境中,而此环境中不可缺少可用性和无障碍。总而言之,脚本必须给站点增加用处,而站点在JavaScript失灵或者根本不存在的情况下依然能继续工作。兼容标准的CSS革命改变了Web开发,JavaScript编程也受到这场运动的巨大影响。

CSS革命
1998年,在Netscape和IE4无法达成任何协议时,一些先天下之忧而忧的Web开发者组成了 Web Standards Project(Web标准工程,简称WaSP),为解决JavaScript某些荒唐的私有元素,并推动使用CSS来定义网站的外观。她们的重要使命是“追随标准”,不仅针对浏览器厂商,而且号召Web开发者。

最初,WaSP及其支持者专注于CSS. 究其原因,CSS是一门比较新的技术,尚未被乱七八糟的东西污染,更容易成为历史的一个转折点,JavaScript就没有这么幸运了,那时候的JavaScript,无论是编程,还是人们对它的想法,都是完全非无障碍的。这也是导致某些标准支持者产生“JavaScript就是障碍”观念的原因,无论是过去还是现在。其实,JavaScript和无障碍可以和谐共存,只要您稍微谨慎。

Unobtrusive脚本编程
2002年,Stuart Langridge创造出Unobtrusive脚本编程(unobtrusive scripting, Stuart Langridge的原文),这是首次重要的尝试——在基于CSS,标准兼容的新理论中嵌入JavaScript.

Unobtrusive脚本应该具备一下所有的特征:

可用性,比如,赋予网站明确的可用性好处;
无障碍,比如,假使JavaScript失效,页面应该保持可读和可理解,尽管不可避免地丧失某些可用性;
容易实现,一个经典案例是,Web开发者只需把脚本引入和增加一个JavaScript调用钩子(hook),脚本就起作用;
分离,属于本身的.js文件而不是散落在HTML的各个角落。
理论上说,第一条自JavaScript诞生之日起就有的,但是经常会被程序员在炫耀JavaScript能力的热忱中忽略。如果没有可用性多酷都无关紧要。

其他三条都是新的。通常都认为无障碍和JavaScript是互斥的。容易的实现需要JavaScript钩子,W3C DOM的降临使之成为可能。分离,是偷师于CSS革命的。如果需要分离HTML和CSS, 逻辑上,也应该把JavaScript从它们中分离。

三个层面
网页包含三个层次(没错,它们都需要各自分离):


HTML结构
CSS表现
JavaScript行为
HTML结构层是网页最重要的基础。HTML标签给予内容含义。CSS表现层则是定义您的HTML该如何显示。JavaScript行为层为页面增加交互。

不管如何,一个网页必需HTML结构层。没有HTML,没有网页。CSS和JavaScript都是可选项,旧的,无名的,罕见的浏览器可能不支持CSS和/或JavaScript,在这种情形下,这两层或其中一层都不起作用。后果是显而易见的,任何网站应能在行为层(或者表现层,但这种情形相比较少)的缺席下还能“存活”。也就是说,网站不能完全依赖于JavaScript,但要保证无障碍即使JavaScript不起作用。

分离的关系
一般来说,最好单独管理好每一层。最基础的,确保:

HTML是结构性的,不要太复杂,没有CSS和JavaScript下保持语义。
CSS表现层和JavaScript表现层分别归属于独自的.css和.js文件。
分离更容易维护。您可以轻而易举地把分离的文件连接到整站的网页上,简单举个例子,您需要把字体从12px改成0.8em,您只需打开CSS文件编辑它,这样网页变化即刻生效。除此之外,分离让您可以不需修改HTML结构层或者JavaScript行为层,只需修改整个CSS表现层就可让网站换上新衣。

分离表现和结构
表现和结构分离的基本思想是确保HTML定义结构,只有结构,所有的表现都定义到分离的CSS文件中去。不再允许font标签或者表现性的表格!在一本JavaScript的书中似乎没有什么余地来探讨CSS和HTML的分离。那么我们就来说说这个分离对我们编写JavaScript代码方式的影响吧。

CSS更改
JavaScript可以让您修改CSS,比如,您可以在CSS定义一个连接为红色,然后用JavaScript控制CSS再定义为绿色。有时候这是很有用的,样式的变化会使用户能注意变化的HTML的元素,比如出错信息。如果没有正确地分离CSS表现层,CSS更改将会变得十分困难。改变元素的className通常是最佳的CSS更改方式。如下例子,假如表单验证程序发现用户输入错误,则改变该表单字段的class:

// obj is the form field
obj.className += ' errorMessage';

// in CSS
input.errorMessage {
    border: 1px solid #cc0000;
}只有您正确分离了表现和结构,这样的方式才会起作用。class errorMessage必须定义在CSS中为了实现样式的更改,反过来,也只有您一开始就从正确的CSS表现层开始才有可能(或者说,可行)。

修改结构还是表现
JavaScript实际上允许您改变网站的表现,也允许您改变HTML文档。用户并不关心我们改了什么。但还是有所不同的。改变一个应答用户行为的表单应该是修改结构而不是表现。相关表单元素不应该只是从视觉上隐藏而已,而应该从文档结构中移除。当一个表单提交时,浏览器为所有表单元素创建名称/值配对,并发送给服务器。如果仅仅是在CSS中隐藏,这些字段依然是表单的组成部分,尽管可能不是服务器所需要的。这只是理论上的东西,您可以不同意我。

分离行为和结构
分离行为与结构很容易理解:不要把任何JavaScript代码写入HTML页面中。采取这两步:

把所有的JavaScript函数定义在一个分离的.js文件中,让所需的HTML页面连接到它。
删除所有的事件处理句柄(注:即行内的那些诸如onmouseover)并归入同一.js文件中去。
分离文件中的函数
JavaScript代码属于.js文件,而非HTML文件。

所以这是错误的:

<script type="text/javascript">
 function doAllKindsOfNiftyThings()
 {
     // JavaScript code
 }
 </script>
 </head>
 <body>
 <h1>My HTML page</h1>
 [etc.]这才是正确的:

</head>
<body>
<h1>My HTML page</h1>
[etc.]

// 定义在分离的nifty.js中
function doAllKindsOfNiftyThings()
{
    // JavaScript code
}删除事件处理句柄
第二步是把所有HTML内的JavaScript函数调用移到分离的.js中去。事实上,99%的HTML内的JavaScript代码是行内事件句柄。

以下,句柄在HTML内,但不应该属于HTML的:

<a href="home.html" onMouseOver="mOv('home')" onMouseOut="mOut('home')">Home</a>应该定义在分离的.js文件中去:

<a href="home.html">Home</a>
// in separate .js file
var nav = document.getElementById('navigation');
var navLinks = nav.getElementsByTagName('a');
for (var i=0;i<navLinks.length;i++)
{
    navLinks[i].onmouseover = [code];
    navLinks[i].onmouseout = [code];
}该脚本处理id="navigation"的元素并处理其内的所有连接,然后再赋予连接事件处理句柄。

javascript:伪协议
有些情况下你会看到像以下的javascript:伪协议:

<a href="javascript:doAllKindsOfNiftyThings()">Do Nifty!</a>

这个复杂肮脏代码隐藏的含义是一个onclick事件句柄:当用户点击该连接,我们需要的是呼叫doAllKindsOfNiftyThings()函数。所以您应该从该连接中删除javascript:呼叫而用一个独立.js文件中的onclick事件句柄来取代之:

<a href="somepage.html" id="nifty">Do Nifty!</a>
// in separate .js file
document.getElementById('nifty').onclick = doAllKindsOfNiftyThings;
因此,对于href,应该包含一个完整的url以备没script的用户能够访问,否则整条连接都由JavaScript产生,不具备无障碍性。

注意:以下内容非正文!

p.s.有人点名要爆隐,没办法,只好完成指标:

新千年,学会上网,为了能向心爱的女孩子炫耀,学做网页,想不到现在就跟网页打交道。
新世纪,开日在江西某所大学无所事事,所念专业跟以后的工作一点关系都没有,世界真奇妙。
继续无所事事……
继续无所事事……
继续无所事事……
开始在网上写blog, 让人知道我多多少少还是知道web标准的,在这行业资源匮乏的时候幸运地到了北京工作,并不断进步。
跳了两次槽,希望有个好开始。
不好意思,还有几天才到这个年龄。
JavaScript的目的November 19, 2006

ppk on JavaScript 学习笔记 固定连接 22条留言

从今天起,我将陆续将 ppk on JavaScript 的读书心得发布到这个blog上。ppk是我所景仰的一位web开发者,原因无它,只是因为作为一个JavaScript的开发者来说,他涉及的领域包括web标准,可用性,无障碍等,正是其他开发者所不关注或者故意忽略的。并且,他写了很多案例测试不同的浏览器,总结出JavaScript的接口(API)兼容性,成为JavaScript开发者重要参考资料,几年如一日,这种钻研精神是很多人所缺乏的。

ppk在今年9月出版了他的书,我从去年起就在等的书。今天拿到手,迫不及待地把第一章阅读完毕。果然让人充满惊喜,他的功力非同一般。虽然只是一个初学者,但我认为我已经走在正确的学习道路上。我想,我若能将学习心得分享,能让正在学习的人看到,可以一起交流一起进步,尽管我不敢确保你能从我这里得到什么启发,但我可以确信,我这些笔记会比你拷贝粘贴代码的学习方式更正确。

这本书有十章,章名都简洁明了,分别是:目的,背景,浏览器,准备,核心,BOM, 事件,DOM, CSS更改和数据获取。从来没有一本书能如此简洁地明确JavaScript的方方面面,因此学习不会有太大负担。前言不宜过多,下面就开始我的第一章学习笔记。

开篇宗义:JavaScript的目的是,为网页增加特别的一层可用性。听起来很简单,但这条黄金定律经常被人误解。就算编写有用的JavaScript, 开发者可能还是没能结合适当的情景:Web标准运动发展下,与当代无障碍的HTML页面的配合。更为不妙的是,有些开发者不是为网页增加一层可用性,而是用整层取代之,后果是,如果浏览器不支持JavaScript, 网站就完了。

概念概述
JavaScript是一门由浏览器解释的脚本语言。它通过在客户端而不是服务器端处理某些交互,比如表单验证,创建新菜单来给网站增添可用性。传统的网页交互是,客户端的一举一动都必须经过服务器端的出来才能反馈回来,漫长的等待会让用户崩溃。而JavaScript可以在客户端代替服务器端做某些事情(最明显的,表单验证),从而提高用户体验。

随着时代的发展,JavaScript能够处理越来越多的交互。问题出现了,JavaScript能做这么多事情,到底要多用还是少用?这就有了富与瘦的对决。是整个页面都用JavaScript来控制交互还是只增加些许的JavaScript来增强可用性?就是说,尽可能地使用JavaScript还是有所节制,甚至不用?

瘦客户端很大程度上依赖于客户端-服务器的通讯,而富客户端尽可能限制额外的数据通讯。

哪种方式更好?尽管富客户端带来一些可用性益处,但瘦客户端可能是更“标准”的JavaScript用法。Web被认为是文档集合,而不是界面集合。最明显的证据是,浏览器有后退前进的功能让你在文档中跳转而界面会有么?浏览器可以收藏(书签)文档而界面可以么?从无障碍来说,瘦客户端也更少出错。

这种非平衡性是很难解决的。富客户端当然也可以在更高级的界面做到前进后退,或者收藏,也可以做到完美的无障碍。这必须需要大量的额外工作,但不是每个项目都有超出预算的时间或金钱。此外,太过专注于可用性而忽略无障碍也是一个问题。

那么JavaScript的目的是为富客户端还是瘦客户端服务?答案是:看情况。得看你的网站,你的受众,你的JavaScript水平。

技术概述
JavaScript分为六个方面,分别是核心(Core),浏览器对象模型(BOM),事件(Events),文档对象模型(DOM),CSS变更和数据获取(XMLHttpRequest)。

上古时代,NetScape领头之时,NetScape3是事实标准。

当代却没有这么简单。ECMA标准化JavaScript Core, W3C标准化DOM,而BOM尚在WHAT-WG的标准化中,W3C也刚有了XMLHttpRequest的第一份草稿。今天,BOM依然遵循NetScape3的事实标准,而XMLHttpRequest还是遵照Microsoft的原始规范。

JavaScript的目的在于为网站增加可用性,而不是破坏用户的隐私和安全。因此JavaScript不允许读写用户的文件(cookies除外),采取同源策略,只允许来自相同域的交互。不允许读取历史记录,不能为上传文件的表单设置值,由JavaScript控制的窗口关闭需经用户确认,由JavaScript打开的窗口不能小于100×100的窗口,不能移出屏幕之外。

JavaScript的历史
探寻历史才能让我们知道JavaScript为什么会被误解得如此深。JavaScript的创造者是Brendan Eich,首次在NetScape 2中实现。它的目的是创建一门足够简单的语言让开发者能容易地为网页增加交互,只要把代码拷贝过来调整一下就可以。这确实令人赞叹,很多JavaScript开发者是从拷贝粘贴开始的。

不幸的是JavaScript生错了名字,也生错了语法。最初它叫LiveScript,但1996年的时候Java炙手可热,NetScape想搭顺风车,于是某产品经理(我想知道她/他是谁,呵呵),命令更名,命令Brendan Eich让“Javascript像Java”。这让很多人误认为JavaScript是Java的低级版,不能引起严肃程序员的关注。

1996年之时,NetScape 3是王,Microsoft只能照抄。这是一个难得的和谐期,当然,那时候浏览器比起现在来“瘦”了,仅限于表单验证,鼠标轮换的一些小花招而已。

接下来就是影响深远的浏览器大战了。为了争夺市场,两家浏览器纷纷实现不同的东西,谁都想成为事实标准。最有名的就是NetScape 4的document.layer和IE 4的document.all(忘记它们吧!)。它们让DHTML流行起来。

1999年Microsoft以推出良好支持CSS和DOM的IE5胜出,NetScape的让位终于有足够的时间让一场革命发生,那就是CSS。WaSP首先从CSS入手,而很多专家也发现/发明了许多浏览器的补救办法,让这场革命成为可能。

2003年,一些先锋们在CSS革命的影响下开始探索新的JavaScript风格,更多地关注无障碍,改观人们对它的坏名声,那就是unobstrusive——把JavaScript从HTML结构层分离出来,遗憾的是,那些在浏览器大战存活下来的程序员可能还没有发现这条新道路。

2005年,Ajax热潮为JavaScript社区注入新的血液。但某些方面,Ajax太像DHTML了,无障碍,是很多Ajax应用的难言之隐。这个热潮趋向于关注技术(如何Ajax),而可用性和交互(为何Ajax)却被低估。最后,各种肿胀的库(现在称为框架)迅速发展起来。

Ajax依然全速前进,但这会像DHTML一样结果,人们渐渐失去兴趣,它们会土崩瓦解。

JavaScript兴衰史好像有一定的“定律”支配,我们能打破这个怪圈吗?不管如何,JavaScript开发者在寻找各种酷代码和华而不实的框架之外,更应该调整自己的行动,让JavaScript运行在:标准兼容的,无障碍的网页中。

你可能感兴趣的:(JavaScript)