HTML5已經出來好長時間了,越來越多人希望並且開始把HTML5應用到平時的工作、個站中。大家對section、article、aside、nav等新標簽的使用也越來越上手,也許是自我感覺良好的上手。不從多個方面去認識理解這些標簽,可能反而讓自己落入了更混亂的境地。HTML的大綱算法(outlining algorithm)就是一個很重要的切入點。
先看兩個大綱:
這兩個都是我早期的作品了。當時還覺得自己的結構寫的不錯,特別是第二個,還用上了HTML5標簽,以為自己就踏進這個新世界了。看過HTML大綱算法之後,檢測了一下這些頁面,真的是慘不忍睹。第一個各種混亂標題不說,“主創陣容”居然從屬於“用戶評論”?第二個也不好發言了,那麼多未命名的是什麼東西?不過總是要踩在傷痛的歷史上才能往前進。
再來看幾個其他人重構的頁面大綱:
想象你是一個有點視力障礙的用戶,需要依靠屏幕閱讀器來浏覽這些網頁,閱讀器會按照層級來給你解讀這個網頁,你覺得上面那個網頁更容易讓你獲得所需要的資訊呢?也許對比完大家更想知道大綱算法到底是個怎麼樣的東西了吧?
大綱算法允許用戶代理(user agent)從一個web頁面生成一個信息結構目錄,讓用戶對頁面有一個快速的概覽。類似書籍、PDF、幫助文檔等,都有一個清晰的目錄結構,用戶能方便的定位所需內容。一個良好結構的大綱,不僅是對於搜索引擎的優化,更是為借助於屏幕閱讀器浏覽網頁的盲人(或弱視力)用戶提供了巨大的幫助。
幫助文檔的目錄結構:
每個頁面都有大綱,先從一個簡單的例子來了解web頁面大綱吧。假設要做一個電影介紹頁面,主題是8月電影推介,頁面結構也許如下:
1.8月電影推介 1.國內電影 1.《四大名捕》 2.《搜索》 2.國外電影 1.《冰川時代4》 2.《在劫難逃》
HTML4或者之前,我們都是采用hn(h1~h6)來生成大綱的。HTML5引入了section、article、aside、nav等新的節點元素(sectioning content),添加了一些新的規則,後面會詳細闡述。
也許HTML4的結構會這樣寫:
<div> <h1>8月電影推介</h1> <h2>國內電影</h2> <h3>《四大名捕》</h3> <p>四大名捕講的是..</p> <h3>《搜索》</h3> <p>搜索講的是..</p> <h2>國外電影</h2> <h3>《冰川時代4》</h3> <p>冰川時代4講的是..</p> <h3>《在劫難逃》</h3> <p>在劫難逃講的是..</p> <p>以上內容由迅雷看看提供</p> <div>
可以看出,網頁大綱由標題的層級來生成。
如果想要查看這段代碼的大綱,可以試試Geoffrey Sneddon做的大綱工具Outliner(強烈推薦),上傳文件和輸入片段代碼都可以。如果想要查看在線網頁的大綱,可以給浏覽器安裝插件:chrome:HTML5 Outliner(推薦)/ Web Devoloper,firefox:Web Devoloper;opera:HTML5 Outliner。(HTML5 Outliner裡中文會顯示亂碼,建議換成英文測試。浏覽器插件可以顯示中文)
每個標題都會生成一個隱性節點(implicit section),緊隨其後的相對層級低的標題會成為它的子節點,層級相同或者更高的標題則會關閉這個節點並生成新的節點。可以測試一下下面的代碼:
<h3>《四大名捕》</h3> <p>四大名捕講的是..</p> <h3>《搜索》</h3> <p>搜索講的是..</p>
或者:
<h3>《搜索》</h3> <p>搜索講的是..</p> <h2>國外電影</h2>
也許HTML5的結構會這樣寫:
<div> <h6>8月電影推介</h6> <section> <h1>國內電影</h1> <article> <h1>《四大名捕》</h1> <p>四大名捕講的是..</p> </article> <article> <h3>《搜索》</h3> <p>搜索講的是..</p> </article> </section> <section> <h5>國外電影</h5> <article> <h6>《冰川時代4》</h6> <p>冰川時代4講的是..</p> </article> <article> <h1>《在劫難逃》</h1> <p>在劫難逃講的是..</p> </article> </section> <p>以上內容由迅雷看看提供</p> <div>
(可以先注意一下上面這段代碼的各個hn)把代碼復制到Outliner工具去查看,很驚訝的發現,生成的大綱跟層級寫的很漂亮的HTML4一樣。為什麼hn的層級在這裡沒有表現出來?
原因是此時大綱是由節點元素生成的,而非標題元素。HTML5的新標簽section、article、aside、nav會生成顯性節點(explicit sections),每個顯性節點內部又有它自己的標題結構(當然也符合HTML4、HTML5大綱算法)。這也就是為什麼HTML5允許多個h1存在的原因,不過,在全部浏覽器、屏幕閱讀器都完美支持HTML5之前,建議還是需要同時考慮標題結構,優雅降級。所以上面的結構可以改成這樣:
<div> <h1>8月電影推介</h1> <section> <h2>國內電影</h2> <article> <h3>《四大名捕》</h3> <p>四大名捕講的是..</p> </article> <article> <h3>《搜索》</h3> <p>搜索講的是..</p> </article> </section> <section> <h2>國外電影</h2> <article> <h3>《冰川時代4》</h3> <p>冰川時代4講的是..</p> </article> <article> <h3>《在劫難逃》</h3> <p>在劫難逃講的是..</p> </article> </section> <p>以上內容由迅雷看看提供</p> <div>
這裡有另外一個問題值得注意,就是“以上內容由迅雷看看提供”這段話指的是上面的哪部分內容?在HTML4結構裡,這段話是從屬於隱性節點“《在劫難逃》”的,但明顯不對。HTML5大綱算法就很好地解決了這個問題。
如果頁面裡既有隱性節點(h1~h6)又有顯性節點(section等),大綱又會如何生成呢?只要記住一點:顯性節點能包含隱性節點,反之則不行。
<h1>8月電影推介</h1> <section> <h2>國內電影</h2> <h3>《四大名捕》</h3> <p>四大名捕講的是..</p> <h3>《搜索》</h3> <p>搜索講的是..</p> </section>
(代碼1)
這段代碼的大綱會是:
1.8月電影推介 1.國內電影 1.《四大名捕》 2.《搜索》
<h1>8月電影推介</h1> <h2>國內電影</h2> <article> <h3>《四大名捕》</h3> <p>四大名捕講的是..</p> </article> <article> <h3>《搜索》</h3> <p>搜索講的是..</p> </article>
然而這段代碼的大綱會是:
1.8月電影推介 1.國內電影 2.《四大名捕》 3.《搜索》
由標題元素生成的隱性節點遇上由節點元素生成的顯性節點就會關閉並生成下一個同級節點。
HTML5新節點元素除了section、article還有aside、nav,我們也來使用一下。
<nav> <ul> <li><a href="">首頁</a></li> <li><a href="">專題</a></li> <li><a href="">關於</a></li> </ul> </nav> <h1>8月電影推介</h1> <section> <h2>國內電影</h2> </section> <section> <h2>國外電影</h2> </section>
復制到outliner會發現, nav標簽會產生一個untitled section,因為nav裡並沒有給予任何標題元素。這不是錯誤也不會被認為是不好的HTML5結構。但是section、article還是建議給予適當的標題。如果不確定可以給予什麼標題,也許使用div更適合,不要忘了我們還有div啊。
前面提到一個重要的原則:顯性節點能包含隱性節點,反之則不行。也許你會注意代碼1生成的大綱:
1.8月電影推介 1.國內電影 1.《四大名捕》 2.《搜索》
標題元素h1(“8月電影推介”)下緊跟著的節點元素section(“國內電影”),變成了它的一個子節點。隱性節點不是不能包含顯性節點麼?這時候就需要認識一下根節點了。
根節點可以生成自己的大綱,它的標題和節點對祖先的大綱沒有任何影響(而且不會出現在祖先大綱裡)。目前有六個根節點:
1.body
2.blockquote
3.details
4.fieldset
5.figure
6.td
可以測試一下:
<h1>我是老大 I'm the big brother</h1> <blockquote> <section> <h1>我是blockquote裡的老大,待會你看不到我了 I'm the big brother in blockquote,you'll not find me in the outliner</h1> </section> </blockquote> <h2>我是老二 I'm the younger</h2>
定義文檔裡說明了:節點元素是離它最近的祖先根節點或節點元素的子節點。代碼1裡的標題元素h1(“8月電影推介”)是body的標題,節點元素section(“國內電影”)是body的子節點。
還有一個很重要的:文檔的標題是文檔中第一個且非節點元素裡的標題元素。測試一下下面的代碼就很明了了:
<section> <h1>我很想成為文檔的標題可惜不能 I want to be the title but I couldn't</h1> </section> <h6>雖然我層級最小可是我是第一個出現的 I'm h6 but I come first</h6> <h1>最大也沒用順序我還是在老6下面 I'm h1 but I come after h6</h1>
過程中我還遇到過另一個讓我迷惑的:
<section> <h1>我很想成為文檔的標題可惜不能 I want to be the title but I couldn't</h1> </section> <section> <h2>我也很想成為文檔的標題可惜不能 Me either:(</h2> </section> <footer> <h3>我是footer可是為什麼我成為了文檔標題啊 I'm footer but why I become the title??</h3> </footer>
原因很簡單,header和footer不是節點元素。
hgroup很好理解也很好用,它的作用就是幫你添加副標題而不影響文檔大綱,大綱中只會出現層級最高的標題,無論出現順序。
<hgroup> <h3>我是副標題,我很重要但我不會出現在大綱中 I'm your loved second title,I'm useful and I won't appear in the outliner</h3> <h2>我是大標題,我是故意跑到下面來的 I'm the highest level of hn in the group,no matter where I am,I will be part of ouliner</h2> </hgroup>
到寫完這篇文章為止,好像還沒有哪個浏覽器是完美支持HTML5大綱算法的。但這不影響我們對HTML5大綱算法的學習,就像我們現在在努力使用HTML5+CSS3一樣。理解了HTML5大綱算法,不僅對於新標簽的使用有更進一步的認識,而且對於最根本的頁面結構有更優化的理解,就算只是標題元素生成的大綱,也能擁有完美的層級結構,這也是語義化的一個標志。
特別感謝一下大安仔,是他提醒我要注意這個問題的。