realazy


标准的、语义的、Unobtrusive的页签切换

页签的流行

自从Yahoo!的首页引进页签(tab, 见下图)之后,这种可用性极佳的方式越来越受欢迎,用户也逐步习惯和喜欢上它,因为它可以在原有的空间上增加更多的可用信息,而且只需切换,不需刷新整个页面,浏览更舒畅。很多网站接受并使用,如新浪等。

页签样例

页签的标记结构

那么,让我们来看看这些页签后的代码。

新浪完全不考虑什么标准,就是表格嵌套,我们略过不提。Yahoo!的XHTML形式是这样的:

<div>
  <ul>
    <li>页签1</li>
    <li>页签2</li>
    ...
  </ul>
</div>
<div>
  <div>内容1</div><!--它们可能由Ajax载入-->
  <div>内容1</div>
  ...
</div>
...

符合标准,但却没有语义。页签和相应内容没有任何关联。也就是说,在没有CSS展现的情况下,用户并不晓得页签究竟对应哪一块内容。而且就JavaScript实现来说,必须对元素定义更多的id或者class作为调用钩子(hook),容易造成代码冗余。有人对此作出改良,使用连接元素的hash(即#号后的字段)跟内容进行关联,即下面这种形式:

<div>
  <ul>
    <li><a href="#content1">页签1</a></li>
    <li><a href="#content2">页签2</a></li>
    ...
  </ul>
</div>
<div>
  <div id="content1">内容1</div><!--它们可能由Ajax载入-->
  <div id="content2">内容1</div>
  ...
</div>
...

这种方式对于机器来说,确实找到了关联点,而且用户点击的时候,也能在hash的作用下(传统说法中的“锚点”)调到相应的内容区块。有进步,但还是不够语义。

语义,语义,语义!

理想中标准的、语义的tab代码应该是怎么样的呢?在我看来,应该是这样:

<dl>
  <dt>页签1</dt>
  <dd>内容1</dd>
  <dt>页签2</dd>
  <dd>内容2</dd>
</dl>

当然,我认为并不是Yahoo!的设计师/开发者并不了解语义,可能是由于某些特殊的需求在这种代码下可能会实现不了,只好采取折衷方案。是的,在这种代码形式下,语义虽能充分体现,但是要实现页签的表现形式,确实是一个难题。

解决之道

首先,请打开我们的Demo页面,先自行分析一下。如果您使用Firefox,可以尝试把CSS样式禁用进行“欣赏”(如果您装了Web developer toolbar,您可以CTRL + SHIFT + S)。继续。

解决dt的横排

dtdd交错,如何能够使得dt排在一行上?well,理论不分析太多,要使它们在一起,我们假设dd不存在。这样的话,使用float就能排在一起。既然dd不能不存在,ok,那么让它们脱离文档流,如何做?position:absolute;就可以了。但是IE6有问题,wtf . 我的解决方法是,使用JavaScript把所有的dt凑一块,这样严重伤害了语义,但这只是一个浏览器问题,而且是在有JavaScript的时候才产生语义问题,阿弥陀佛,辩证法认为事物都具两面性。

解决dd的自适用高度

对于已经position:absolute;了的dd,无论是理论还是实践,使用纯CSS都没有解决方法。同样,我使用了JavaScript来动态计算它的每一次高度,然后赋予整个dl

局限性与缺点

这样做保证了标准、语义、Unobtrusive。但对于少部分拥有能解析CSS的先进浏览器但却关闭了JavaScript的用户来说,极有可能会被不能自适用高度的页签下的内容区块挡住了跟随在后的信息。

s2uTab

很高兴我能写出一些实用的JavaScript,以上所提到的,我将之命名为s2uTab — 偏要解释的话,它就是Standard, Semantic, Unobtrusive Tab的缩写。首先,它很小,不依赖于任何库,在IE6+, opera 9+, Firefox 2+均通过测试(若您有Safari,务必帮忙测试一下,谢谢)。其次,灵活,除了dl外无须任何钩子,且页签数目灵活没有限制。再次,您可以指定页签切换的事件形式,可以指定初始的页签是哪个。

用法

您可以为window.onload添加如下函数:

s2uTab(页签, 事件类型, 初始页签);

其中,页签指dl元素的引用,如果您传入的是字符串,则返回id是改字符串的dl引用;事件类型是指,页签的激活是点击还是鼠标悬停,传入click或者mouseover(注意:没有”on”!)即可;初始页签是指您在初始化页面时需要激活的页签,注意,为符合编程习惯,请从0算起。

请多多参考我们的例子

23 Responses to “标准的、语义的、Unobtrusive的页签切换”

  1. 每日阅读 » links for 2007-02-22 Says:

    [...] realazy » 标准的、语义的、Unobtrusive的页签切换 (tags: 网页设计) [...]

  2. gougou8180 Says:

    找书过程中,翻到楼主的BLOG,进来瞅瞅。不晓得楼主讲些什么,技术上的东西都挺肤浅的。用js写了半年的ui组件了,越做越困惑。在中国做程序员,好没前途

  3. 小马 Says:

    楼上的兄台,如果你觉得技术上的东西都很肤浅了,你应该很有前途了:)。等有一天深入浅出了,就不会困惑了。

  4. PorkFat Says:

    hmmm…
    我更青睐Yahoo!的写法,页签就是页签,是作为导航的无序列表,分块内容就是分块内容,里面有标题有条目列表有扩展链接,是完整的区块,所以我觉得就语义来说也是很合适的
    你的写法中,虽然呈现形式上是页签,实际结构是当作标题了,不再是导航,当然未尝不可,只是用ajax载入内容的话,不知道扩展性如何,如果上面的结构中只是用一个同一个div来装载内容,这里dd就有好几个,在无js的情况下结构又变得如何,页面加载时js获取内容可能很缓慢,这时候高度的变化又能不能很顺畅,综合这些,成本可能更大

  5. PorkFat Says:

    ps. 在像例子里这样简单的情况下使用是很合适的,不过我觉得在Yahoo!的首页,它的代码就已经是很适合它了

  6. om19 Says:

    我也会用dl,dt,dd标签。不过后来google出了好像是名词搜索的服务,据说都是按照dt,dd标签来爬的,于是我重新思考了dl,dt,dd的用法–是否dl,dt,dd只能应用于形如名词解释上?
    所以如果现在用的话,我会用headings标签来表现语义。

  7. leeking011 Says:

    不错,有空我也尝试用dl dt dd来实现,谢谢楼主。
    不过从我自身来说,在我没看别人的写法之前,第一次用就不自觉的就想到了Yahoo的实现方式,是不是能说明这种方式从逻辑上更容易让人理解呢……探讨一下~

  8. realazy Says:

    @om19

    具体请查W3C的相关解释。个人理解,term应该不只是名词,而description也不仅是解释,应该是条目与内容之间的纽带。比方用代码来描述几个人的对话的话,那么人名可以是dt,而说话的内容可以是dd。使用headings也是个不错的做法,问题在于无法圈定整体,更令人抓狂的是,现有标准没有section的概念,hn中的n是什么得随时更改。

    @leeking011

    Yahoo!影响力太大了,呵呵。

  9. leeking001 Says:

    sorry,可能我没说清楚,请谅解,应该是
    “不过从我自身来说,在我没看任何人的写法之前,第一次用就不自觉的就想到了跟Yahoo一样的实现方式,是不是能说明这种方式从Xhtml的语句逻辑上更容易让人理解呢……”
    经常看你的博客,很受用~

  10. xw Says:

    ~~ 不错不错·~换一种思想

  11. lushnis Says:

    强文,支持语义!
    不过实例页面中有个小错误:“何年致此身。”

    T_T,代码过滤了
    〈pT〉何年致此身。〈/p〉

  12. 怿飞 Says:

    比较赞同这种做法,至少在XHTML中更容易理解包含关系,使代码更有语义化!至于headings期待2.0中section和h的使用!

  13. nowa Says:

    可用性工程不仅仅是使用者的可用性,也是开发者的可用性。相比之下,语义化固然是王道,但是在目前的情况下在这个例子里,却不是最为可取的。

  14. realazy Says:

    @nowa,

    您说得没错,在商业环境中只有最合适的,没有最好的。今天不适用,明天或许就适用。2004年,当web standards还是geek手中玩物时,Yahoo!已经在首页全面启用,那时候,或许也没有多少人觉得合适,但今天看来,是自然不过的事情。我也承认,现在,如果真的在商业环境中适用上述方法,会带来更多的麻烦,但并不是说我们平时自己的小项目就不能使用这个更佳的做法,一旦成熟,商业也会慢慢迁移和接受。

    一点个人看法。

  15. forestgan Says:

    如果客户端把JS禁用了……

  16. realazy Says:

    @forestgan

    这点我已经在局限性与缺点中说明了,确实有这样的风险。可以这么说,要实现页签切换,必须用JavaScript来实现(当然你也可以说用纯粹的CSS来实现,但永远赶不上用JavaScript实现的平滑,而且很多功能如XMLHttpRequest,动画等CSS无法做到),没有JavaScript,就没有页签。如果客户端把JS禁了,对,没有页签。

    其实,除了纯粹的安全环境和刻意的手动禁止,CSS和JavaScript在大多数情况下总是相符相成的,就是说有CSS必有JavaScript。

    当然,我跟你一样,十分在意accessibility,这点我很赞赏。这是一个实验,或者试验。没有完美的东西,没有能够满足任何条件下的程序,这是我们必须承认的。

  17. weston Says:

    safari测试正常!

  18. rill Says:

    FF1.5.0.10 下没有确发事件
    Netscape 7.0 下有重叠

  19. lidahang Says:

    非常好的内容,受益!

  20. leim Says:

    用javaScript来计算高度是否有点麻烦,我的想法是将内容浮动,选项卡采用内联显示,能够实现高度的自适应,但要加入额外的元素来清除浮动。“阿弥陀佛,辩证法认为事物都具两面性”,我想这样的牺牲是值得的!
    http://bbs.blueidea.com/viewthread.php?tid=2735808&pid=3158712&page=1&extra=page%3D1#pid3158712

  21. 古天乐 Says:

    不错哦!

  22. 月牙感 Says:

    xixi

  23. 爆牙齿 Says:

    页签我一直用dl。

    小样的,写得好正式,有因有果,晕倒,看见命名,爬起来再晕倒。
    够忽悠,恭喜恭喜,哈哈哈。

    比较高兴的是,好难得哦,看见你独立思考,不跟随而出轨。

    “当然,我认为并不是Yahoo!的设计师/开发者并不了解语义,可能是由于某些特殊的需求在这种代码下可能会实现不了,只好采取折衷方案。”
    别为雅虎贴金,他们就是没有挖掘细节。
    狗屁影响力,都是人类,我只相信我大脑的计算分析结果。

Leave a Reply


第三届 D2 前端技术论坛 (上海)

realazy (懒到死) is proudly powered by WordPress | Entries (RSS) and Comments (RSS)