到目前为止,我们只是关注了ASP.NET在开发“标准”网页和Web应用方面的特性,所谓“标准”网页和Web应用是指能为浏览器生成标准的HTML输出。实际上,ASP.NET自动利用了现代浏览器的一些特性。例如,前几章提到过,ASP.NET会生成客户端JavaScript代码来实现某些链接和交互式页面内容所需的回送机制。
不过,我们还没有考虑发送给客户的具体HTML和其他内容,而认为ASP.NET生成的内容适用于所有类型的浏览器和所有访问者。遗憾的是,事实并非如此。在大多数应用中,必须从两个方面考虑所生成的输出是否适用,一方面是用户浏览器的技术功能,另一方面是一些用户上网时遇到的限制。
这一章介绍的技术能使你的网站更适合于所有类型的客户。主要包括以下问题:
q 检测浏览器的功能,并提供替代内容。
q 指定额外信息,使页面更易于使用。
q 增加有关特性来支持残疾用户和专用用户代理。
q 构建适用于小屏幕和移动设备的页面。
q 构建支持模块化和多种语言的页面。
实际上,前两个问题相当重要,因为这能为所有用户提供帮助。不论你面向什么用户,构建所有网站时都应当考虑这两个问题。
14.1 页面验证、浏览器功能和替代内容
利用ASP.NET构建网站相当容易,可以使用Visual Studio之类的IDE来构建,然后只需在你最喜欢的浏览器中测试。这种方法可以说是“屡试不爽”。实际上,即使有内置的ASP.NET Web服务器以及默认浏览器(IE)提供的页面自动启动特性,这种方法也并未因此有多大的改变。不过,这种技术只适于构建面向特定浏览器的网站。如果访问者使用其他浏览器或专用用户代理,则可能无法访问采用这种方法构建的网站。
不错,通常使用的Web浏览器无非那么几种。在写这本书时,用户很可能通过IE、Mozilla Firefox、某种Netscape浏览器以及Avant和Opera等其他浏览器来访问你的页面。所有这些浏览器都支持ASP.NET所需的特性,如cookie(为ASP.NET会话提供支持)、客户端脚本(用于链接按钮、自动回送、验证等),以及标准HTML元素和CSS样式集。
最好的办法是在你的测试系统上尽可能多地安装这些浏览器(或者运行虚拟机),然后在所有这些浏览器中测试你的页面。这样做可以很快发现一些问题,如果你想全面支持所有类型浏览器,就必须解决这些问题。还要记住,大多数浏览器可以在不同的操作系统上使用。用户可能在Unix或Linux上运行浏览器,也可能在一个某版本MAC-OS的苹果机上运行浏览器。尽管浏览器制造商尽力在不同操作系统上为浏览器提供相同的外观和同样的行为,但是这个目标不是总能达到。所显示的输出可能会有很大差异,所以还要争取在这些不同的环境中测试你的页面。如果做不到,可以向非Microsoft环境的用户索要反馈甚至切屏图。
可以从以下地址下载到最新的浏览器。
q Internet Explorer: http://www.microsoft.com/windows/ie/。
q Mozilla Firefox: http://www.mozilla.org/。
q Netscape: http://browser.netscape.com/。
q Avant: http://www.avantbrowser.com/。
q Opera: http://opera.com/。
14.1.1 验证页面内容
默认情况下,Visual Studio会检查页面的内容,并在源代码视图中显示存在的问题,在有问题的元素和属性下加下划线。因此可以很容易地根据一组HTML和XHTML模式验证内容。可以使用“格式化”(Formatting)工具条中的下拉列表选择需要哪种级别的兼容性。如图14-1所示,尽管某些内容对于当前的HTML 4.0和XHTML模式来说是非法的,但如果选择面向IE和Netscape Navigator 3的一种传统格式(如HTML 3.2)时,这些内容也能接受,源代码中没有下划线警告。

图14-1 根据传统模式验证HTML内容
不过,如果选择默认模式(XHTML 1.0 Transitional),HTML源代码中则会出现下划线警告(参见图14-2)。这个模式要求更严格的元素和属性结构,更遵循XHTML标准,不过还是允许使用某些HTML 4属性。

图14-2 根据默认XHTML Transitional模式验证HTML内容
如果把鼠标停留在有下划线的元素和属性上,Visual Studio会显示验证失败的详细信息,以及修正这个问题的有用的提示。例如,在XHTML中,<form>元素不应有name属性(如图14-3所示)。不过,这个错误会标志为一个警告而不是错误,下划线是紫色而不是红色(由于这是一个黑白图片,所以在此看不出这一点)。如果选择XHTML 1.1 Strict模式,Visual Studio会将其标志为一个错误。

图14-3 警告<form>元素不应有name属性
Visual Studio将本例中的其他问题标志为错误(有红色下划线),必须修正这些问题,页面才能与所选的模式兼容。在图14-4中,可以看到,对应一个水平线的单标记元素必须使用正确的空元素语法才认为是合法的,即包括一个空格和一个结束斜线(如<hr />)。这一点同样适用于它上面的<input>元素以及其他元素(如<br />)。

图14-4 错误,指示空元素中缺少结束斜线
1. 其他验证服务
Visual Studio编辑器可以很好地帮助你编写合法的HTML。例如,它会自动为空元素增加结束斜线,并要求在所有ASP.NET Web控件声明中使用结束斜线。通过提供弹出的合法选择器列表names并检查整个结构,Visual Studio编辑器还可以对其他文档(如CSS样式表)完成一些验证。不过,如果愿意,也可以使用一些外部验证服务来检查页面和样式表。
W3C提供了CSS和HTML验证服务,在网上搜一下会找到很多这样的服务。W3C CSS样式表验证服务见http://jigsaw.w3.org/css-validator/,W3C HTML验证服务见http://validator.w3.org/。
2. XHTML兼容性
ASP.NET允许创建与XHTML规范兼容的页面。尽管这本书不涉及XHTML标准的内容,但要知道,如果为页面指定XHTML兼容格式,不仅会影响生成到浏览器的输出,还会影响页面模板的输出。这里的主要问题包括:
q 客户脚本标记生成时没有language属性而有type属性。
q 隐藏字段(如viewstate使用的字段)生成到一个div元素中,其display属性设置为none。
q 输入元素生成到一个block元素中,因此在form元素中直接有一个div元素。
q 只有当BrowserCapabilities类的W3CDomVersion.MajorVersion属性大于0时才生成表单的name属性。
q 特殊字符(如&、’和尖括号)在控件生成的属性和查询串中都要编码。
不过,要注意,ASP.NET 中使用的一些控件并不总能创建严格遵循XHTML 1.1的输出。这是因为,超链接中使用的target属性在XHTML 1.1中是非法的。有些控件可以设置target属性,如Hyperlink、BulletedList、ImageMap和TreeView,不过只要不设置导致生成target的Target属性,就能得到与XHTML 1.1兼容的输出。
14.1.2 检测浏览器功能
如果想构建内容可变的页面,即取决于每个访问者所用浏览器的类型以某种定制方式改变页面的内容,必须能够在代码中检测浏览器的类型或其功能。ASP.NET 会自动检测浏览器类型,并尽可能调整输出以适应当前浏览器。例如,对于现代浏览器,Panel控件会生成为一个<div>元素,但是对于不支持<div>元素的较早浏览器,则生成为一个单行单列的表。
在你的页面中可以插入这种浏览器检测机制,或调整ASP.NET 的行为。在9.2.1节中,我们已经介绍了如何使用Page类的ClientTarget属性来指定行为,覆盖默认的浏览器自动检测过程。
1. 浏览器定义
要检测浏览器类型,ASP.NET 会把客户请求的HTTP首部中发送给服务器的USER-AGENT值与ASP.NET配置主文件夹下Browsers子文件夹中存储的一组浏览器定义文件匹配。默认路径如下:
\%WINDIR%\Microsoft.NET\Framework\v2.0.50727\CONFIG\Browsers\
浏览器定义文件的一般格式如代码清单14-1所示。
代码清单14-1 浏览器定义文件的一般格式
<browsers>
<browser id="device-name" parentID="family-type-to-inherit-from">
<identification>
<!-- Specifies how to identify this browser -->
</identification>
<capture>
<!-- Specifies additional HTTP header values to match -->
</capture>
<capabilities>
<!-- Specifies capabilities values to set, for example -->
<capability name="cookies" value="true" />
</capabilities>
<controlAdapters>
<!-- Specifies control adapters to use for this browser -->
</controlAdapters>
</browser>
</browsers>
有一个名为Default.browser的文件,其中定义了基浏览器类型的默认值和功能,还有一些文件则定义某些常用浏览器特定的值(如Internet Explorer和Mozilla)。每个定义中的Id和parentId属性将这些定义相互链接,这样就为各个浏览器相关的继承设置和版本特定设置建立了一个层次体系。
安装框架时,ASP.NET将所有这些文件编译为一个精简表示。如果更新一个定义,可以运行随框架安装的aspnet_regbrowsers.exe实用工具手动地将其重新编译。这就带来一种可能性,实现浏览器定义的自动更新会容易得多,甚至将来会成为框架更新过程的一部分。
还可以把浏览器定义文件放在应用根文件夹中一个名为App_Browsers的特殊文件夹下。另外,web.config文件<browserCaps>元素中的所有浏览器定义也能被识别,并合并到框架最终使用的浏览器定义集中。不过,ASP.NET会忽略machine.config文件中的所有浏览器定义。
2. BrowserCapabilities类
尽管ASP.NET中设备检测系统的实现和操作是自动的,不过也可以在代码中用它来查找有关当前浏览器的信息,必要时还可以修改页面的行为。当前Request实例(HttpRequest)通过其Browser属性提供了HttpBrowserCapabilities类的一个实例。这说明,可以编写代码查询浏览器功能属性。例如,以下代码会返回当前浏览器的浏览器名和主版本号:
String details = Request.Browser("Browser")
+ Request.Browser("MajorVersion");
HttpBrowserCapabilities类有上百个属性。其中一些与常用任务无关,不过大多数对于检测各种功能都很有用。例如,可以检测浏览器是否支持cookie、框架、颜色、声音、脚本等等。
关于HttpBrowserCapabilities类属性的完整列表见http://msdn2.microsoft.com/en-us/ library/system.web.httpbrowsercapabilities_members.aspx。
3. 浏览器特定的页面和网站,以及客户端代码支持
有一点要记住,HttpBrowserCapabilities类只是根据浏览器定义文件的内容来提供信息。这说明,对于用户可能在浏览器中打开和关闭(启用和禁用)的特性,并不总能得到正确的结果。
例如,用户可能禁用了VBScript和/或JavaScript客户端脚本,关闭了图像显示,或者禁用了cookie。如果页面中依赖于这些特性,就必须自行实现更得力的检测方法,或者使用一种替代浏览器检测机制。也可以使用第三方工具来完成浏览器检测。这方面的一个很好的例子是BrowserHawk,它会自动更新自己的浏览器定义文件,对新浏览器类型和新版本提供准确的检测。它还会检测用户是否禁用了一些常用的浏览器特性。
有关BrowserHawk的信息可以访问http://www.cyscape.com/products/bhawk/。
还可以自己创建代码来检测当前启用的功能,如cookie和客户端脚本。这种代码通常依赖于发送给客户的初始页面(通常是Default.aspx),其中包含一个<meta>重定向指令以及一个客户端脚本重定向语句。代码清单14-2显示了一个页面的<head>元素,其中包含一个<meta>重定向指令,指向名为no-script.aspx的页面,这会导致浏览器在3秒之后加载该页面。在它下面是包含一个函数的客户端脚本段,这个函数将浏览器重定向到网站的主页。最后,开始<body>标记包含一个onload属性,这会导致Default.aspx加载结束时执行以上JavaScript函数,并打开网站主页:
<body onload="jumpScriptEnabled()">
代码清单14-2 检测是否启用客户端JavaScript
<meta http-equiv="refresh" content="3;url=no-script.aspx" />
<script language="JavaScript">
<!--
function jumpScriptEnabled() {
// jump to page using client-side JavaScript - if jump not executed
// then client does not have scripting available or it is disabled
window.location.href = 'mainmenu.aspx';
}
//-->
</script>
如果用户禁用了客户端脚本,浏览器则会加载no-script.aspx页面,这可能显示一个消息,指示必须启用客户端脚本你的网站才能正确工作。或者,如果你的网站有另外一个不需要客户端脚本就能工作的版本,可以将其URL放在<meta>指令中,将用户重定向到该网站。另外一种办法是在用户的会话中存储一个值,指示客户端脚本不可用,然后在网站页面中使用这个值来提供不依赖客户端脚本的替代特性。
在页面中包括一个<noscript>元素也是个不错的办法。大多数浏览器都允许用户禁用<meta>重定向,有些代理服务器也会禁用<meta>重定向。在这种情况下,客户端脚本不可用或禁用时,浏览器会自动地显示<noscript>元素的内容,可以利用这个特性提供信息和其他网站的链接。
4. 检测cookie支持
大多数服务器端编程环境都依赖于cookie维护各个用户的会话。如果没有cookie,ASP.NET框架的一些特性和一些服务器控件将无法正常工作。另外,如果服务器端代码在用户会话中存储了数据,就会依赖于客户浏览器中的cookie支持,除非利用了ASP.NET中无cookie会话支持特性。幸运的是,现代浏览器中提供了一些特性,允许用户在不想要cookie的情况下(如来自另一个网站的第三方cookie)禁用cookie支持,而为当前网站保留cookie。
不过,可以很容易地检测当前浏览器是否支持cookie,为此只需向Default.aspx页面增加一些简单的代码。这个代码所做的只是设置一个会话变量的值,然后在后续的页面中可以查找这个值。如果这个值不可用,则说明用户是通过另一个页面进入网站的,或者用户在其浏览器中没有启用cookie。代码清单14-3 显示了一个简单的例子,它将用户重定向到一个请求启用cookie的页面,其中还包含指向网站主页的一个链接。或者,也可以重定向到使用无cookie会话的另一个版本的网站。
代码清单14-3 检测是否启用cookie
In Default.aspx:
<script runat="server">
Sub Page_Load()
' put value in session to check for cookie/session
' support by looking for it again in the next page
Session("SessionCheck") = "OK"
End Sub
</script>
In your main site menu page:
<script runat="server">
Sub Page_Load()
' look for "sessions-enabled" cookie
If CType(Session("SessionCheck"), String) > "OK" Then
Response.Redirect("no-sessions.aspx")
Response.End()
End If
End Sub
</script>
ASP.NET中的无cookie会话特性使用URL-munging(在每个页面请求上自动向UR4L插入会话ID)来跟踪各个用户,并维护其会话。为了启用无cookie会话支持,需要使用web.config文件<system.web>中的<sessionState>元素指定ASP.NET应当使用无cookie会话:
<sessionState cookieless="true" />
有关的更多详细信息,见11.1.3节。
14.1.3 CSS支持的特异性
一般,所有主流浏览器的较新版本都支持ASP.NET 所需的所有特性,不过有些情况下不同浏览器之间的CSS支持有所不同。例如,IE和Mozilla对于CSS支持就与W3C建议有点小差异,而对于动态元素定位等问题,Opera与这两个浏览器的表现又不相同。
如果一个浏览器的行为与标准或建议有所不同,这种差别通常称为“特异性”(quirk)。可以在页面的开始处使用一个适当的DOCTYPE声明来改变IE 6.0及以后版本、Opera 7.0及以后版本以及Mozilla的行为。这些浏览器会考虑服务器在HTTP首部中向浏览器发送的MIME类型(如"text/html" 或"text/xml"),还会考虑DOCTYPE元素中的文档类型声明(DTD)和URL。
如果你的页面设计或布局依赖于较老浏览器提供的一个或多个特异行为,可以忽略DOCTYPE声明来指出这一点,或者使用DOCTYPE元素,并指定4.0以前的HTML版本或HTML 4.0 Transitional版本(后一种方案更好):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
要在现代浏览器中启用与标准兼容的模式,可以使用以下的某个DOCTYPE元素:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Strict//EN">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
如果你的页面是XHTML兼容的,可以使用适当的DOCTYPE指示。这会在所有现代浏览器中启用标准兼容模式:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN"
"xhtml-basic10.dtd">
默认情况下,Visual Studio会向指定了部分XHTML兼容的页面自动增加一个DOCTYPE元素,如下所示:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
有关不同模式的更多信息,各模式在各个浏览器中的影响,以及可以采用哪些方法启用各个模式,请见
http://msdn.microsoft.com/library/en-us/dnie60/html/cssenhancements.asp
http://www.mozilla.org/docs/web-developer/quirks/doctypes.html
http://www.opera.com/docs/specs/doctype/
还有一个有用的网站QuirksMode,其中提供了一些特性对照表,显示了主流浏览器中不同模式的差异,请见:
http://www.quirksmode.org/css/quirksmode.html







