摘要 Microsoft ASPNET 具有很多有用的功能能幫助您設計和生成符合 XHTML 和可訪問性標准的 Web 站點本文探討如何以及為什麼生成這些符合標准的站點
Web 標准使您能通過最少的工作生成可被最廣大受眾訪問的 Web 站點Web 標准的承諾是只需設計頁面一次即可讓該頁以完全相同的方式在任何現代的浏覽器中顯示和工作例如在按照標准生成以後旨在在 Microsoft Internet Explorer 中以某種方式顯示的頁可在其他浏覽器(如Mozilla FirefoxNetscape NavigatorOperaCamino 和 Safari)中以相同的方式顯示而無需完成任何額外的工作
Web 標准的一個額外好處是 — 使 Web 站點更易於為殘疾人士訪問這是一個范圍廣泛的受眾群體包括視力衰退的中年人士剛剛在滑雪時跌斷胳膊的人士以及完全失明的人士等使用標准可避免無意中阻止那些具有暫時性或永久性身體殘疾的人士訪問 Web 頁
對於生成滿足公共 Web 標准的 Web 站點而言Microsoft ASPNET 框架是最佳的框架特別強調的是ASPNET 框架中的每個控件都按照 XHTML 和可訪問性標准進行了全面的檢查和測試此外Microsoft Visual Studio NET 還包含一些新工具用於按照 XHTML 和可訪問性標准驗證 Web 頁
本文的目的是為您提供有關 XHTML 和可訪問性標准的概述並說明如何利用 ASPNET 和 Visual Studio NET 來滿足這些標准在本文的結尾將分步演練以下功能即創建能夠同時滿足 XHTML 和可訪問性標准的 ASPNET Web 站點
HTML 在正式的場合已經過時了World Wide Web Consortium (WC) 於 年 月 日發布了 XHTML 的第一個版本作為推薦標准XHTML 標准的目標是取代 HTML按照 WC 的說法XHTML 是 HTML 的繼承者()
XHTML 標准的制定者具有兩大目標
為了實現第一個目標WC 一直在堅定地從 HTML 中刪除純粹描述性的元素和屬性(他們是從 HTML 開始這一過程的)例如XHTML Strict 不包含諸如 標記之類的元素或諸如 bgcolor 屬性之類的屬性因為這些元素和屬性完全用於描述文檔的外觀它們與文檔的結構沒有任何關系
WC 一直在努力使 Web 站點設計人員和開發人員摒棄特定標記應當具有特定外觀這一觀念例如您可能會認為
您不應當試圖使用諸如
XHTML 的第二個目標是迫使 HTML 開發人員遵守更為嚴格的 XML 規則按照 WC 的說法XHTML 是 HTML 的作為 XML 應用程序的修訂()換句話說使用 XHTML 生成 Web 頁時實際上是在創建 XML 文檔
XML 文檔具有比 HTML 文檔更嚴格的語法例如XML 區分大小寫所有 XML 屬性都必須放在引號內而且 XML 標記不能重疊強迫 Web 站點開發人員和設計人員遵守有更高要求的語言規則有很多好處
好處之一用 XHTML 標記編寫的頁具有更高的跨浏覽器跨設備和跨操作系統兼容性如果在浏覽器中打開傳統的 HTML 頁浏覽器將千方百計地呈現該頁浏覽器將試圖呈現該頁即使您的 HTML 一團糟例如Internet Explorer(以及 Firefox 和 Opera)能夠很好地顯示下面的 HTML 頁
this is bold and italic and this is bold
Internet Explorer 會恰當地顯示該頁 — 即使該頁缺少 和 開始標記 標記不具有匹配的結束標記並且開始和結束 標記的大小寫不一致所有主要的浏覽器都能適應幾乎任何 HTML 標記混合物並且不顧一切地呈現一些內容
浏覽器的這種適應行為是危險的因為不同的浏覽器(或相同浏覽器的將來版本或在不同操作系統上運行的相同浏覽器)可能以不同方式呈現錯亂的 HTML實際上對於最新版本的 Internet ExplorerMozilla Firefox 和 Opera 而言它們呈現無效 HTML 的方式驚人地一致但是一旦開始違反游戲規則就不會得到任何保證
然而如果用 XHTML 的更嚴格的規則編寫 Web 頁那麼 Web 頁就更有可能以一致的方式與當前浏覽器協作並且它們將繼續與當前浏覽器的未來新版本協作對於任何公司而言幾乎都不具備針對每個浏覽器在每個操作系統和每個設備上測試其 Web 站點的資源如果按照 Web 標准編寫頁面那麼就不必具有這樣的資源
有三個版本的 XHTML 它們分別對應三個版本的 HTML
XHTML Transitional 包含 HTML Transitional 中的全部標記和屬性引入 XHTML Transitional 標准的目的是使現有 HTML 設計人員和開發人員無需經歷太多的痛苦就能遷移到 XHTML
XHTML Strict 與 XHTML Transitional 的不同之處在於它在文檔結構和表示形式之間實施了一種更為明顯的分離與 XHTML Transitional 不同XHTML Strict 強迫您使用層疊樣式表來控制頁的外觀
XHTML Frameset 文檔意在成為使用
WC 還發布了 XHTML 以作為推薦標准( 年 月 日)XHTML 非常類似於 XHTML Strict二者的主要區別在於可以用附加模塊擴展 XHTML 以便支持新元素例如可以生成特定的 XHTML 頁該頁還包含 MathML(數學標記語言)SVG(可伸縮向量語言)或創建的自定義模塊中的元素
最後WC 正在制訂 XHTML 推薦標准因為 XHTML 仍然處於起草階段並且當前沒有 Web 浏覽器支持該標准所以我們不在本文討論它
ASPNET 框架和 Visual Studio NET 面向 XHTML Transitional該標准是 XHTML 標准中限制性最低的而且它是與現有 HTML 頁最兼容的標准但是還可以生成面向 XHTML Strict 標准甚至 XHTML 標准的 ASPNET 頁(請參閱後面的配置 XHTML 一致性一節)
(請注意默認情況下ASPNET 框架的 Beta 版本面向 XHTML ASPNET 框架的最終版本將面向 XHTML Transitional)
與 HTML 頁不同XHTML 頁必須是標准格式且有效的 XML 文檔XHTML 推薦標准的第 部分對 HTML 和 XHTML 之間的區別進行了總結這裡給出生成有效 XHTML 頁的最重要需求的列表
頁必須包含有效的 XHTML DOCTYPE
有效的 XHTML 頁必須在其任何內容之前包含一個 XHTML DOCTYPE當在 Visual Studio NET 或 Microsoft Visual Web Developer 中創建新的 ASPNET 頁時該頁中將自動包含 XHTML Transitional 的正確的 DOCTYPE下面列出四個標准的 XHTML DOCTYPE
XHTML Transitional
XHTML Strict
XHTML Frameset
XHTML
向頁中添加 DOCTYPE 會影響該頁在浏覽器中的呈現方式請參閱以下標題為XHTML 和 DOCTYPE 切換的一節
根元素必須引用 XHTML 命名空間
XHTML 頁的開始 標記必須指定默認命名空間 以下是 XHTML Transitional 頁的有效開始 標記的示例
所有元素和屬性名都必須小寫
XML 區分大小寫因此在
標記和
標記之間存在差異只有前者是有效的 XHTML 段落標記
屬性值必須始終放在引號內
確保始終將屬性值放在雙引號或單引號中例如以下是無效的 XHTML
Next
在該示例中href 屬性缺少引號以下代碼是有效的 XHTML
您可以通過選擇菜單選項 ToolsOptionsFormat將 Visual Studio NET 和 Visual Web Developer 配置為自動將屬性值放在引號內
所有具有開始標記的非空元素都必須具有匹配的結束標記
如果具有開始
標記則必須包含結束
為使 XHTML 頁與現有的 HTML 浏覽器向後兼容需要小心處理打開和關閉標記的方式例如現有 HTML 浏覽器傾向於將開始和結束 標記錯誤地解釋為兩個 元素因此您應當使用空元素簡寫
此外除非您小心地在結束斜槓之前添加一個空格否則現有 HTML 浏覽器在處理空元素簡寫時會出現問題因此應當使用 [space] />(而不是)向頁中添加 元素。tw.wINgWIt.cOM
不得存在重疊標記。
可以使標記嵌套,但是不允許使標記重疊。例如,以下 XHTML 是有效的。
This is bold and italic
但是,以下 XHTML 是無效的。
不得存在屬性最簡化。
所有屬性都必須具有值,即使該值看起來有一點兒奇怪。例如,標記是無效的 XHTML,因為 checked 屬性不具有值。該標記應當寫成。
必須使用 id 屬性而不是 name 屬性。
在 HTML 中,可以使用 name 屬性來標識 、
、
必須將
使用 CDATA 節並非對所有浏覽器都有效。例如,Internet Explorer 會將
JavaScript 使用 /* 和 */ 來標志注釋的開始和結束。因此,CDATA 節對 JavaScript 隱藏,但不對分析該頁的浏覽器隱藏。總之,較好的做法是將樣式規則和腳本放在外部文件中,而從 XHTML 頁中引用這些文件。通過使用外部樣式表和腳本,能夠避免上述所有問題。
默認情況下,ASP.NET 2.0 框架中包含的每個 ASP.NET 控件都呈現有效的 XHTML。換句話說,向頁中添加 ASP.NET 控件時,您無需完成任何特殊工作來生成有效的 XHTML 標記。例如,如果您向頁中添加 GridView 控件,則 GridView 控件會生成有效的 XHTML 標記。
這裡需要澄清三個要點。首先,包含 ASP.NET 控件的頁的源代碼不會通過 XHTML 驗證。驗證 ASP.NET 頁時,需要驗證頁呈現的內容(在 Internet Explorer 中選擇 View Source 時看到的所有內容),而不是該頁的源代碼。
其次,在創建 ASP.NET 頁時,沒有任何事情阻止您編寫無效的 XHTML。您當然可以向 ASP.NET 頁中添加希望添加的任何標記。例如,如果向頁中添加 標記,那麼頁將不會通過 XHTML 1.0 Strict 驗證。
最後,當您使用自定義 ASP.NET 控件時,沒有任何保證。如果購買第三方 ASP.NET 控件(例如,一個一流的增強 DataGrid 控件),則該控件可能會呈現有效的 XHTML,但也可能不會。保證不犯錯誤是控件供應商的責任。
Visual Studio .NET 2005 和 Visual Web Developer 會在生成 Web 頁的過程中自動驗證該頁的有效性。通過在違反規則的內容下添加綠色或紅色波浪線,在“Source”視圖中指出驗證問題。紅色波浪線對應於諸如缺少結束標記之類的驗證錯誤。綠色波浪線對應於驗證警告,例如,使用了已否決的標記。
將鼠標懸停在任何波浪線上方,可查看包含驗證錯誤或警告消息的工具提示(參見圖 1)。或者,還可以在 Error List 窗口中查看驗證錯誤或警告的列表(依次選擇 View、Other Windows、Error List)。
圖 1. 驗證 XHTML 文檔
默認情況下,Visual Studio .NET 2005 和 Visual Web Developer 被配置為針對 Internet Explorer 6.0 架構驗證頁。如果要針對 XHTML 架構驗證頁,則需要從工具欄的下拉列表中選擇 XHTML 架構中的一個,或依次選擇 Tools、Options、Validation 來選擇目標架構。
作為替代方法,還可以通過使用 W3C驗證服務來驗證 ASP.NET 頁。W3C 驗證服務使您能夠通過提供 URL 或通過上載 XHTML 頁的源代碼來驗證頁。
為 Web頁指定 DOCTYPE 會影響浏覽器呈現頁的方式。Internet Explorer、Mozilla Firefox 和 Opera 全都支持一種名為“DOCTYPE 切換”(也叫“DOCTYPE 嗅探”)的功能。
引入 DOCTYPE 切換的目的是使浏覽器能夠正確地呈現符合標准的 Web 站點以及舊式 Web 站點。大多數 Web 站點被開發為呈現 HTML 頁而不是 XHTML 頁。浏覽器通過判斷是否存在 DOCTYPE 來確定何時應該使用標准來呈現頁。
Internet Explorer 6+ 支持兩種呈現模式,分別叫做 Quirks 模式和 Standards 模式。當 Internet Explorer 呈現包含有效 XHTML(或 HTML 4.0)DOCTYPE 的頁時,它會以 Standards 模式呈現該頁;否則,它會以 Quirks模式呈現該頁(有關詳細信息,請參閱 CSS Enhancements in Internet Explorer 6)。
Opera 浏覽器 (Opera 7+) 支持與 Internet Explorer 相同的兩種呈現模式:Quirks 和 Standards(有關詳細信息,請參閱 )。
Mozilla Firefox 1+ 支持三種呈現模式:Quirks 模式、Almost Standards 模式和 Standards 模式。Firefox 的 Almost Standards 模式對應於 Internet Explorer 和 Opera 的 Standards 模式。當頁包含有效的 XHTML 1.0 Transitional DOCTYPE(並且該頁被分配為 text/html MIME 類型)時,Firefox 會以 Almost Standards 模式呈現該頁。當頁包含 XHTML 1.0 Strict 或 XHTML 1.1 DOCTYPE(或者該頁被分配為 XML MIME 類型)時,該頁將以 Standards 模式呈現(有關詳細信息,請參閱 -developer/quirks/l)。
可以通過臨時向頁中添加以下客戶端腳本(該腳本在最新版本的 Internet Explorer、Firefox 和 Opera 中有效)確定浏覽器的當前呈現模式。
您需要關心浏覽器的呈現模式,因為它會影響將層疊樣式表應用於該頁的方式。如果將現有 HTML 頁轉換為 XHTML 頁,那麼在浏覽器中打開它們時,它們可能看起來非常不同。
例如,Internet Explorer 以不同方式計算頁元素的大小,這取決於呈現模式(它使用不同的 CSS Box Model)。在 Quirks 模式下,元素的寬度是通過將元素的內容、內邊距、邊框和邊距相加而計算得到的。在 Standards 模式下,元素的寬度是只考慮元素內容的寬度而計算得到的。
例如,考慮下列兩個 標記。
First Box Second Box
除了第二個 元素的附加內邊距以外,這兩個 元素是相同的。在 Quirks 模式(參見圖 2)下,這兩個 元素看起來大小相同,因為在計算第二個 元素的寬度時考慮了它的附加內邊距(這兩個元素的總寬度為 400px)。在 Standards 模式(參見圖 3)下,第二個 元素看起來要比第一個 元素寬,因為在計算元素的寬度時未考慮內邊距(這兩個元素的總寬度大於 400px)。
圖 2. Quirks 模式
圖 3. Standards 模式
這只是 Quirks 模式下浏覽器差異的一個示例。在 Quirks 模式下,每個浏覽器都以相當不同的方式實現 W3C層疊樣式表標准。有關切換到 Standards 模式的一個妙處在於,它強制幾乎所有現代浏覽器以非常類似的方式(不完全相同,但要好得多)解釋 W3C標准。
如果希望 Web 頁以相同方式出現在所有浏覽器中,那麼通過包含 XHTML 1.0 Transitional DOCTYPE 觸發 Standards 模式(在 Internet Explorer 和 Opera 中)和 Almost Standards 模式(在 Firefox 中)是一個好主意。幸運的是,默認情況下,Visual Studio .NET 2005 和 Visual Web Developer 自動將該 DOCTYPE 添加到每個新的 ASP.NET 頁中。
當 Web 浏覽器從 Web 服務器請求頁時,Web 服務器會為該頁分配特定的 MIME 類型(也稱為 Content 類型)。例如,HTML 頁被分配為 text/html MIME 類型,GIF 圖像被分配為 image/gif MIME 類型,而 Microsoft Word 文檔被分配為 application/msword MIME 類型。
浏覽器使用 MIME 類型來確定如何處理頁(或其他資源)。例如,如果浏覽器從 Web 服務器獲得一個具有可識別圖像 MIME 類型的文件,則浏覽器嘗試將該文件解釋並呈現為圖像。如果浏覽器獲得一個具有 application/msword MIME 類型的文件,則該浏覽器可能自動打開 Microsoft Word 以顯示該文檔(這裡的確切行為取決於浏覽器及其配置方式)。
W3C 為 XHTML 文檔引入了一個 MIME 類型。這一新的 MIME 類型是 application/xhtml+xml。W3C 建議您在提供 XHTML 文檔時使用 application/xhtml+xml MIME 類型,因為 XHTML 頁應該以比舊式 HTML 頁更嚴格的方式進行解釋。
通過在頁指令中包含 ContentType 屬性,為 ASP.NET 頁分配特定的 MIME 類型。例如,在 ASP.NET 頁的頂部包含以下指令會導致為該頁分配 application/xhtml+xml 類型。
<%@ ContentType="application/xhtml+xml" %>
W3C 的推薦標准有一個突出問題:並非所有浏覽器都能識別 application/xhtml+xml。特別需要指出的是,Internet Explorer(有史以來最為流行的 Web 浏覽器)不能識別 application/xhtml+xml MIME 類型。因此,使用推薦的 application/xhtml+xml MIME 類型提供 XHTML 頁不是一個可行的選擇。
有三種解決該問題的方式。可以使用 text/html MIME 類型來提供 XHTML 頁,或者使用 application/xml(或 text/xml)MIME 類型來提供 XHTML 頁,也可以使用內容協商方式。讓我們對上述每個選擇進行探討。
第一個選擇 — 以 text/html 類型提供頁 — 是最容易的選擇。默認情況下,ASP.NET 頁被分配為該 MIME 類型。更好的做法是,按照 W3C 的建議,在向現有的 HTML 浏覽器提供頁時使用這一選擇(請參閱 -media-types/)。如果創建的是 XHTML 1.0 Transitional 頁,並且 Web 應用程序的主要受眾使用不能理解 application/xhtml+xml MIME 類型的浏覽器,那麼以 text/html 類型提供頁似乎十分明智。畢竟,引入 XHTML 1.0 Transitional 標准的目的是使開發人員能夠更為容易地將現有的 HTML 頁遷移到 XHTML。
這一主張是有爭議的。例如,Ian Hickson 認為,絕不應該以 text/html 類型提供 XHTML 頁,因為這樣會導致隨便的、不標准的 XHTML 頁(請參閱 )。他建議作者們繼續堅持使用 HTML 4.0,直到更多的浏覽器完全支持 XHTML 標准為止。
第二個選擇是使用 application/xml 或 text/xml MIME 類型,以 XML 類型提供 XHTML 頁。在向 Internet Explorer 提供 XML 文檔時,該文檔會作為 XML 文檔進行分析並呈現到浏覽器中。(該文檔由 document.XMLDocument 對象公開的 XML DOM 表示。)
以 XML 類型提供 XHTML 文檔的優點是,XHTML 文檔具有的任何問題都會被 Internet Explorer 的 XML 分析器捕獲。例如,如果文檔包含重疊標記,或者如果沒有將屬性的值包裝到引號內,則不會呈現該文檔,並且會顯示錯誤信息(參見圖 4)。XHTML 純粹主義者認為該行為是一件好事,因為它可以防止您編寫格式錯誤的 XHTML。
圖 4. 在 Internet Explorer 中顯示 XML
該方法的問題是:默認情況下,Internet Explorer 呈現 XML 文檔的源代碼。因此,如果以 XML 類型提供 XHTML 文檔,則 Web 站點訪問者將看到 XHTML 文檔的源代碼,而不是預期的呈現輸出。W3C 推薦了一個用來解決該問題的“竅門”(請參閱 -faq#ie):如果通過使用 XSLT 轉換將 XHTML 文檔轉換為 HTML,那麼文檔將分析為 XML 並顯示為 HTML。
例如,清單 1 中的 ASP.NET 頁將以 XML 文檔的形式提供,但被轉換為 HTML 文檔。結果頁會正確地顯示在 Internet Explorer、Opera 和 Firefox 中。
清單 1. XMLPage.aspx
<%@ Page Language="VB" ContentType="text/xml" %>
頁指令會導致該頁以 text/xml 類型呈現。清單中的第二行引用了一個名為 copy.xsl 的 XSLT 樣式表,它會對當前文檔執行標識轉換。換句話說,除了將原始XML 文檔中的所有元素復制到新的 HTML 文檔中以外,它根本沒有做任何事情。copy.xsl 的源代碼包含在清單 2 中。
清單 2. Copy.xsl
該解決方案是有效的,但它似乎不是很精彩。當分析 XML 文檔時,的確獲得了額外的驗證步驟。但是,如果在 Visual Studio .NET 2005 或 Visual Web Developer 中生成 ASP.NET 頁,那麼開發環境會在“Source”視圖中執行相同的驗證。最後,Internet Explorer 將收到與向它發送 text/html 類型文檔時相同的文檔。
第三個選擇 — 內容協商,將 W3C 推薦標准的精神與最大程度的浏覽器兼容性最佳地組合在一起(請參閱 -mimetype/content-negotiation)。當使用內容協商時,會以不同的 MIME 類型向不同的浏覽器提供 ASP.NET 頁。如果浏覽器聲稱它支持 XHTML,則向它提供 XHTML 類型的頁;否則,以 text/html MIME 類型向該浏覽器提供頁。
清單 3 中的 Global.asax 包含向不同的浏覽器提供不同 MIME 類型頁所需的代碼。如果將該文件添加到 Web 項目中,則每個 ASP.NET 頁的 MIME 類型都會隨著每個請求而修改。將頁提供給 Firefox 或 Opera 時,該頁以 application/xhtml+xml 類型提供。另一方面,Internet Explorer 6 會收到 text/html 頁。
清單 3. Global.asax
ASP.NET 2.0 框架的默認行為是呈現針對 XHTML 1.0 Transitional 能夠通過驗證的頁。生成 Web 站點的大多數開發人員都希望面向該標准,因為它是與現有 HTML 頁最為兼容的標准。但是,在某些情況下,該標准可能顯得太松散或太嚴格。
例如,如果您志向遠大,那您也許要生成 XHTML 1.0 Strict(甚至 XHTML 1.1)的 Web 站點。畢竟,XHTML 1.0 Transitional 標准的目標是充當通往這些更具限制性標准的跳板。默認情況下,因為 ASP.NET 2.0 框架面向 XHTML 1.0 Transitional,所以某些 ASP.NET 控件會呈現與 XHTML 1.0 Strict 或 XHTML 1.1 不兼容的屬性。
而且,有時您還可能發現 XHTML 1.0 Transitional 標准的限制性過高。Microsoft 必須對現有 ASP.NET 1.1 控件進行多項更改才能符合 XHTML 1.0 Transitional 標准。其中一些更改可能會破壞現有的 ASP.NET 1.1 Web 站點。
為了滿足每個人的要求,Microsoft 創建了一個名為 xhtmlConformance 的新配置選項,您可以在 Web 站點的配置文件中設置該選項。新的配置選項使您能夠指定 Web 頁的 XHTML 一致性的級別。它的內容如下所示。
默認情況下,xhtmlConformance 設置為值 transitional。但是,還可以將該選項設置為值 strict 或 legacy。
如果將 xhtmlConformance 選項設置為 strict,那麼標准的 ASP.NET 控件將不會再呈現某些屬性。例如,ASP.NET
如果將 xhtmlConformance 選項設置為 legacy,那麼對於某些元素和屬性(但不是全部),ASP.NET 框架將恢復為 ASP.NET 1.1 呈現行為。在這種情況下,ASP.NET 框架將呈現不與任何 XHTML 標准兼容的內容,並且頁將不再通過 XHTML 標准驗證。例如,在 legacy 模式下,呈現 標記時不會呈現它需要的 XHTML 結束斜槓 ()。只有在將現有 ASP.NET 1.1 應用程序遷移到 ASP.NET 2.0 的過程中遇到問題時,將 xhtmlConformance 設置為 legacy 模式才是有意義的。
遵守公共 Web 標准的好處是:它們使您以盡可能少地工作,使盡可能多的人能訪問您的 Web 頁。需要指出的是,可訪問性標准使您能夠生成可被殘疾人士更容易訪問的 Web 站點。
同樣要強調的是,Web 站點用戶中的相當一部分具有這樣或那樣的殘疾。請試想一下您自己的家庭成員,並且考慮他們中有多少人會在與 Web 頁交互時遇到麻煩。我就有一些上了年紀的親戚是盲人或者失去了動作協調性。我猜測,本文的很多讀者也有上了年紀的父母或祖父母,他們在使用大多數 Web 站點時會遇到很多困難。
生成可訪問的 Web 站點有很多充分的理由:財務、道德、法律等等。但是,我們將重點討論法律動機。在美國,按照康復法案 (Rehabilitation Act) 508 節的要求,聯邦政府機構開發的任何 Web 站點都要使殘疾人士可以訪問。這一法律適用於聯邦政府機構以及與聯邦政府機構訂立合同的公司(請參閱 )。
其他國家/地區也具有類似的要求。例如,在加拿大,Treasury Board Common Look and Feel Standards 要求聯邦政府機構開發的 Web 站點都要使殘疾人士可以訪問。在澳大利亞,Disability Discrimination Act 要求澳大利亞服務器上承載的所有 Web 站點(無論其是否是政府的 Web 站點)都要使殘疾人士可以訪問。(有關可訪問性法律的詳細信息,請參閱 。)
在我知道的 Web 站點開發人員中,沒有任何人會故意生成殘疾人士無法訪問的 Web 站點。問題在於大多數開發人員都不熟悉各種可訪問性標准。
在本文的下列各節中,將概述以下兩個最重要的可訪問性標准:WCAG 和 508 節標准。您還將學習如何通過使用 ASP.NET 控件生成可訪問的 Web 頁。最後,您將學習如何“驗證”Web 頁的可訪問性。
幾乎所有可訪問性標准和法律都源自 W3C Web Content Accessibility 1.0 Guidelines (WCAG)。這些准則是由 World Wide Web Consortium 在 1999 年 5 月 5 日作為推薦標准首次發布的(請參閱 )。
WCAG 包含 14 條准則。每一條准則又包含一個或多個進一步闡明該准則的檢查點。每個檢查點都按 1 到 3 的優先級進行分級。為使這些准則的實施變得更加容易,W3C 已經發布了一組文檔,其中包含有關如何遵守這些准則的技術(請參閱 -TECHS/)。
您可以要求不同程度地遵守 WCAG 准則。如果要求 Web 站點滿足所有優先級 1 的檢查點,則您可以顯示具有 Conformance Level A 的標識語。當 Web 站點滿足所有優先級 1 和 2 檢查點時,該 Web 站點可以顯示 Conformance Level Double-A 標識語。最後,滿足所有檢查點的 Web 站點可以顯示 Conformance Level Triple-A 標識語(請參閱 )。
508 節准則源自 WCAG 准則。在美國,聯邦政府機構(以及與聯邦政府機構訂立合同的公司)需要對這組准則給予最高程度的關注,因為這些准則具有法律效力。您可以在 508 節 Web 站點讀到 508 節准則的完整文本。
ASP.NET 2.0 框架旨在使您能夠滿足所有 WCAG 優先級 1 和優先級 2 的檢查點以及所有 508 節准則。這些准則使用起來非常嚴格。每個使用 ASP.NET 2.0 框架的開發人員都需要檢查和測試每個 ASP.NET 控件的可訪問性。而且,每個開發人員都應該在桌面上安裝一個屏幕閱讀器,以便針對這些准則測試頁。
本文重點討論 ASP.NET 2.0 框架中六個方面的可訪問性改進。在下列各節中,您將學習如何使用 ASP.NET 控件來顯示可訪問的圖像、表單、導航、數據和 XHTML。在本節結尾,我們還將考慮與在 ASP.NET 頁中使用客戶端腳本有關的可訪問性問題。
您不應當做這樣的假設:與 Web 站點交互的每個人都可以實際看到您的 Web 站點。如果某個人是盲人或者視力不足,那麼這個人就可能需要使用屏幕閱讀器或盲文顯示器來訪問您的 Web 頁。屏幕閱讀器通過使用語音合成器來朗讀 Web 頁中的文本。盲文顯示器將頁中的文本轉換為盲文表示。
對於無法看到它們的人而言,圖像和其他非文本頁元素(例如,Java、Shockwave 和 Flash 內容)都是沒有用的。如果您希望使 Web 站點對於盲人或弱視的人是可訪問的,那麼需要為 Web 頁中的所有非文本內容提供文本等效內容。
Web 頁中的每個圖像都應該包含 alt 屬性。alt 屬性用來表示由屏幕閱讀器或其他輔助性設備閱讀的替換文本。以下是 alt 屬性的使用方式。
alt 屬性應當包含圖像的說明。在任何情況下,它都不應該只是包含該圖像的文件名。alt 屬性的目的是為盲人和視力正常的人傳遞相同的圖像信息。寫入 alt 屬性的值時要求對該元素的含義進行人工解釋。因此,不能自動完成創建 alt 屬性的過程。
每個顯示圖像的 ASP.NET 控件都包含用於為該圖像提供替換文本的方法。例如,ASP.NET 圖像控件包含 AlternateText 屬性。如果使用 Image 控件,則需要將 AlternateText 屬性設置為有意義的值。
如果某個圖像只是用作設計元素,則應當將它的 alt 屬性設置為空字符串。如果圖像不具有需要傳達的有用信息,那麼就沒有理由使屏幕閱讀器的頁解說變得散亂。
在 ASP.NET 2.0 框架中,必須采取特殊措施,使您能夠呈現空的 AlternateText。如果將空文本分配給 ASP.NET 控件的屬性,則 ASP.NET 控件將根本不會呈現該屬性。例如,假設將以下 ASP.NET Image 控件添加到頁中。
在這種情況下,會呈現以下標記。
請注意,alt 屬性消失了。這是所有 ASP.NET 控件屬性的默認行為。當沒有為屬性分配值時,該屬性不會呈現出來。遺憾的是,在這種情況下,我們確實希望為 alt 屬性呈現空值。
為了解決該問題,ASP.NET 2.0 框架中引入了以下新屬性,使您能夠用 Image 控件顯示空替換文本:GenerateEmptyAlternateText 屬性。
如果使用 GenerateEmptyAlternateText 屬性,則會正確地呈現 alt="" 屬性。
當圖像表示某個真正復雜的事物(例如,組織結構圖)時,不能使用 alt 屬性來提供替換文本說明。當需要提供較長的圖像含義說明時,需要使用 longdesc 屬性。
longdesc 屬性接受相對或絕對 URL 作為它的值。該 URL 應當鏈接到包含圖像內容的文本說明的頁。以下示例說明如何將該屬性與 標記配合使用。
ASP.NET Image 控件包含一個名為 DescriptionUrl 的屬性,它對應於 HTML longdesc 屬性。以下示例說明如何使用該屬性。
Web 頁表單可能給視力低下的人士以及缺乏動作協調性的人士帶來問題。如果通過屏幕閱讀器訪問 Web 頁表單,那麼可能很難將表單域與其相應的標簽相關聯。例如,假設 Web 頁包含以下表單。
First Name: Last Name:
該表單顯示一個人的名和姓的輸入域。在這種情況下,因為該表單顯示在表中,所以屏幕閱讀器用戶可能很難將正確的標簽與正確的表單域相關聯。HTML 4.0 中引入以下新標記,以使您能夠將表單域標簽與表單域相關聯: 標記。下面說明如何使用 標記編寫前面的表單。
標記將表單域標簽與其相應的表單域顯式關聯起來。請注意, 域包含 id 屬性,這是因為 for 屬性的值必須是輸入域的 id 屬性而不是 name 屬性。
通常,ASP.NET Label 控件生成 標記。但是,如果您在聲明 ASP.NET Label 控件時提供了 AssociatedControlId 屬性,則該控件會呈現 標記。下面說明如何用 ASP.NET Label 和 TextBox 控件生成可訪問的表單。
在為 ASP.NET 控件提供標簽時,應當使用 ASP.NET Label 控件,而不是 HTML 標記。在將一個 ID 分配給 ASP.NET 控件(如 TextBox 控件)時,呈現到浏覽器中的 ID 可能與您分配給該控件的 ID 不同。因此,如果使用 標記,則 標記中的 ID 可能與所呈現的 TextBox 控件的 ID 不匹配。另一方面,如果使用 ASP.NET Label 控件,則不必擔心該問題。
ASP.NET CheckBox、RadioButton、CheckBoxList 和 RadioButtonList 控件自動呈現 標記。在使用這些控件時,請小心使用 Text 屬性來標記控件的文本。您不應該執行以下操作。
Include Gift Wrap
相反,請執行以下操作。
對於通過屏幕閱讀器與 Web 頁進行交互的用戶,大型表單也可能產生問題。在聆聽大型表單的內容時,很容易忘記正在聆聽該表單的哪個部分。在顯示大型表單時,將該表單劃分為多個小塊是一個好主意。您可以通過使用
該表單通過
圖 5.
標記
視力低下的人士並不是 Web 頁用戶中唯一可能覺得 Web 表單難以訪問的人。那些缺乏動作協調性的用戶也會在與表單交互時遇到困難。
在生成 Web 表單時,為每個表單域包含 accesskey 和 tabindex 屬性總是一個好主意。accesskey 屬性使無法使用鼠標的用戶能夠直接導航到任何表單域。tabindex 屬性使您能夠控制表單域的 Tab 鍵順序。對於那些必須通過鍵盤(或像鍵盤一樣操作的輔助性設備)與頁面進行交互的用戶而言,這兩個屬性可使其生活變得更方便一些。
下面是一個同時使用 accesskey 和 tabindex 屬性的示例表單。
First Name Last Name
tabindex 屬性用來控制表單域的 Tab 鍵順序。因為第一個表單域具有的 tabindex 值為 1,所以當用戶第一次按 Tab 鍵時,該頁中任何出現在該表單之前的其他元素都被跳過。
在使用 Internet Explorer 或 Firefox 時,按 ALT+F 可自動將焦點移至 First Name 文本框。如果按 ALT+L,則焦點會自動移至 Last Name 文本框。在使用 Opera 時,必須首先按 SHIFT+ESC,然後才能選擇訪問鍵。
請注意,First Name 和 Last Name 標簽的第一個字母都帶有下劃線。通過為字母添加下劃線,可以為 Web 站點的用戶提供訪問鍵的直觀表示。這是在 Microsoft Windows 應用程序中標記訪問鍵的標准方式。但是,還有其他在表單中指示訪問鍵的推薦方法(請參閱 ~jkorpela/forms/l)。
使用下劃線指示訪問鍵的一個問題是無法為按鈕中的字符添加下劃線,並且超鏈接已經帶有下劃線。例如,下面的 Button 控件並不像您預期和希望的那樣工作。
ubmit" Runat="server" />
在呈現該 ASP.NET Button 控件時,會顯示實際文本 Submit,而不是顯示帶下劃線的S字符。ASP.NET Button 控件呈現 HTML 標記,但遺憾的是, 標記不支持下劃線。
您可能認為可以通過使用樣式規則解決該問題。遺憾的是,當前不存在以下這種跨浏覽器兼容方法:即,使用層疊樣式表為 標記中的單個字符加下劃線。
如果您願意在頁中使用客戶端 JavaScript,則可以解決該問題。清單 4 中的頁包含的 JavaScript 根據是否按下 ALT 鍵而顯示或隱藏所有訪問鍵。當按下 ALT 鍵時,會彈出一個框,顯示訪問鍵鍵盤組合鍵(參見圖 6)。該腳本在 Internet Explorer 和 Firefox 中都能夠正常工作(Opera 不使用 ALT 鍵來選擇訪問鍵)。
圖 6. AccessKeys.aspx
清單 4. AccessKeys.aspx
<%@ Page Language="VB" %>
清單 4 中的頁包含樣式表和客戶端 JavaScript。樣式表隱藏了由 accessKey 類標識的任何 標記的內容。JavaScript 會在 ALT 鍵已經被按下時進行檢測,並且顯示 標記的內容。
請注意,即使 Web 浏覽器中禁用了樣式表和 JavaScript,該頁也能夠正常工作。在這種情況下,將總是顯示訪問鍵幫助(參見圖 7)。
圖 7. AccessKeys.aspx 適度降格
我討厭撥打客戶支持電話並按照自動系統的指示操作。當計算機語音系統用其低沉單調的聲音宣布每個選項時,我感覺自己正在慢慢地變老。如果按錯了一個鍵,那麼您就會永遠迷失在自動計算機系統深不可測的迷宮中。
遺憾的是,如果您被迫使用屏幕閱讀器,那麼這正是您在訪問幾乎任何 Web 頁時的體驗。大多數 Web 站點都在每一頁中包含一個導航欄,其中包含指向 Web 站點各個部分的鏈接列表。如果使用屏幕閱讀器,則每當您打開頁時,都必須逐個聆聽這些導航鏈接中的各個鏈接。
通過對導航欄進行一處簡單的修改,就可顯著提高 Web 頁的可訪問性。只需添加一個用來跳過所有導航鏈接的方法。可以用“跳過導航”鏈接完成該工作。
例如,CNN Web 站點包含一個導航欄,其中列出了 CNN Web 站點的不同部分(World、U.S.、Weather 等等)。但是,CNN Web 站點的設計人員已經做了一件聰明的事情。如果查看頁的源代碼,則您將注意到導航欄上會出現以下鏈接。
當查看 CNN Web 站點的主頁時,您絕對不會看到該鏈接。該鏈接中包含的圖像是一幅透明的單像素圖像。但是,如果您用屏幕閱讀器訪問該頁,則會閱讀與該圖像相關聯的替換文本。盲人可以選擇跳過所有導航鏈接,並直接移至 Web 頁的主要內容區域(這與在自動語音系統中按 0 並直接導航到話務員等效)。
“跳過導航”鏈接已經被集成到多個標准 ASP.NET 2.0 控件中。特別需要指出的是,Menu、TreeView、SiteMapPath、Wizard 和 CreateUserWizard 控件全都支持“跳過導航”鏈接。
例如,清單 5 中的頁包含 ASP.NET Menu 控件。該控件用來顯示指向該 Web 站點中其他頁的鏈接列表。
清單 5. SiteMenu.aspx
如果查看清單 5 中頁的源代碼,您將看到以下鏈接出現在菜單頂部。
該鏈接包含一幅在您查看該頁時不會出現的寬和高皆為零的圖像。但是,通過屏幕閱讀器訪問該頁的用戶可以選擇“跳過導航”鏈接跳到該菜單的結尾。
默認情況下,“跳過導航”鏈接包含文本 Skip Navigation Links。可以通過更改 Menu 控件的 SkipLinkText 屬性修改該值。
ASP.NET 2.0 框架包含一組豐富的、用於顯示數據庫數據的控件。這些控件包括 GridView、DetailsView、DataList、FormView 和 Repeater 控件。默認情況下,GridView、DetailsView 和 DataList 控件在 HTML 表中顯示數據庫記錄。
在 HTML 表中呈現信息時,如果操作錯誤,則可能引起可訪問性問題。在聆聽 HTML 表的內容時,您很容易忘記自己當前在該表中的位置。例如,假設您使用 HTML 表顯示一個產品信息列表。在聆聽由屏幕閱讀器朗讀的表內容時,您很容易將某個表單元格所代表的信息搞混,不知道它們是有關產品名稱的,還是有關所訂購產品數量的,抑或是有關存儲這些產品的倉庫的代碼。
在查看 HTML 表時,可通過掃視列或行標題來確定特定單元格的含義。為使表對於使用屏幕閱讀器的用戶是可訪問的,需要顯式標記表標題並將這些標題與各個單元格顯式關聯起來。
在創建表以顯示數據時,應當始終使用正確的標記來標記列和行標題。表標題應當總是用
Product Name Price Milk $2.33 Cereal $5.61
在該示例中,
一些設計人員避免使用
為了使表可訪問,還應當顯式指明與各個單元格相關聯的一個或多個標題。您可以將多個屬性用於此目的:scope、headers 和 axis。
scope 屬性可用來指示表標題是列標題還是行標題。例如,下面的表同時包含列標題和行標題,它們都通過使用 scope 屬性的
First Train Last Train
該表包含 Boston 地鐵 Red Line 的時間表(參見圖 8)。請注意,每個列標題都包含 scope="col" 屬性,而每個行標題都包含 scope="row" 屬性。
圖 8. 簡單的地鐵時間表
scope 屬性非常適合於簡單的表。但是,對於更為復雜的表,需要使用 headers 屬性。例如,嵌套表可能有三個或更多的標題與單個單元格相關聯。headers 屬性使您能夠用與各個單元格相關聯的標題來標記它。
axis 屬性使您能夠對表標題進行分類。例如,在地鐵時間表中,可以將屬性 axis="location" 添加到每個表示位置的標題(Alewife 和 Braintree 標題)中。axis 屬性接受由逗號分隔的類別列表。
清單 6 中的頁包含一個更復雜版本的 Boston 地鐵時間表,它同時使用了 headers 和 axis 屬性(參見圖 9)。
圖 9. 復雜的地鐵時間表
清單 6. Subway.aspx
請注意,每個表單元格都包含 headers 屬性。headers 屬性表示與列和行標題相對應的 ID 的空格分隔列表。地鐵時間表中的每個單元格都具有相關聯的位置、日期和列車標題。
同時,請注意,每個
最後,請注意清單 6 中的表同時包含 summary 屬性和 標記。summary 屬性的工作方式非常類似於 alt 屬性。您可以使用 summary 屬性提供浏覽器未呈現的表的說明。另一方面,浏覽器呈現 標記的內容。您應當使用 標記來標識表的用途。
如果使用 ASP.NET 2.0 GridView 或 DetailsView 控件來顯示 HTML 表中的數據庫數據,則默認情況下,生成的 HTML 表是可訪問的。例如,清單 7 包含一個 ASP.NET 頁,它通過使用 GridView 控件來顯示 Titles 數據庫表的內容。
清單 7. DisplayTitles.aspx
在清單 7 中,GridView 控件被綁定到一個表示 Titles 數據庫表中記錄的 SqlDataSource 控件。在浏覽器中打開清單 7 中的 ASP.NET 頁時,Titles 數據庫表的內容顯示在 HTML 表中(參見圖 10)。
圖 10. DisplayTitles.aspx
請注意,GridView 控件自動為每個列標題生成
GridView 控件支持其他多個與可訪問性相關的屬性:
請注意,GridView 控件不具有 Summary 屬性。但是,像大多數 ASP.NET 控件一樣,GridView 控件支持 expando 屬性。當您聲明 GridView 控件時,您可以聲明喜歡的任何屬性,而該屬性將被呈現到浏覽器中。因此,如果您希望向 GridView 中添加摘要,則請按如下方式聲明 summary 屬性。
GridView 控件的默認行為非常適合於以可訪問的方式顯示簡單數據表。但是,如果您需要顯示更為復雜的表(例如,一組嵌套表),則您必須完成額外的工作。
例如,您可能希望顯示產品類別的列表,並且希望在每個類別下顯示匹配產品的列表。換句話說,您希望創建單頁“主要信息/詳細信息”表單(參見圖 11)。在這種情況下,需要為每個表單元格包含 headers 屬性。
圖 11. 嵌套 Repeater 控件
清單 8 中的頁說明如何將一個 Repeater 控件嵌套到另一個 Repeater 控件中,以及如何生成符合可訪問性准則要求的復雜表。
清單 8. NestedRepeaters.aspx
<%@ Page Language="VB"%> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %>
在清單 8 中,外層的 Repeater 控件用來列出產品類別,而內層的 Repeater 控件用來列出匹配產品。下列兩個 Helper 函數用來生成 Category Name 和 Product ID 標題的 id 值:GetProductHeader 和 GetCategoryHeader 函數。另外一個單獨的名為 GetHeaders 的 Helper 函數用來生成用於 headers 屬性的值。
清單 8 中的 ASP.NET 頁生成如下所示的 HTML 表。
ID Name Price
請注意,每個 標記都包含適當的 headers 屬性。
很多可訪問性准則共有的一個主題是這樣一個概念 — 即,Web 頁應當符合標准,這樣才能成為可訪問的頁。按照准則,您應當努力使用最新的 W3C 標准(例如,最新版本的 XHTML 和層疊樣式表)來生成 Web 站點。
特別需要指出的是,在設計 Web 頁時,您應當將文檔的結構與它的表示形式分開。請使用標記來表示 Web 頁的結構,並且使用層疊樣式表來控制 Web 頁的外觀。
例如,絕不要僅僅使用
元素來縮進文本塊。 元素的用途是創建原文的引文。如果您希望縮進文本,則應當改而使用層疊樣式表 margin 屬性。 您還應當只在表示數據表時使用 標記。盡管使用 標記來對 Web 頁面進行布局在當前是一種常見的做法,但是,請盡可能改而使用 標記。例如,清單 9 中的頁具有三列式布局,但是不包含一個 標記(參見圖 12)。 圖 12. 不含表的頁布局 清單 9. Tableless.aspx <%@ Page Language="VB" %> Tableless Layout Left column contents... Left column contents... Left column contents... Left column contents... Left column contents... Left column contents... Left column contents... Left column contents... Left column contents... Left column contents... Middle column contents... Middle column contents... Middle column contents... Middle column contents... Middle column contents... Middle column contents... Middle column contents... Middle column contents... Middle column contents... Right column contents... Right column contents... Right column contents... Right column contents... Right column contents... Right column contents... Right column contents... Right column contents... 清單 9 中的頁包含四個 標記。第一個 標記(名為 content)用來指定頁的內容區域的寬度。其余三個 標記(分別名為 left、middle 和 right)將內容區域劃分為三列。該頁可以在 Internet Explorer 6、Firefox 和 Opera 8 中正確顯示(要查看一些不使用 HTML 表創建布局的真正漂亮的頁面,請參見 。) WCAG 准則認為,不可能總是避免使用 標記來創建頁布局,因為較舊的浏覽器不完全支持層疊樣式表標准(請參閱 WCAG 准則 5)。在無法避免使用表創建布局的情況下,您應該確認這些表的內容在進行線性化(即,按照表-單元格順序來閱讀)時是有意義的。 因為 ASP.NET 框架必須與舊式和新式浏覽器同時兼容,所以一些 ASP.NET 控件實際上確實使用 標記來創建布局。例如,ASP.NET 2.0 Login 控件使用 標記來控制用戶名和密碼輸入字段的布局。 創建可訪問的腳本 WCAG 和 508 節准則中包含的一個非常嚴格的限制與客戶端腳本有關。根據 WCAG 1.0 准則中的優先級 1 檢查點,要求: 6.3 確保頁在腳本、小程序或其他編程對象關閉或不受支持時是可用的。如果這是不可能的,請在可訪問的替換頁中提供等效信息。[優先級 1] 508 節准則包含類似的要求: (l) 當頁利用腳本語言來顯示內容或者創建界面元素時,應該用可通過輔助性技術閱讀的功能性文本標識由該腳本提供的信息。 問題在於,多個 ASP.NET 控件要求具有客戶端 JavaScript 才能正常工作。這方面的主要示例是 ASP.NET LinkButton 控件。LinkButton 控件使用 JavaScript 將包含該控件的表單提交給 Web 服務器。 該問題沒有很好的解決方案。如果需要生成能夠滿足所有可訪問性准則的 Web 站點,則需要非常小心地使用客戶端腳本。您可能需要避免使用某些依賴於 JavaScript 的 ASP.NET 控件,例如 LinkButton 控件。 遺憾的是,在生成現代 Web 站點時,很難遵守該准則。這種假定似乎使得 Web 站點更像雜志而不是應用程序。現代 Web 站點傾向於包含動態的客戶端內容。例如,很多房地產 Web 站點包含一個 JavaScript 按揭計算器。人們尚不清楚 JavaScript 按揭計算器的文本等效物應該是什麼。 驗證頁的可訪問性 與存在 XHTML 的完全自動化驗證程序不同,並不存在完全自動化的可訪問性驗證程序。之所以不存在可訪問性的自動化驗證程序,原因在於判斷頁的可訪問性需要人工解釋。 例如,為了使 Web 頁可訪問,該頁中的每個圖像都必須包含有意義的替換文本。目前,沒有任何計算機能夠確定一段文本是否具有與圖像相同的含義。可訪問性驗證程序最多只能提供應該檢查的事物的列表。 Visual Studio .NET 2005(但不是 Visual Web Developer)包含可訪問性檢查器。可從工具欄中打開可訪問性檢查器。還可通過選擇菜單選項 Tools、Check Accessibility 來打開它(參見圖 13)。 圖 13. Visual Studio .NET 2005 可訪問性檢查器 可訪問性檢查器提供了用於按照 WCAG 優先級 1 檢查點、WCAG 優先級 2 檢查點或 508 節准則驗證 Web 站點的選項。可以通過打開“Error List”(依次選擇菜單選項 View、Other Windows、Error List)來查看 Web 站點的驗證結果。 Visual Studio .NET 2005 可訪問性檢查器還提供顯示可訪問性問題的“手動檢查列表”的選項。如果選擇該選項,則每當驗證 Web 站點的可訪問性時,都會在 Error List 窗口中顯示相同的可訪問性問題靜態列表。該檢查列表包含無法通過可訪問性檢查器自動驗證的問題。 如果使用 Visual Web Developer 生成 Web 站點,則還可以檢查 Web 頁的可訪問性。為此,需要使用某個聯機可訪問性檢查器。下面的鏈接指向兩個最流行的聯機可訪問性檢查器: • Bobby • WAVE 示例應用程序:可訪問的 XHTML ASP.NET Web 站點 在最後一節中,我們將從頭到尾完整地生成一個 ASP.NET 2.0 Web 站點。本白皮書隨附有該示例 Web 站點的源代碼。您可以下載該示例 Web 站點的源代碼,並且在 Visual Web Developer 或 Visual Studio .NET 2005 中打開該 Web 站點。 我們的目標是創建一個完全符合標准的 Web 站點。該 Web 站點將通過 XHTML 1.0 Strict(甚至 XHTML 1.1)驗證。而且,該 Web 站點還可供殘疾人士訪問。它將同時滿足 508 節和 WCAG(優先級 1 和優先級 2)可訪問性要求。 我們將生成一個名為 Super Super Bookstore Web 站點的網上書店。我們將通過 Amazon 電子商務 Web 服務檢索書店的所有書籍清單。Amazon 電子商務 Web 服務為我們提供了足夠的免費示例數據,以供我們進行演練(有關 Amazon Web 服務的詳細信息,請參閱 )。 為簡單起見,我們的 Web 站點僅由兩個 ASP.NET 頁組成: • Default.aspx — 該頁顯示指定類別中的書籍的列表。• Search.aspx — 該頁使您能夠搜索滿足特定搜索條件的所有書籍。 在幕後,該 Web 站點使用了 ASP.NET 2.0 框架的多項新功能。例如,該 Web 站點使用了一個母版頁來創建公共頁布局,並且使用了一個主題來創建公共頁樣式。最後,示例站點使用新的 GridView 和 ObjectDataSource 控件進行數據訪問。 訪問 Amazon Web 服務 Super Super Bookstore 使用一個名為 Amazon 的公共類來針對 Amazon 書目檢索書籍信息並執行搜索。該類包含在清單 10 中。 清單 10. Amazon.vb Imports Microsoft.VisualBasic Public Class Amazon Const SubscriptionId As String = "1CD1NYF3YQ830DG7AM02" ''' ''' Attempts to get books in category from cache. ''' If not in cache, call Amazon Web service ''' Public Function GetBooks(ByVal CategoryId As String) _ As AmazonServices.Item() Dim context As HttpContext = HttpContext.Current Dim Books As AmazonServices.Item() If IsNothing(context.Cache(CategoryId)) Then Books = GetBooksFromAmazon(CategoryId) context.Cache(CategoryId) = Books Else Books = CType(context.Cache(CategoryId), _ AmazonServices.Item()) End If Return Books End Function ''' ''' Retrieves books in certain category from Web service ''' Public Function GetBooksFromAmazon(ByVal CategoryId As String) _ As AmazonServices.Item() Dim service As New AmazonServices.AWSECommerceService() ' Initialize Request Dim searchRequest As New AmazonServices.ItemSearchRequest With searchRequest .SearchIndex = "Books" .Sort = "salesrank" .ResponseGroup = New String() {"Medium"} .BrowseNode = CategoryId End With Dim search As New AmazonServices.ItemSearch With search .SubscriptionId = SubscriptionId .Request = New AmazonServices.ItemSearchRequest() _ {searchRequest} End With ' Get Response Dim response As AmazonServices.ItemSearchResponse = Nothing Try service.Timeout = 5000 response = service.ItemSearch(search) Catch End Try If IsNothing(response) Then Return Nothing End If Return response.Items(0).Item End Function ''' ''' Searches for books by calling Amazon Web service ''' Public Function SearchBooksFromAmazon(ByVal Author As String, _ ByVal Title As String, ByVal Keywords As String, _ ByVal PowerSearch As String) As AmazonServices.Item() ' Don't search if nothing to search for If IsNothing(PowerSearch) And IsNothing(Author) And _ IsNothing(Title) And IsNothing(Keywords) Then Return Nothing End If ' Initialize Request Dim service As New AmazonServices.AWSECommerceService() Dim searchRequest As New AmazonServices.ItemSearchRequest With searchRequest .SearchIndex = "Books" .ResponseGroup = New String() {"Medium"} If Not IsNothing(PowerSearch) Then .Power = PowerSearch Else If Not IsNothing(Author) Then .Author = Author End If If Not IsNothing(Title) Then .Title = Title End If If Not IsNothing(Keywords) Then .Keywords = Keywords End If End If End With Dim search As New AmazonServices.ItemSearch With search .SubscriptionId = SubscriptionId .Request = New AmazonServices.ItemSearchRequest() _ {searchRequest} End With ' Get Response Dim response As AmazonServices.ItemSearchResponse Try service.Timeout = 5000 response = service.ItemSearch(search) Catch End Try If IsNothing(response) Then Return Nothing End If Return response.Items(0).Item End Function ''' ''' The Amazon Author property represents a list of authors. ''' Therefore, we create a comma separated list ''' Public Shared Function FormatAuthor(ByVal Authors As String()) _ As String If Not IsNothing(Authors) Then Return String.Join(", ", Authors) Else Return "Not Listed" End If End Function ''' ''' Formats Amazon ListPrice into US currency ''' Public Shared Function FormatPrice(ByVal Price As String) As String If Not IsNothing(Price) Then Return "$" & Price.Insert(Price.Length - 2, ".") Else Return "Not Listed" End If End Function ''' ''' Formats tooltip for the link to the book details ''' Public Shared Function _ FormatDetailsTooltip(ByVal Title As String) As String If Not IsNothing(Title) Then Return String.Format("Link to {0} details", Title) Else Return "Link to details" End If End Function ''' ''' If there is no book cover, we fall back to displaying our image ''' Public Shared Function FormatBookCover(ByVal Url As String) _ As String If Not IsNothing(Url) Then Return Url Else Return "Images/NoBookCover.gif" End If End Function End Class 該類中的兩個最重要的函數名為 GetBooksFromAmazon 和 SearchBooksFromAmazon。第一個函數從 Default.aspx 頁中調用,以便按照類別顯示書籍清單。第二個函數從 Search.aspx 頁中調用,以便使用戶能夠搜索書籍。 這兩個函數都使用名為 AmazonServices 的 Web 服務代理類。該代理類是通過依次選擇菜單選項 Web site、Add Web Reference 並且輸入 URL 創建的。這是用於訪問美國 Amazon 數據的正確的 URL。 默認頁 Default.aspx 頁顯示書籍類別的列表,並且顯示所選類別的匹配書籍的列表(參見圖 14)。Default.aspx 頁包含在清單 11 中。 圖 14. 默認頁 清單 11. Default.aspx <%@ Page Language="VB" MasterPageFile="~/SiteMaster.master" Title="Super Super Books" %> Book Listings ' AlternateText="Book cover image" Runat="server" /> <%#Server.HtmlEncode(Eval("ItemAttributes.Title"))%> Authors: <%#Amazon.FormatAuthor(Eval("ItemAttributes.Author"))%> Price: <%#Amazon.FormatPrice(Eval("ItemAttributes.ListPrice.Amount"))%> Sales Rank: <%#Eval("SalesRank")%> ' Text="View Details" Tooltip= '<%#Amazon.FormatDetailsTooltip(Eval("ItemAttributes.Title"))%>' Runat="server" /> 該頁使用下列兩個 ASP.NET 控件來顯示書籍清單:Menu 控件和 GridView 控件。Menu 控件用來顯示書籍類別的列表,而 GridView 控件用來顯示書籍列表。 GridView 控件被綁定到 ObjectDataSource 控件。ObjectDataSource 控件繼而調用 Amazon 類中的 GetBooks() 方法來檢索書籍列表。 默認頁的 XHTML 功能 在生成 XHTML 頁時,目標之一是將文檔的結構與其表示形式截然分開。為了達到這一目標,不能在 Default.aspx 頁中的任何 ASP.NET 控件上設置格式屬性。頁格式設置被封裝在通過 ASP.NET 主題與該頁相關聯的外部樣式表中。 ASP.NET 2.0 主題使您可以更容易地遵循 Web 標准,因為它們將所有表示內容與頁分開。示例站點包含一個名為 SiteTheme 的主題,該主題包含單個樣式表。該主題自動使用 Web.Config 文件中的下列配置設置與每個頁相關聯。 您應該注意到,HTML 表沒有用來創建頁布局。盡管 XHTML 標准和可訪問性標准都沒有禁止您使用表來創建頁布局,但這兩個標准都建議您避免這樣做。在示例站點中,頁布局完全是由外部樣式表確定的。頁本身由兩個 元素劃分為兩列。外部樣式表包含確定這兩個 元素位置的規則。 最後,示例站點在提供頁時使用內容協商。當使用能夠理解 application/xhtml+xml MIME 類型的浏覽器從 Web 站點請求頁時,將以 MIME 類型提供該頁;否則,將以 text/html 類型提供該頁。 內容協商是用 Global.asax 文件中的以下事件處理程序完成的。 Sub Application_PreSendRequestHeaders(ByVal s As Object, _ ByVal e As EventArgs) If Array.IndexOf(Request.AcceptTypes, _ "application/xhtml+xml") > Then ResponseContentType = application/xhtml+xml End If End Sub 默認頁的可訪問性功能 當無法提供 JavaScript 的文本等效內容時WCAG 和 節可訪問性准則都禁用客戶端 JavaScript為了滿足這些准則Defaultaspx 頁不依賴於客戶端 JavaScript即使您在浏覽器中關閉 JavaScript該頁仍然能夠正常工作 為了滿足該要求在實現菜單時必須完成額外的工作默認情況下ASPNET Menu控件為每個菜單項呈現 JavaScript 以處理客戶端單擊事件但是當為菜單項提供了 NavigateUrl 屬性時該菜單項將不再使用 JavaScript 在示例站點中為每個菜單項提供了一個指回到 Defaultaspx 頁的 NavigateUrl 屬性當您單擊菜單項時將重新加載 Defaultaspx 頁Page_Load 事件處理程序用來檢測單擊了哪個菜單項而且該子例程用當前菜單選擇更新菜單 使用 Menu 控件的好處是Menu 控件自動生成跳過導航鏈接如果使用 Tab 鍵浏覽 Defaultaspx 頁中的每個元素會注意到(觀察浏覽器的狀態欄)有一個跳過菜單內容的隱藏鏈接Menu 控件使您能夠自動滿足 WCAG 和 節准則該准則要求您提供相應的方法以跳過重復性的導航鏈接 搜索頁 搜索頁包含一個表單使 Web 站點的用戶能夠通過提供書籍作者書名書籍關鍵字或者通過提供復雜查詢來搜索書籍(參見圖 )查詢的結果顯示在 GridView 控件中Searchaspx 頁包含在清單 中 圖 搜索頁 清單 Searchaspx <%@ Page Language="VB" MasterPageFile="~/SiteMaster.master" Title="Search Books" %> Search Books Quick Search access key is a access key is t access key is k access key is s Power Search access key is q access key is p AlternateText=Book cover image Runat=server /> ><%#ServerHtmlEncode(Eval(ItemAttributesTitle))%>> Authors: <%#AmazonFormatAuthor(Eval(ItemAttributesAuthor))%> Price: <%#AmazonFormatPrice( Eval(ItemAttributesListPriceAmount))%> Sales Rank: <%#Eval(SalesRank)%> Text=View Details Tooltip= <%#AmazonFormatDetailsTooltip(Eval(ItemAttributesTitle))%> Runat=server /> >搜索頁的 XHTML 功能> 就像默認頁一樣搜索頁不包含任何表示性元素或屬性搜索頁的樣式和布局完全封裝在通過 ASPNET 主題與該頁相關聯的外部樣式表中 同樣像默認頁一樣搜索頁使用內容協商如果有人用能夠識別 application/xhtml+xml MIME 類型的浏覽器請求搜索頁則將以該 MIME 類型提供該頁否則將以 text/html 類型提供該頁 >搜索頁的可訪問性功能> 搜索頁包含一個表單或者更准確地說該頁包含被劃分為兩個子表單的單個表單它包含一個Quick Search表單和一個Power Search表單 請注意該表單用 HTML 標記劃分為兩個子表單 標記使您能夠將邏輯相關的表單元素組合在一起可訪問性准則要求您在處理復雜表單時使用 標記(請參閱 WCAG ) 而且請注意每個表單字段都與其標簽顯式關聯每個 ASPNET 控件都包含一個指向其相應表單字段的 AssociatedControlID 屬性標簽和字段之間的這些顯式關聯可以幫助屏幕閱讀器的用戶確定特定表單字段的用途 最後請注意每個 Label 控件都分配了一個訪問鍵訪問鍵使您無需使用鼠標就能夠方便地浏覽表單字段例如如果按 ALT+A則可以輸入作者的姓名如果隨後按 ALT+S則會提交Quick Search表單並且在 GridView 中顯示結果換句話說無需觸摸鼠標即可方便地執行搜索 如果按 ALT 鍵則會自動顯示訪問鍵(參見圖 )這通過 JavaScript 實現請注意在每個表單字段後面都會出現一個 標記例如Title 搜索字段是通過以下代碼實現的 access key is t 當按 ALT 鍵時將執行客戶端 JavaScript並且顯示 標記的內容 alt= src=http://imgeducitycn/img_///gif width= border=> 圖 搜索表單訪問鍵 您可能為該功能感到擔心因為按照可訪問性准則當 JavaScript 和樣式表關閉時該頁必須能夠繼續工作(WCAG 准則 )幸運的是當 JavaScript 和樣式表都被禁用時該頁確實能夠正常工作在這種情況下 標記的內容不再隱藏並且總是顯示訪問鍵(參見圖 ) alt= src=http://imgeducitycn/img_///gif width= border=> 圖 搜索表單適度降格>母版頁> 示例 Web 站點在幕後使用一個名為 SiteMastermaster 的 ASPNET 母版頁母版頁使您能夠在 Web 站點的多個頁中包含相同的內容並創建相同的布局母版頁通過 WebConfig 文件中的以下配置設置與示例 Web 站點中的每個頁相關聯 母版頁的內容包含在清單 中 清單 SiteMastermaster <%@ Master Language=VB %> //WC//DTD XHTML Strict//EN strictdtd> > server> Super Super Books form runat=server> SiteLogo src= alt=SSB Web site logo image /> http://imgeducitycn/img_///png alt=Valid XHTML icon class=icon/> http://imgeducitycn/img_///gif alt=Valid CSS icon class=icon /> width= src=http://imgeducitycn/img_///png alt=Level DoubleA conformance icon WCWAI Web Content Accessibility Guidelines class=icon /> >母版頁的 XHTML 功能> 利用母版頁可以方便地為 Web 站點中的所有頁提供正確的 DOCTYPESiteMastermaster 頁包含 XHTML Strict DOCTYPE在母版頁中指定 DOCTYPE 的好處是如果您將來需要更改 Web 站點中所有頁的 DOCTYPE那麼只需在一個位置更改它例如在不久之後的某一天您可能希望遷移到 XHTML Web 站點並修改 DOCTYPE 以反映所做的更改 母版頁還包含一系列一致性標識語它們出現在示例 Web 站點中每一頁的頁腳一致性標識語通告人們該 Web 站點符合 XHTMLCSS 和 WCAG Web 標准(參見圖 ) alt= src=http://imgeducitycn/img_///gif width= border=> 圖 一致性標識語>母版頁的可訪問性功能> 示例 Web 站點中每一頁的頂部都包含一個鏈接可以使用該鏈接切換用於顯示相應頁的樣式表每一頁都可以用下列兩個版本之一進行顯示普通文本版本和大型文本版本在選擇大型文本版本以後Web 站點中所有文本的大小都會有所增加以使可讀性更強(參見圖 ) alt= src=http://imgeducitycn/img_///gif width= border=> 圖 大型文本大小 用戶只需要執行該選擇一次如果某個用戶選擇 Web 站點的大型文本版本那麼該首選項會被自動記錄下來並且每當該用戶返回該 Web 站點時都會使用它該功能是通過利用 ASPNET 框架的另一項新功能實現的配置文件配置文件使您能夠存儲用戶在多次訪問 Web 站點時的設置 配置文件在 WebConfig 文件中定義 該配置文件定義一個名為 AccessibleStyleSheet 的布爾型屬性在 WebConfig 文件中定義該屬性以後就可以在任何 ASPNET 頁中通過由 Page 類公開的 Profile 屬性來讀取或設置該屬性例如要將 AccessibleStyleSheet 屬性設置為值 True並且顯示該 Web 站點的大型文本版本可以編寫以下代碼 ProfileAccessibleStyleSheet = true 母版頁包含用於選擇 Web 站點的普通文本或大型文本版本的所有邏輯HyperLink 控件用於使 Web 站點訪問者能夠執行該選擇在單擊 HyperLink 以後Page_Load 事件處理程序檢測用戶的選擇並設置 AccessibleStyleSheet Profile 屬性 如果使用 LinkButton 控件(而不是 HyperLink 控件)那麼這裡的代碼會更加簡單但是可訪問性准則再一次禁止我們這樣做因為 LinkButton 控件依賴客戶端 JavaScript 在選擇大型文本版本以後將向該頁中添加對附加樣式表的引用該樣式表包含單個規則 body { fontsize: xlarge; } 該規則將正文字體大小設置為值 xlarge因為主樣式表(包含在 SiteTheme 文件夾中)中指定的所有字體都使用相對大小所以修改正文元素的字體大小會自動增加 Web 站點中所有元素的字體大小 >小結> Web 標准是一個好東西通過遵循 Web 標准您能夠以最少的工作讓最廣大的受眾訪問您的 Web 站點您的 Web 站點將與更多的浏覽器兼容並且它們更有可能在將來繼續正常工作 ASPNET 框架旨在使您能夠輕松地生成滿足 Web 標准的 Web 站點該框架使您能夠輕松地生成 XHTML Web 站點在 ASPNET 框架中默認情況下所有 ASPNET 控件都呈現 XHTML 元素和屬性而且Visual Studio NET 和 Visual Web Developer 允許您在生成頁的過程中自動針對 XHTML 標准驗證這些頁的有效性 通過 ASPNET 框架還可以更容易地生成可被殘疾人士訪問的 Web 站點ASPNET 框架中的控件包含大量在設計時考慮了可訪問性的新屬性例如每個呈現圖像的 ASPNET 控件都使您能夠呈現圖像的替換文本此外所有新導航控件都包含跳過導航鏈接以使殘疾人士可以更容易地浏覽 Web 站點 >>> From:http://tw.wingwit.com/Article/program/net/201311/12505.html
元素的用途是創建原文的引文。如果您希望縮進文本,則應當改而使用層疊樣式表 margin 屬性。 您還應當只在表示數據表時使用 標記。盡管使用 標記來對 Web 頁面進行布局在當前是一種常見的做法,但是,請盡可能改而使用 標記。例如,清單 9 中的頁具有三列式布局,但是不包含一個 標記(參見圖 12)。 圖 12. 不含表的頁布局 清單 9. Tableless.aspx <%@ Page Language="VB" %> Tableless Layout Left column contents... Left column contents... Left column contents... Left column contents... Left column contents... Left column contents... Left column contents... Left column contents... Left column contents... Left column contents... Middle column contents... Middle column contents... Middle column contents... Middle column contents... Middle column contents... Middle column contents... Middle column contents... Middle column contents... Middle column contents... Right column contents... Right column contents... Right column contents... Right column contents... Right column contents... Right column contents... Right column contents... Right column contents... 清單 9 中的頁包含四個 標記。第一個 標記(名為 content)用來指定頁的內容區域的寬度。其余三個 標記(分別名為 left、middle 和 right)將內容區域劃分為三列。該頁可以在 Internet Explorer 6、Firefox 和 Opera 8 中正確顯示(要查看一些不使用 HTML 表創建布局的真正漂亮的頁面,請參見 。) WCAG 准則認為,不可能總是避免使用 標記來創建頁布局,因為較舊的浏覽器不完全支持層疊樣式表標准(請參閱 WCAG 准則 5)。在無法避免使用表創建布局的情況下,您應該確認這些表的內容在進行線性化(即,按照表-單元格順序來閱讀)時是有意義的。 因為 ASP.NET 框架必須與舊式和新式浏覽器同時兼容,所以一些 ASP.NET 控件實際上確實使用 標記來創建布局。例如,ASP.NET 2.0 Login 控件使用 標記來控制用戶名和密碼輸入字段的布局。 創建可訪問的腳本 WCAG 和 508 節准則中包含的一個非常嚴格的限制與客戶端腳本有關。根據 WCAG 1.0 准則中的優先級 1 檢查點,要求: 6.3 確保頁在腳本、小程序或其他編程對象關閉或不受支持時是可用的。如果這是不可能的,請在可訪問的替換頁中提供等效信息。[優先級 1] 508 節准則包含類似的要求: (l) 當頁利用腳本語言來顯示內容或者創建界面元素時,應該用可通過輔助性技術閱讀的功能性文本標識由該腳本提供的信息。 問題在於,多個 ASP.NET 控件要求具有客戶端 JavaScript 才能正常工作。這方面的主要示例是 ASP.NET LinkButton 控件。LinkButton 控件使用 JavaScript 將包含該控件的表單提交給 Web 服務器。 該問題沒有很好的解決方案。如果需要生成能夠滿足所有可訪問性准則的 Web 站點,則需要非常小心地使用客戶端腳本。您可能需要避免使用某些依賴於 JavaScript 的 ASP.NET 控件,例如 LinkButton 控件。 遺憾的是,在生成現代 Web 站點時,很難遵守該准則。這種假定似乎使得 Web 站點更像雜志而不是應用程序。現代 Web 站點傾向於包含動態的客戶端內容。例如,很多房地產 Web 站點包含一個 JavaScript 按揭計算器。人們尚不清楚 JavaScript 按揭計算器的文本等效物應該是什麼。 驗證頁的可訪問性 與存在 XHTML 的完全自動化驗證程序不同,並不存在完全自動化的可訪問性驗證程序。之所以不存在可訪問性的自動化驗證程序,原因在於判斷頁的可訪問性需要人工解釋。 例如,為了使 Web 頁可訪問,該頁中的每個圖像都必須包含有意義的替換文本。目前,沒有任何計算機能夠確定一段文本是否具有與圖像相同的含義。可訪問性驗證程序最多只能提供應該檢查的事物的列表。 Visual Studio .NET 2005(但不是 Visual Web Developer)包含可訪問性檢查器。可從工具欄中打開可訪問性檢查器。還可通過選擇菜單選項 Tools、Check Accessibility 來打開它(參見圖 13)。 圖 13. Visual Studio .NET 2005 可訪問性檢查器 可訪問性檢查器提供了用於按照 WCAG 優先級 1 檢查點、WCAG 優先級 2 檢查點或 508 節准則驗證 Web 站點的選項。可以通過打開“Error List”(依次選擇菜單選項 View、Other Windows、Error List)來查看 Web 站點的驗證結果。 Visual Studio .NET 2005 可訪問性檢查器還提供顯示可訪問性問題的“手動檢查列表”的選項。如果選擇該選項,則每當驗證 Web 站點的可訪問性時,都會在 Error List 窗口中顯示相同的可訪問性問題靜態列表。該檢查列表包含無法通過可訪問性檢查器自動驗證的問題。 如果使用 Visual Web Developer 生成 Web 站點,則還可以檢查 Web 頁的可訪問性。為此,需要使用某個聯機可訪問性檢查器。下面的鏈接指向兩個最流行的聯機可訪問性檢查器: • Bobby • WAVE 示例應用程序:可訪問的 XHTML ASP.NET Web 站點 在最後一節中,我們將從頭到尾完整地生成一個 ASP.NET 2.0 Web 站點。本白皮書隨附有該示例 Web 站點的源代碼。您可以下載該示例 Web 站點的源代碼,並且在 Visual Web Developer 或 Visual Studio .NET 2005 中打開該 Web 站點。 我們的目標是創建一個完全符合標准的 Web 站點。該 Web 站點將通過 XHTML 1.0 Strict(甚至 XHTML 1.1)驗證。而且,該 Web 站點還可供殘疾人士訪問。它將同時滿足 508 節和 WCAG(優先級 1 和優先級 2)可訪問性要求。 我們將生成一個名為 Super Super Bookstore Web 站點的網上書店。我們將通過 Amazon 電子商務 Web 服務檢索書店的所有書籍清單。Amazon 電子商務 Web 服務為我們提供了足夠的免費示例數據,以供我們進行演練(有關 Amazon Web 服務的詳細信息,請參閱 )。 為簡單起見,我們的 Web 站點僅由兩個 ASP.NET 頁組成: • Default.aspx — 該頁顯示指定類別中的書籍的列表。• Search.aspx — 該頁使您能夠搜索滿足特定搜索條件的所有書籍。 在幕後,該 Web 站點使用了 ASP.NET 2.0 框架的多項新功能。例如,該 Web 站點使用了一個母版頁來創建公共頁布局,並且使用了一個主題來創建公共頁樣式。最後,示例站點使用新的 GridView 和 ObjectDataSource 控件進行數據訪問。 訪問 Amazon Web 服務 Super Super Bookstore 使用一個名為 Amazon 的公共類來針對 Amazon 書目檢索書籍信息並執行搜索。該類包含在清單 10 中。 清單 10. Amazon.vb Imports Microsoft.VisualBasic Public Class Amazon Const SubscriptionId As String = "1CD1NYF3YQ830DG7AM02" ''' ''' Attempts to get books in category from cache. ''' If not in cache, call Amazon Web service ''' Public Function GetBooks(ByVal CategoryId As String) _ As AmazonServices.Item() Dim context As HttpContext = HttpContext.Current Dim Books As AmazonServices.Item() If IsNothing(context.Cache(CategoryId)) Then Books = GetBooksFromAmazon(CategoryId) context.Cache(CategoryId) = Books Else Books = CType(context.Cache(CategoryId), _ AmazonServices.Item()) End If Return Books End Function ''' ''' Retrieves books in certain category from Web service ''' Public Function GetBooksFromAmazon(ByVal CategoryId As String) _ As AmazonServices.Item() Dim service As New AmazonServices.AWSECommerceService() ' Initialize Request Dim searchRequest As New AmazonServices.ItemSearchRequest With searchRequest .SearchIndex = "Books" .Sort = "salesrank" .ResponseGroup = New String() {"Medium"} .BrowseNode = CategoryId End With Dim search As New AmazonServices.ItemSearch With search .SubscriptionId = SubscriptionId .Request = New AmazonServices.ItemSearchRequest() _ {searchRequest} End With ' Get Response Dim response As AmazonServices.ItemSearchResponse = Nothing Try service.Timeout = 5000 response = service.ItemSearch(search) Catch End Try If IsNothing(response) Then Return Nothing End If Return response.Items(0).Item End Function ''' ''' Searches for books by calling Amazon Web service ''' Public Function SearchBooksFromAmazon(ByVal Author As String, _ ByVal Title As String, ByVal Keywords As String, _ ByVal PowerSearch As String) As AmazonServices.Item() ' Don't search if nothing to search for If IsNothing(PowerSearch) And IsNothing(Author) And _ IsNothing(Title) And IsNothing(Keywords) Then Return Nothing End If ' Initialize Request Dim service As New AmazonServices.AWSECommerceService() Dim searchRequest As New AmazonServices.ItemSearchRequest With searchRequest .SearchIndex = "Books" .ResponseGroup = New String() {"Medium"} If Not IsNothing(PowerSearch) Then .Power = PowerSearch Else If Not IsNothing(Author) Then .Author = Author End If If Not IsNothing(Title) Then .Title = Title End If If Not IsNothing(Keywords) Then .Keywords = Keywords End If End If End With Dim search As New AmazonServices.ItemSearch With search .SubscriptionId = SubscriptionId .Request = New AmazonServices.ItemSearchRequest() _ {searchRequest} End With ' Get Response Dim response As AmazonServices.ItemSearchResponse Try service.Timeout = 5000 response = service.ItemSearch(search) Catch End Try If IsNothing(response) Then Return Nothing End If Return response.Items(0).Item End Function ''' ''' The Amazon Author property represents a list of authors. ''' Therefore, we create a comma separated list ''' Public Shared Function FormatAuthor(ByVal Authors As String()) _ As String If Not IsNothing(Authors) Then Return String.Join(", ", Authors) Else Return "Not Listed" End If End Function ''' ''' Formats Amazon ListPrice into US currency ''' Public Shared Function FormatPrice(ByVal Price As String) As String If Not IsNothing(Price) Then Return "$" & Price.Insert(Price.Length - 2, ".") Else Return "Not Listed" End If End Function ''' ''' Formats tooltip for the link to the book details ''' Public Shared Function _ FormatDetailsTooltip(ByVal Title As String) As String If Not IsNothing(Title) Then Return String.Format("Link to {0} details", Title) Else Return "Link to details" End If End Function ''' ''' If there is no book cover, we fall back to displaying our image ''' Public Shared Function FormatBookCover(ByVal Url As String) _ As String If Not IsNothing(Url) Then Return Url Else Return "Images/NoBookCover.gif" End If End Function End Class 該類中的兩個最重要的函數名為 GetBooksFromAmazon 和 SearchBooksFromAmazon。第一個函數從 Default.aspx 頁中調用,以便按照類別顯示書籍清單。第二個函數從 Search.aspx 頁中調用,以便使用戶能夠搜索書籍。 這兩個函數都使用名為 AmazonServices 的 Web 服務代理類。該代理類是通過依次選擇菜單選項 Web site、Add Web Reference 並且輸入 URL 創建的。這是用於訪問美國 Amazon 數據的正確的 URL。 默認頁 Default.aspx 頁顯示書籍類別的列表,並且顯示所選類別的匹配書籍的列表(參見圖 14)。Default.aspx 頁包含在清單 11 中。 圖 14. 默認頁 清單 11. Default.aspx <%@ Page Language="VB" MasterPageFile="~/SiteMaster.master" Title="Super Super Books" %> Book Listings ' AlternateText="Book cover image" Runat="server" /> <%#Server.HtmlEncode(Eval("ItemAttributes.Title"))%> Authors: <%#Amazon.FormatAuthor(Eval("ItemAttributes.Author"))%> Price: <%#Amazon.FormatPrice(Eval("ItemAttributes.ListPrice.Amount"))%> Sales Rank: <%#Eval("SalesRank")%> ' Text="View Details" Tooltip= '<%#Amazon.FormatDetailsTooltip(Eval("ItemAttributes.Title"))%>' Runat="server" /> 該頁使用下列兩個 ASP.NET 控件來顯示書籍清單:Menu 控件和 GridView 控件。Menu 控件用來顯示書籍類別的列表,而 GridView 控件用來顯示書籍列表。 GridView 控件被綁定到 ObjectDataSource 控件。ObjectDataSource 控件繼而調用 Amazon 類中的 GetBooks() 方法來檢索書籍列表。 默認頁的 XHTML 功能 在生成 XHTML 頁時,目標之一是將文檔的結構與其表示形式截然分開。為了達到這一目標,不能在 Default.aspx 頁中的任何 ASP.NET 控件上設置格式屬性。頁格式設置被封裝在通過 ASP.NET 主題與該頁相關聯的外部樣式表中。 ASP.NET 2.0 主題使您可以更容易地遵循 Web 標准,因為它們將所有表示內容與頁分開。示例站點包含一個名為 SiteTheme 的主題,該主題包含單個樣式表。該主題自動使用 Web.Config 文件中的下列配置設置與每個頁相關聯。 您應該注意到,HTML 表沒有用來創建頁布局。盡管 XHTML 標准和可訪問性標准都沒有禁止您使用表來創建頁布局,但這兩個標准都建議您避免這樣做。在示例站點中,頁布局完全是由外部樣式表確定的。頁本身由兩個 元素劃分為兩列。外部樣式表包含確定這兩個 元素位置的規則。 最後,示例站點在提供頁時使用內容協商。當使用能夠理解 application/xhtml+xml MIME 類型的浏覽器從 Web 站點請求頁時,將以 MIME 類型提供該頁;否則,將以 text/html 類型提供該頁。 內容協商是用 Global.asax 文件中的以下事件處理程序完成的。 Sub Application_PreSendRequestHeaders(ByVal s As Object, _ ByVal e As EventArgs) If Array.IndexOf(Request.AcceptTypes, _ "application/xhtml+xml") > Then ResponseContentType = application/xhtml+xml End If End Sub 默認頁的可訪問性功能 當無法提供 JavaScript 的文本等效內容時WCAG 和 節可訪問性准則都禁用客戶端 JavaScript為了滿足這些准則Defaultaspx 頁不依賴於客戶端 JavaScript即使您在浏覽器中關閉 JavaScript該頁仍然能夠正常工作 為了滿足該要求在實現菜單時必須完成額外的工作默認情況下ASPNET Menu控件為每個菜單項呈現 JavaScript 以處理客戶端單擊事件但是當為菜單項提供了 NavigateUrl 屬性時該菜單項將不再使用 JavaScript 在示例站點中為每個菜單項提供了一個指回到 Defaultaspx 頁的 NavigateUrl 屬性當您單擊菜單項時將重新加載 Defaultaspx 頁Page_Load 事件處理程序用來檢測單擊了哪個菜單項而且該子例程用當前菜單選擇更新菜單 使用 Menu 控件的好處是Menu 控件自動生成跳過導航鏈接如果使用 Tab 鍵浏覽 Defaultaspx 頁中的每個元素會注意到(觀察浏覽器的狀態欄)有一個跳過菜單內容的隱藏鏈接Menu 控件使您能夠自動滿足 WCAG 和 節准則該准則要求您提供相應的方法以跳過重復性的導航鏈接 搜索頁 搜索頁包含一個表單使 Web 站點的用戶能夠通過提供書籍作者書名書籍關鍵字或者通過提供復雜查詢來搜索書籍(參見圖 )查詢的結果顯示在 GridView 控件中Searchaspx 頁包含在清單 中 圖 搜索頁 清單 Searchaspx <%@ Page Language="VB" MasterPageFile="~/SiteMaster.master" Title="Search Books" %> Search Books Quick Search access key is a access key is t access key is k access key is s Power Search access key is q access key is p AlternateText=Book cover image Runat=server /> ><%#ServerHtmlEncode(Eval(ItemAttributesTitle))%>> Authors: <%#AmazonFormatAuthor(Eval(ItemAttributesAuthor))%> Price: <%#AmazonFormatPrice( Eval(ItemAttributesListPriceAmount))%> Sales Rank: <%#Eval(SalesRank)%> Text=View Details Tooltip= <%#AmazonFormatDetailsTooltip(Eval(ItemAttributesTitle))%> Runat=server /> >搜索頁的 XHTML 功能> 就像默認頁一樣搜索頁不包含任何表示性元素或屬性搜索頁的樣式和布局完全封裝在通過 ASPNET 主題與該頁相關聯的外部樣式表中 同樣像默認頁一樣搜索頁使用內容協商如果有人用能夠識別 application/xhtml+xml MIME 類型的浏覽器請求搜索頁則將以該 MIME 類型提供該頁否則將以 text/html 類型提供該頁 >搜索頁的可訪問性功能> 搜索頁包含一個表單或者更准確地說該頁包含被劃分為兩個子表單的單個表單它包含一個Quick Search表單和一個Power Search表單 請注意該表單用 HTML 標記劃分為兩個子表單 標記使您能夠將邏輯相關的表單元素組合在一起可訪問性准則要求您在處理復雜表單時使用 標記(請參閱 WCAG ) 而且請注意每個表單字段都與其標簽顯式關聯每個 ASPNET 控件都包含一個指向其相應表單字段的 AssociatedControlID 屬性標簽和字段之間的這些顯式關聯可以幫助屏幕閱讀器的用戶確定特定表單字段的用途 最後請注意每個 Label 控件都分配了一個訪問鍵訪問鍵使您無需使用鼠標就能夠方便地浏覽表單字段例如如果按 ALT+A則可以輸入作者的姓名如果隨後按 ALT+S則會提交Quick Search表單並且在 GridView 中顯示結果換句話說無需觸摸鼠標即可方便地執行搜索 如果按 ALT 鍵則會自動顯示訪問鍵(參見圖 )這通過 JavaScript 實現請注意在每個表單字段後面都會出現一個 標記例如Title 搜索字段是通過以下代碼實現的 access key is t 當按 ALT 鍵時將執行客戶端 JavaScript並且顯示 標記的內容 alt= src=http://imgeducitycn/img_///gif width= border=> 圖 搜索表單訪問鍵 您可能為該功能感到擔心因為按照可訪問性准則當 JavaScript 和樣式表關閉時該頁必須能夠繼續工作(WCAG 准則 )幸運的是當 JavaScript 和樣式表都被禁用時該頁確實能夠正常工作在這種情況下 標記的內容不再隱藏並且總是顯示訪問鍵(參見圖 ) alt= src=http://imgeducitycn/img_///gif width= border=> 圖 搜索表單適度降格>母版頁> 示例 Web 站點在幕後使用一個名為 SiteMastermaster 的 ASPNET 母版頁母版頁使您能夠在 Web 站點的多個頁中包含相同的內容並創建相同的布局母版頁通過 WebConfig 文件中的以下配置設置與示例 Web 站點中的每個頁相關聯 母版頁的內容包含在清單 中 清單 SiteMastermaster <%@ Master Language=VB %> //WC//DTD XHTML Strict//EN strictdtd> > server> Super Super Books form runat=server> SiteLogo src= alt=SSB Web site logo image /> http://imgeducitycn/img_///png alt=Valid XHTML icon class=icon/> http://imgeducitycn/img_///gif alt=Valid CSS icon class=icon /> width= src=http://imgeducitycn/img_///png alt=Level DoubleA conformance icon WCWAI Web Content Accessibility Guidelines class=icon /> >母版頁的 XHTML 功能> 利用母版頁可以方便地為 Web 站點中的所有頁提供正確的 DOCTYPESiteMastermaster 頁包含 XHTML Strict DOCTYPE在母版頁中指定 DOCTYPE 的好處是如果您將來需要更改 Web 站點中所有頁的 DOCTYPE那麼只需在一個位置更改它例如在不久之後的某一天您可能希望遷移到 XHTML Web 站點並修改 DOCTYPE 以反映所做的更改 母版頁還包含一系列一致性標識語它們出現在示例 Web 站點中每一頁的頁腳一致性標識語通告人們該 Web 站點符合 XHTMLCSS 和 WCAG Web 標准(參見圖 ) alt= src=http://imgeducitycn/img_///gif width= border=> 圖 一致性標識語>母版頁的可訪問性功能> 示例 Web 站點中每一頁的頂部都包含一個鏈接可以使用該鏈接切換用於顯示相應頁的樣式表每一頁都可以用下列兩個版本之一進行顯示普通文本版本和大型文本版本在選擇大型文本版本以後Web 站點中所有文本的大小都會有所增加以使可讀性更強(參見圖 ) alt= src=http://imgeducitycn/img_///gif width= border=> 圖 大型文本大小 用戶只需要執行該選擇一次如果某個用戶選擇 Web 站點的大型文本版本那麼該首選項會被自動記錄下來並且每當該用戶返回該 Web 站點時都會使用它該功能是通過利用 ASPNET 框架的另一項新功能實現的配置文件配置文件使您能夠存儲用戶在多次訪問 Web 站點時的設置 配置文件在 WebConfig 文件中定義 該配置文件定義一個名為 AccessibleStyleSheet 的布爾型屬性在 WebConfig 文件中定義該屬性以後就可以在任何 ASPNET 頁中通過由 Page 類公開的 Profile 屬性來讀取或設置該屬性例如要將 AccessibleStyleSheet 屬性設置為值 True並且顯示該 Web 站點的大型文本版本可以編寫以下代碼 ProfileAccessibleStyleSheet = true 母版頁包含用於選擇 Web 站點的普通文本或大型文本版本的所有邏輯HyperLink 控件用於使 Web 站點訪問者能夠執行該選擇在單擊 HyperLink 以後Page_Load 事件處理程序檢測用戶的選擇並設置 AccessibleStyleSheet Profile 屬性 如果使用 LinkButton 控件(而不是 HyperLink 控件)那麼這裡的代碼會更加簡單但是可訪問性准則再一次禁止我們這樣做因為 LinkButton 控件依賴客戶端 JavaScript 在選擇大型文本版本以後將向該頁中添加對附加樣式表的引用該樣式表包含單個規則 body { fontsize: xlarge; } 該規則將正文字體大小設置為值 xlarge因為主樣式表(包含在 SiteTheme 文件夾中)中指定的所有字體都使用相對大小所以修改正文元素的字體大小會自動增加 Web 站點中所有元素的字體大小 >小結> Web 標准是一個好東西通過遵循 Web 標准您能夠以最少的工作讓最廣大的受眾訪問您的 Web 站點您的 Web 站點將與更多的浏覽器兼容並且它們更有可能在將來繼續正常工作 ASPNET 框架旨在使您能夠輕松地生成滿足 Web 標准的 Web 站點該框架使您能夠輕松地生成 XHTML Web 站點在 ASPNET 框架中默認情況下所有 ASPNET 控件都呈現 XHTML 元素和屬性而且Visual Studio NET 和 Visual Web Developer 允許您在生成頁的過程中自動針對 XHTML 標准驗證這些頁的有效性 通過 ASPNET 框架還可以更容易地生成可被殘疾人士訪問的 Web 站點ASPNET 框架中的控件包含大量在設計時考慮了可訪問性的新屬性例如每個呈現圖像的 ASPNET 控件都使您能夠呈現圖像的替換文本此外所有新導航控件都包含跳過導航鏈接以使殘疾人士可以更容易地浏覽 Web 站點 >>> From:http://tw.wingwit.com/Article/program/net/201311/12505.html
您還應當只在表示數據表時使用 標記。盡管使用 標記來對 Web 頁面進行布局在當前是一種常見的做法,但是,請盡可能改而使用 標記。例如,清單 9 中的頁具有三列式布局,但是不包含一個 標記(參見圖 12)。
圖 12. 不含表的頁布局
清單 9. Tableless.aspx
清單 9 中的頁包含四個 標記。第一個 標記(名為 content)用來指定頁的內容區域的寬度。其余三個 標記(分別名為 left、middle 和 right)將內容區域劃分為三列。該頁可以在 Internet Explorer 6、Firefox 和 Opera 8 中正確顯示(要查看一些不使用 HTML 表創建布局的真正漂亮的頁面,請參見 。)
WCAG 准則認為,不可能總是避免使用 標記來創建頁布局,因為較舊的浏覽器不完全支持層疊樣式表標准(請參閱 WCAG 准則 5)。在無法避免使用表創建布局的情況下,您應該確認這些表的內容在進行線性化(即,按照表-單元格順序來閱讀)時是有意義的。
因為 ASP.NET 框架必須與舊式和新式浏覽器同時兼容,所以一些 ASP.NET 控件實際上確實使用 標記來創建布局。例如,ASP.NET 2.0 Login 控件使用 標記來控制用戶名和密碼輸入字段的布局。
WCAG 和 508 節准則中包含的一個非常嚴格的限制與客戶端腳本有關。根據 WCAG 1.0 准則中的優先級 1 檢查點,要求:
6.3 確保頁在腳本、小程序或其他編程對象關閉或不受支持時是可用的。如果這是不可能的,請在可訪問的替換頁中提供等效信息。[優先級 1]
508 節准則包含類似的要求:
(l) 當頁利用腳本語言來顯示內容或者創建界面元素時,應該用可通過輔助性技術閱讀的功能性文本標識由該腳本提供的信息。
問題在於,多個 ASP.NET 控件要求具有客戶端 JavaScript 才能正常工作。這方面的主要示例是 ASP.NET LinkButton 控件。LinkButton 控件使用 JavaScript 將包含該控件的表單提交給 Web 服務器。
該問題沒有很好的解決方案。如果需要生成能夠滿足所有可訪問性准則的 Web 站點,則需要非常小心地使用客戶端腳本。您可能需要避免使用某些依賴於 JavaScript 的 ASP.NET 控件,例如 LinkButton 控件。
遺憾的是,在生成現代 Web 站點時,很難遵守該准則。這種假定似乎使得 Web 站點更像雜志而不是應用程序。現代 Web 站點傾向於包含動態的客戶端內容。例如,很多房地產 Web 站點包含一個 JavaScript 按揭計算器。人們尚不清楚 JavaScript 按揭計算器的文本等效物應該是什麼。
與存在 XHTML 的完全自動化驗證程序不同,並不存在完全自動化的可訪問性驗證程序。之所以不存在可訪問性的自動化驗證程序,原因在於判斷頁的可訪問性需要人工解釋。
例如,為了使 Web 頁可訪問,該頁中的每個圖像都必須包含有意義的替換文本。目前,沒有任何計算機能夠確定一段文本是否具有與圖像相同的含義。可訪問性驗證程序最多只能提供應該檢查的事物的列表。
Visual Studio .NET 2005(但不是 Visual Web Developer)包含可訪問性檢查器。可從工具欄中打開可訪問性檢查器。還可通過選擇菜單選項 Tools、Check Accessibility 來打開它(參見圖 13)。
圖 13. Visual Studio .NET 2005 可訪問性檢查器
可訪問性檢查器提供了用於按照 WCAG 優先級 1 檢查點、WCAG 優先級 2 檢查點或 508 節准則驗證 Web 站點的選項。可以通過打開“Error List”(依次選擇菜單選項 View、Other Windows、Error List)來查看 Web 站點的驗證結果。
Visual Studio .NET 2005 可訪問性檢查器還提供顯示可訪問性問題的“手動檢查列表”的選項。如果選擇該選項,則每當驗證 Web 站點的可訪問性時,都會在 Error List 窗口中顯示相同的可訪問性問題靜態列表。該檢查列表包含無法通過可訪問性檢查器自動驗證的問題。
如果使用 Visual Web Developer 生成 Web 站點,則還可以檢查 Web 頁的可訪問性。為此,需要使用某個聯機可訪問性檢查器。下面的鏈接指向兩個最流行的聯機可訪問性檢查器:
Bobby
在最後一節中,我們將從頭到尾完整地生成一個 ASP.NET 2.0 Web 站點。本白皮書隨附有該示例 Web 站點的源代碼。您可以下載該示例 Web 站點的源代碼,並且在 Visual Web Developer 或 Visual Studio .NET 2005 中打開該 Web 站點。
我們的目標是創建一個完全符合標准的 Web 站點。該 Web 站點將通過 XHTML 1.0 Strict(甚至 XHTML 1.1)驗證。而且,該 Web 站點還可供殘疾人士訪問。它將同時滿足 508 節和 WCAG(優先級 1 和優先級 2)可訪問性要求。
我們將生成一個名為 Super Super Bookstore Web 站點的網上書店。我們將通過 Amazon 電子商務 Web 服務檢索書店的所有書籍清單。Amazon 電子商務 Web 服務為我們提供了足夠的免費示例數據,以供我們進行演練(有關 Amazon Web 服務的詳細信息,請參閱 )。
為簡單起見,我們的 Web 站點僅由兩個 ASP.NET 頁組成:
在幕後,該 Web 站點使用了 ASP.NET 2.0 框架的多項新功能。例如,該 Web 站點使用了一個母版頁來創建公共頁布局,並且使用了一個主題來創建公共頁樣式。最後,示例站點使用新的 GridView 和 ObjectDataSource 控件進行數據訪問。
Super Super Bookstore 使用一個名為 Amazon 的公共類來針對 Amazon 書目檢索書籍信息並執行搜索。該類包含在清單 10 中。
清單 10. Amazon.vb
Imports Microsoft.VisualBasic Public Class Amazon Const SubscriptionId As String = "1CD1NYF3YQ830DG7AM02" ''' ''' Attempts to get books in category from cache. ''' If not in cache, call Amazon Web service ''' Public Function GetBooks(ByVal CategoryId As String) _ As AmazonServices.Item() Dim context As HttpContext = HttpContext.Current Dim Books As AmazonServices.Item() If IsNothing(context.Cache(CategoryId)) Then Books = GetBooksFromAmazon(CategoryId) context.Cache(CategoryId) = Books Else Books = CType(context.Cache(CategoryId), _ AmazonServices.Item()) End If Return Books End Function ''' ''' Retrieves books in certain category from Web service ''' Public Function GetBooksFromAmazon(ByVal CategoryId As String) _ As AmazonServices.Item() Dim service As New AmazonServices.AWSECommerceService() ' Initialize Request Dim searchRequest As New AmazonServices.ItemSearchRequest With searchRequest .SearchIndex = "Books" .Sort = "salesrank" .ResponseGroup = New String() {"Medium"} .BrowseNode = CategoryId End With Dim search As New AmazonServices.ItemSearch With search .SubscriptionId = SubscriptionId .Request = New AmazonServices.ItemSearchRequest() _ {searchRequest} End With ' Get Response Dim response As AmazonServices.ItemSearchResponse = Nothing Try service.Timeout = 5000 response = service.ItemSearch(search) Catch End Try If IsNothing(response) Then Return Nothing End If Return response.Items(0).Item End Function ''' ''' Searches for books by calling Amazon Web service ''' Public Function SearchBooksFromAmazon(ByVal Author As String, _ ByVal Title As String, ByVal Keywords As String, _ ByVal PowerSearch As String) As AmazonServices.Item() ' Don't search if nothing to search for If IsNothing(PowerSearch) And IsNothing(Author) And _ IsNothing(Title) And IsNothing(Keywords) Then Return Nothing End If ' Initialize Request Dim service As New AmazonServices.AWSECommerceService() Dim searchRequest As New AmazonServices.ItemSearchRequest With searchRequest .SearchIndex = "Books" .ResponseGroup = New String() {"Medium"} If Not IsNothing(PowerSearch) Then .Power = PowerSearch Else If Not IsNothing(Author) Then .Author = Author End If If Not IsNothing(Title) Then .Title = Title End If If Not IsNothing(Keywords) Then .Keywords = Keywords End If End If End With Dim search As New AmazonServices.ItemSearch With search .SubscriptionId = SubscriptionId .Request = New AmazonServices.ItemSearchRequest() _ {searchRequest} End With ' Get Response Dim response As AmazonServices.ItemSearchResponse Try service.Timeout = 5000 response = service.ItemSearch(search) Catch End Try If IsNothing(response) Then Return Nothing End If Return response.Items(0).Item End Function ''' ''' The Amazon Author property represents a list of authors. ''' Therefore, we create a comma separated list ''' Public Shared Function FormatAuthor(ByVal Authors As String()) _ As String If Not IsNothing(Authors) Then Return String.Join(", ", Authors) Else Return "Not Listed" End If End Function ''' ''' Formats Amazon ListPrice into US currency ''' Public Shared Function FormatPrice(ByVal Price As String) As String If Not IsNothing(Price) Then Return "$" & Price.Insert(Price.Length - 2, ".") Else Return "Not Listed" End If End Function ''' ''' Formats tooltip for the link to the book details ''' Public Shared Function _ FormatDetailsTooltip(ByVal Title As String) As String If Not IsNothing(Title) Then Return String.Format("Link to {0} details", Title) Else Return "Link to details" End If End Function ''' ''' If there is no book cover, we fall back to displaying our image ''' Public Shared Function FormatBookCover(ByVal Url As String) _ As String If Not IsNothing(Url) Then Return Url Else Return "Images/NoBookCover.gif" End If End Function End Class
該類中的兩個最重要的函數名為 GetBooksFromAmazon 和 SearchBooksFromAmazon。第一個函數從 Default.aspx 頁中調用,以便按照類別顯示書籍清單。第二個函數從 Search.aspx 頁中調用,以便使用戶能夠搜索書籍。
這兩個函數都使用名為 AmazonServices 的 Web 服務代理類。該代理類是通過依次選擇菜單選項 Web site、Add Web Reference 並且輸入 URL 創建的。這是用於訪問美國 Amazon 數據的正確的 URL。
Default.aspx 頁顯示書籍類別的列表,並且顯示所選類別的匹配書籍的列表(參見圖 14)。Default.aspx 頁包含在清單 11 中。
圖 14. 默認頁
清單 11. Default.aspx
<%@ Page Language="VB" MasterPageFile="~/SiteMaster.master" Title="Super Super Books" %>
該頁使用下列兩個 ASP.NET 控件來顯示書籍清單:Menu 控件和 GridView 控件。Menu 控件用來顯示書籍類別的列表,而 GridView 控件用來顯示書籍列表。
GridView 控件被綁定到 ObjectDataSource 控件。ObjectDataSource 控件繼而調用 Amazon 類中的 GetBooks() 方法來檢索書籍列表。
在生成 XHTML 頁時,目標之一是將文檔的結構與其表示形式截然分開。為了達到這一目標,不能在 Default.aspx 頁中的任何 ASP.NET 控件上設置格式屬性。頁格式設置被封裝在通過 ASP.NET 主題與該頁相關聯的外部樣式表中。
ASP.NET 2.0 主題使您可以更容易地遵循 Web 標准,因為它們將所有表示內容與頁分開。示例站點包含一個名為 SiteTheme 的主題,該主題包含單個樣式表。該主題自動使用 Web.Config 文件中的下列配置設置與每個頁相關聯。
您應該注意到,HTML 表沒有用來創建頁布局。盡管 XHTML 標准和可訪問性標准都沒有禁止您使用表來創建頁布局,但這兩個標准都建議您避免這樣做。在示例站點中,頁布局完全是由外部樣式表確定的。頁本身由兩個 元素劃分為兩列。外部樣式表包含確定這兩個 元素位置的規則。
最後,示例站點在提供頁時使用內容協商。當使用能夠理解 application/xhtml+xml MIME 類型的浏覽器從 Web 站點請求頁時,將以 MIME 類型提供該頁;否則,將以 text/html 類型提供該頁。
內容協商是用 Global.asax 文件中的以下事件處理程序完成的。
Sub Application_PreSendRequestHeaders(ByVal s As Object, _ ByVal e As EventArgs) If Array.IndexOf(Request.AcceptTypes, _ "application/xhtml+xml") > Then ResponseContentType = application/xhtml+xml End If End Sub
當無法提供 JavaScript 的文本等效內容時WCAG 和 節可訪問性准則都禁用客戶端 JavaScript為了滿足這些准則Defaultaspx 頁不依賴於客戶端 JavaScript即使您在浏覽器中關閉 JavaScript該頁仍然能夠正常工作
為了滿足該要求在實現菜單時必須完成額外的工作默認情況下ASPNET Menu控件為每個菜單項呈現 JavaScript 以處理客戶端單擊事件但是當為菜單項提供了 NavigateUrl 屬性時該菜單項將不再使用 JavaScript
在示例站點中為每個菜單項提供了一個指回到 Defaultaspx 頁的 NavigateUrl 屬性當您單擊菜單項時將重新加載 Defaultaspx 頁Page_Load 事件處理程序用來檢測單擊了哪個菜單項而且該子例程用當前菜單選擇更新菜單
使用 Menu 控件的好處是Menu 控件自動生成跳過導航鏈接如果使用 Tab 鍵浏覽 Defaultaspx 頁中的每個元素會注意到(觀察浏覽器的狀態欄)有一個跳過菜單內容的隱藏鏈接Menu 控件使您能夠自動滿足 WCAG 和 節准則該准則要求您提供相應的方法以跳過重復性的導航鏈接
搜索頁包含一個表單使 Web 站點的用戶能夠通過提供書籍作者書名書籍關鍵字或者通過提供復雜查詢來搜索書籍(參見圖 )查詢的結果顯示在 GridView 控件中Searchaspx 頁包含在清單 中
圖 搜索頁
清單 Searchaspx
<%@ Page Language="VB" MasterPageFile="~/SiteMaster.master" Title="Search Books" %>
就像默認頁一樣搜索頁不包含任何表示性元素或屬性搜索頁的樣式和布局完全封裝在通過 ASPNET 主題與該頁相關聯的外部樣式表中
同樣像默認頁一樣搜索頁使用內容協商如果有人用能夠識別 application/xhtml+xml MIME 類型的浏覽器請求搜索頁則將以該 MIME 類型提供該頁否則將以 text/html 類型提供該頁
搜索頁包含一個表單或者更准確地說該頁包含被劃分為兩個子表單的單個表單它包含一個Quick Search表單和一個Power Search表單
請注意該表單用 HTML
而且請注意每個表單字段都與其標簽顯式關聯每個 ASPNET 控件都包含一個指向其相應表單字段的 AssociatedControlID 屬性標簽和字段之間的這些顯式關聯可以幫助屏幕閱讀器的用戶確定特定表單字段的用途
最後請注意每個 Label 控件都分配了一個訪問鍵訪問鍵使您無需使用鼠標就能夠方便地浏覽表單字段例如如果按 ALT+A則可以輸入作者的姓名如果隨後按 ALT+S則會提交Quick Search表單並且在 GridView 中顯示結果換句話說無需觸摸鼠標即可方便地執行搜索
如果按 ALT 鍵則會自動顯示訪問鍵(參見圖 )這通過 JavaScript 實現請注意在每個表單字段後面都會出現一個 標記例如Title 搜索字段是通過以下代碼實現的
access key is t
當按 ALT 鍵時將執行客戶端 JavaScript並且顯示 標記的內容
圖 搜索表單訪問鍵
您可能為該功能感到擔心因為按照可訪問性准則當 JavaScript 和樣式表關閉時該頁必須能夠繼續工作(WCAG 准則 )幸運的是當 JavaScript 和樣式表都被禁用時該頁確實能夠正常工作在這種情況下 標記的內容不再隱藏並且總是顯示訪問鍵(參見圖 )
圖 搜索表單適度降格
示例 Web 站點在幕後使用一個名為 SiteMastermaster 的 ASPNET 母版頁母版頁使您能夠在 Web 站點的多個頁中包含相同的內容並創建相同的布局母版頁通過 WebConfig 文件中的以下配置設置與示例 Web 站點中的每個頁相關聯
母版頁的內容包含在清單 中
清單 SiteMastermaster
<%@ Master Language=VB %> //WC//DTD XHTML Strict//EN strictdtd> >
利用母版頁可以方便地為 Web 站點中的所有頁提供正確的 DOCTYPESiteMastermaster 頁包含 XHTML Strict DOCTYPE在母版頁中指定 DOCTYPE 的好處是如果您將來需要更改 Web 站點中所有頁的 DOCTYPE那麼只需在一個位置更改它例如在不久之後的某一天您可能希望遷移到 XHTML Web 站點並修改 DOCTYPE 以反映所做的更改
母版頁還包含一系列一致性標識語它們出現在示例 Web 站點中每一頁的頁腳一致性標識語通告人們該 Web 站點符合 XHTMLCSS 和 WCAG Web 標准(參見圖 )
圖 一致性標識語
示例 Web 站點中每一頁的頂部都包含一個鏈接可以使用該鏈接切換用於顯示相應頁的樣式表每一頁都可以用下列兩個版本之一進行顯示普通文本版本和大型文本版本在選擇大型文本版本以後Web 站點中所有文本的大小都會有所增加以使可讀性更強(參見圖 )
圖 大型文本大小
用戶只需要執行該選擇一次如果某個用戶選擇 Web 站點的大型文本版本那麼該首選項會被自動記錄下來並且每當該用戶返回該 Web 站點時都會使用它該功能是通過利用 ASPNET 框架的另一項新功能實現的配置文件配置文件使您能夠存儲用戶在多次訪問 Web 站點時的設置
配置文件在 WebConfig 文件中定義
該配置文件定義一個名為 AccessibleStyleSheet 的布爾型屬性在 WebConfig 文件中定義該屬性以後就可以在任何 ASPNET 頁中通過由 Page 類公開的 Profile 屬性來讀取或設置該屬性例如要將 AccessibleStyleSheet 屬性設置為值 True並且顯示該 Web 站點的大型文本版本可以編寫以下代碼
ProfileAccessibleStyleSheet = true
母版頁包含用於選擇 Web 站點的普通文本或大型文本版本的所有邏輯HyperLink 控件用於使 Web 站點訪問者能夠執行該選擇在單擊 HyperLink 以後Page_Load 事件處理程序檢測用戶的選擇並設置 AccessibleStyleSheet Profile 屬性
如果使用 LinkButton 控件(而不是 HyperLink 控件)那麼這裡的代碼會更加簡單但是可訪問性准則再一次禁止我們這樣做因為 LinkButton 控件依賴客戶端 JavaScript
在選擇大型文本版本以後將向該頁中添加對附加樣式表的引用該樣式表包含單個規則
body { fontsize: xlarge; }
該規則將正文字體大小設置為值 xlarge因為主樣式表(包含在 SiteTheme 文件夾中)中指定的所有字體都使用相對大小所以修改正文元素的字體大小會自動增加 Web 站點中所有元素的字體大小
Web 標准是一個好東西通過遵循 Web 標准您能夠以最少的工作讓最廣大的受眾訪問您的 Web 站點您的 Web 站點將與更多的浏覽器兼容並且它們更有可能在將來繼續正常工作
ASPNET 框架旨在使您能夠輕松地生成滿足 Web 標准的 Web 站點該框架使您能夠輕松地生成 XHTML Web 站點在 ASPNET 框架中默認情況下所有 ASPNET 控件都呈現 XHTML 元素和屬性而且Visual Studio NET 和 Visual Web Developer 允許您在生成頁的過程中自動針對 XHTML 標准驗證這些頁的有效性
通過 ASPNET 框架還可以更容易地生成可被殘疾人士訪問的 Web 站點ASPNET 框架中的控件包含大量在設計時考慮了可訪問性的新屬性例如每個呈現圖像的 ASPNET 控件都使您能夠呈現圖像的替換文本此外所有新導航控件都包含跳過導航鏈接以使殘疾人士可以更容易地浏覽 Web 站點