jQuery 虽然在前端框架层出不穷的今天使用率有所下降,但它的源码仍然是一份优秀的兼容性处理教材。support 模块集中管理浏览器能力检测,其中 support.transition 用来判断浏览器是否支持 CSS3 过渡。这个判断逻辑并不是简单读取一个标准属性就能完成,因为早期浏览器对 transition 的支持普遍采用厂商前缀,而且过渡结束事件名称也不一致。下面将结合简化源码,分析检测原理和私有前缀处理方式。

一、为什么CSS3过渡检测需要处理私有前缀
CSS 过渡是让元素属性在一段时间内平滑变化的能力。标准写法是直接在样式表中声明 transition 属性。但在标准规范尚未稳定时,浏览器厂商为了提前支持该特性,采用了带前缀的实现:WebKit 内核使用 -webkit-transition,Firefox 早期使用 -moz-transition,Opera 使用 -o-transition,而 IE10 以及后来的现代浏览器则直接支持标准 transition。对于运行在旧版浏览器上的页面,如果只检测标准属性是否存在,会误判为不支持过渡,从而放弃动画增强。
除了属性名不同,过渡结束事件也存在差异。标准事件名为 transitionend,但 WebKit 内核最初使用 webkitTransitionEnd,Opera 使用 oTransitionEnd,部分旧版 WebKit 还会触发 otransitionend 或 webkitTransitionEnd。因此完整的过渡能力检测不仅要判断样式属性是否可写,还要为后续绑定回调提供一个统一的事件名。jQuery 的 support.transition 检测恰好同时解决这两个问题,把这些差异封装在特性检测内部。
二、jQuery源码中support.transition的实现拆解
下面是 jQuery 1.x 系列中 support.transition 检测逻辑的简化版本。它首先创建一个 div 元素作为测试载体,然后准备一个候选属性名与过渡结束事件的映射对象。候选属性名采用驼峰形式,因为 JavaScript 中通过 style 对象访问 CSS 属性时,连字符会转换成驼峰写法。
// 简化自 jQuery 源码
support.transition = (function() {
var div = document.createElement("div");
var transitionEnd = "transitionend";
var names = {
WebkitTransition: "webkitTransitionEnd",
MozTransition: "transitionend",
OTransition: "oTransitionEnd otransitionend",
transition: "transitionend"
};
for (var name in names) {
if (div.style[name] !== undefined) {
return {
transition: true,
transitionEnd: names[name]
};
}
}
return {
transition: false,
transitionEnd: transitionEnd
};
})();
在这个循环中,div.style[name] 是核心检测手段。对于不支持的 CSS 属性,style 对象上对应的属性值通常是 undefined;如果浏览器认识该属性,无论是否设置过值,访问它都会返回一个字符串或空字符串。因此用 !== undefined 来判断属性是否存在,比使用 in 运算符更加直观。一旦某个候选属性命中,循环立即中断,并把对应的过渡结束事件赋给 support.transitionEnd,同时标记 support.transition 为 true。
需要注意的是,jQuery 并没有把检测结果直接暴露为一个布尔值,而是放在了 jQuery.support 对象上。上层代码可以通过 jQuery.support.transition 来读取布尔值,而过渡结束事件名则可以用于后续动画模块。这种集中式管理让浏览器差异不会散落在业务代码中。
三、各浏览器私有前缀的检测顺序与兼容性细节
候选属性对象的遍历顺序会直接影响检测结果。在 jQuery 的简化实现中,WebkitTransition 排在首位,随后是 MozTransition、OTransition,最后才是标准 transition。之所以把标准属性放在后面,是因为某些旧版 WebKit 引擎可能同时支持带前缀和标准属性,但它们的过渡事件名称可能不一致。优先命中带前缀属性可以获得更准确的事件名,避免错误地使用标准事件名导致回调不触发。
从浏览器实现角度看,Chrome 和 Safari 很长时间内都支持 -webkit-transition,因此在 style 对象中表现为 WebkitTransition。Firefox 早期虽然支持 -moz-transition,但它的过渡结束事件名与标准一致,都是 transitionend,所以映射值保持了 transitionend。Opera 的 -o-transition 对应的结束事件有些特殊,既有 oTransitionEnd,也有全小写的 otransitionend,因此映射字符串中同时写入了两种形式,便于后续做多事件绑定。
IE10 是首个支持标准 transition 属性的 IE 版本,同时它也支持 msTransition 属性。jQuery 的检测对象中并未显式加入 msTransition,而是依赖标准 transition 命中。对于更老的 IE 浏览器,候选属性全部不可用,support.transition 会返回 false,此时开发者可以通过条件判断放弃过渡动画或使用 JavaScript 动画替代。
现代浏览器已经完全支持标准属性,检测逻辑会逐步命中最后的 transition 项。不过保留前缀检测仍然重要,因为一些封装库需要兼容旧版移动端 WebView,而这些环境很可能只识别带前缀的过渡属性。
四、在自定义组件中实现健壮的过渡检测
如果把 jQuery 的思路应用到自己的组件中,可以编写一个独立的工具函数,返回浏览器支持情况和推荐的过渡结束事件。下面的实现与 jQuery 源码结构类似,但更适合现代项目,同时补充了 msTransition 的检测。这样可以在不支持 CSS 过渡的浏览器中降级为即时状态切换。
function getTransitionSupport() {
var el = document.createElement("div");
var style = el.style;
var candidates = {
WebkitTransition: "webkitTransitionEnd",
MozTransition: "transitionend",
msTransition: "transitionend",
OTransition: "oTransitionEnd otransitionend",
transition: "transitionend"
};
for (var prop in candidates) {
if (style[prop] !== undefined) {
return {
supported: true,
property: prop,
eventName: candidates[prop]
};
}
}
return {
supported: false,
property: "",
eventName: ""
};
}
// 使用示例
var info = getTransitionSupport();
if (info.supported) {
element.addEventListener(info.eventName, function() {
console.log("过渡结束");
});
}
在实际使用过渡结束事件时,还需要注意两个问题。一是 transitionend 会在每个过渡属性结束时分别触发一次,如果元素同时过渡了多个属性,回调会被执行多次。可以通过 event.propertyName 判断是否是目标属性,或者使用计数器等业务逻辑进行去重。二是某些浏览器在元素隐藏或动画被中断时可能不触发 transitionend,因此健壮的做法是设置一个与过渡时长一致的 setTimeout 兜底,在超时后强制执行清理逻辑。
现代浏览器还提供了 CSS.supports 方法来检测属性支持,例如 CSS.supports('transition', 'all 1s')。但该方法无法返回具体的过渡结束事件名,因此仍然需要结合 style 对象遍历。jQuery 当年的特性检测思路在今天并不过时,只是需要根据新的浏览器环境适当调整候选属性列表。
jQuery源码transition检测私有前缀修改时间:2026-08-26 18:27:58