document.enableStyleSheetsForSet() 的兼容

本文介绍如何通过脚本在不同样式表集之间进行切换,利用CSSOM规范中的enableStyleSheetsForSet方法实现样式表的动态调整,并提供了一种适用于WebKit浏览器的兼容性解决方案。
可能有不少同学已经了解 alternate stylesheet ,不过实际上author样式表可以被设定为三类:

1. persistent style sheet:总是应用的样式表
2. preferred style sheet:默认应用的样式表
3. alternate style sheet:其他可选的样式表

我们平时通常写的样式表都是第一类,即persistent style sheet。
第二类样式表就是有title属性的样式表,比如:

<link rel="stylesheet" [color=red]title="人文主义"[/color] href="...">

第三类则是这样:

<link rel="[color=red]alternate[/color] stylesheet" [color=red]title="古典"[/color] href="...">
<link rel="[color=red]alternate[/color] stylesheet" [color=red]title="Geek风"[/color] href="...">

一些浏览器(FF和Opera)可以通过菜单切换到alternate stylesheet。Safari可能也有,Chrome默认没有,但是可安装extension。

注意,切换是依据title属性互斥的,相同title的样式表称为一个样式表集(style sheet set)。比如切换到“古典”之后,原先perferred的“人文主义”就被disable了。但是persistent style sheet仍然是起作用的。

问题是如何通过脚本来切换样式表集?CSSOM规范引入了一个新的API来达成这个目的:

[Supplemental] interface Document {
readonly attribute StyleSheetList styleSheets;
...
void [color=red]enableStyleSheetsForSet[/color](DOMString? name);
};

所以简单的:
document.enableStyleSheetsForSet('Geek风')
就可以切换到“Geek风”样式表集。

FF4已经支持该方法,不过较早的版本以及使用WebKit引擎的Safari、Chrome等怎么办呢?

一种想法是遍历document.styleSheets然后根据title来设定disabled值,因为标准所规定的行为就是如此。代码如下:


// 以下代码在当前WebKit下不能work!
document.enableStyleSheetsForSet = function(name) {
if (name != null) for (var i = 0, n = this.styleSheets.length; i < n; i++) {
var sheet = this.styleSheets[i]
if (sheet.title) sheet.disabled = !(sheet.title == name)
}
}


不幸的是,上述看似合理的代码在WebKit下不能work,因为WebKit的document.styleSheets集合里根本不包括所有alternate style sheet。

那么我们是否能自行取样式集合呢?比如通过 document.querySelectorAll("style, link[rel~='stylesheet']") 。实际也是不行的,因为WebKit根本就忽略了那些alternate样式表,即使你直接设置那些样式表的 disabled = false ,也不能启用样式表(实际上它们的disabled值原本就是false)。

难道除了抱怨WebKit在这个方面不合标准之外,我们就没辙了吗?


在放弃之前,我们应该把spec翻出来再好好读读。

直接上代码:

if (!document.enableStyleSheetsForSet) document.enableStyleSheetsForSet = function(name) {
if (name != null) {
var meta = document.querySelector('meta[http-equiv="default-style"]')
if (!meta) {
meta = document.createElement('meta')
meta.httpEquiv = 'default-style'
document.head.appendChild(meta)
}
meta.content = name
}
}


非常简单的实现,一切皆源自于default-style这个被人遗忘的特性。以上代码在Chrome 10下测试通过。


PS. 在上述代码里,你可能注意到了“document.head”,这也是HTML5新增的属性,但是那些更早的浏览器并没有这个属性。类似的问题还有querySelector方法。这些就作为浏览器兼容性的练习题留给读者了。
在 JavaScript 中,获取页面的滚动距离是常见的需求,尤其是在需要根据滚动位置进行页面交互或动画效果时。获取滚动距离的方式在不同浏览器中存在兼容性差异,主要体现在 `document.body.scrollTop` 和 `document.documentElement.scrollTop` 的使用上。 ### 获取页面滚动距离的兼容性差异 在早期浏览器中,尤其是 Internet Explorer(IE)的不同版本中,`document.body.scrollTop` 和 `document.documentElement.scrollTop` 的行为有所不同。这种差异主要源于文档模式(即是否声明了 `<!DOCTYPE html>`)对滚动属性的影响: - **当文档声明了 `<!DOCTYPE html>`**,在 IE9 及以上版本中,可以通过 `document.documentElement.scrollTop` 获取页面滚动距离。 - **当文档未声明 `<!DOCTYPE html>`**,在 IE9 及以下版本中,可以通过 `document.body.scrollTop` 获取页面滚动距离。 - **在现代浏览器(如 Chrome、Firefox、Edge)中**,通常支持 `window.pageXOffset` 和 `window.pageYOffset`,这是获取滚动距离的标准化方法,且不依赖于文档模式[^1]。 ### 推荐的兼容性写法 为了确保代码在不同浏览器和文档模式下都能正确获取滚动距离,可以采用以下兼容性写法: ```javascript var x = window.pageXOffset || document.documentElement.scrollTop || document.body.scrollTop; ``` 此写法优先使用 `window.pageXOffset`,如果不可用,则尝试 `document.documentElement.scrollTop`,最后回退到 `document.body.scrollTop`。这种写法覆盖了大多数浏览器和文档模式下的兼容性问题。 ### 函数封装以提高性能 为了进一步优化性能,可以将滚动距离的获取逻辑封装为一个函数,首次调用时根据浏览器支持情况动态重写函数,从而避免重复判断: ```javascript function getScrollOffset() { if (window.pageXOffset) { getScrollOffset = function() { return { top: window.pageXOffset, left: window.pageYOffset }; }; } else { getScrollOffset = function() { return { top: document.documentElement.scrollTop + document.body.scrollTop, left: document.documentElement.scrollLeft + document.body.scrollLeft }; }; } return getScrollOffset(); } ``` 通过这种方式,函数在首次调用时会根据浏览器的支持情况重新定义,后续调用时直接使用最合适的实现,从而提高执行效率。 ### 总结 在实际开发中,推荐优先使用 `window.pageXOffset` 和 `window.pageYOffset` 获取滚动距离。如果需要兼容老旧的浏览器,尤其是 IE9 及以下版本,可以通过 `document.documentElement.scrollTop` 和 `document.body.scrollTop` 进行回退处理。通过合理的兼容性写法和函数封装,可以确保代码在不同环境下稳定运行。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值