【续】抓个Firefox的小辫子,jQuery表示不背这黑锅,Chrome,Edge,IE8-11继续围观中
引子
昨天我发了一篇文章【抓个Firefox的小辫子,围观群众有:Chrome、Edge、IE8-11】,提到了一个Firefox很多版本都存在的问题,而相同的测试页面在Chrome、Edge、IE8-11下面一切正常。
在评论里面,网友 @Blackheart 的回复引起了我的注意:

我就按照网友提供的方法重新测试了一下:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
<style>
*, :after, :before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
</style>
</head>
<body>
<fieldset id="fieldset1" style="border:solid 1px red;width:500px;position:absolute;top:0;left:0;">
<legend>fieldset</legend>
</fieldset> <script> $(function () {
// $('#fieldset1').height(200);
document.getElementById("fieldset1").style.height = "200px";
alert(parseInt($('#fieldset1').height(), 10));
}); </script>
</body>
</html>
在Firefox下显示效果:

在Chrome下显示效果:

截图中提示 181px,而不是 200px,这是完全正确的:
- jQuery.height 函数是不包含padding、border和margin的
- 在box-sizing: border-box;规则下,通过style.height设置的值是包含padding和border的
这两者的差异体现在最终设置的fieldset的高度不同:
$('#fieldset1').height(200);

document.getElementById("fieldset1").style.height = "200px";
当然,这两种设置高度的差异不是我们本篇文章讨论的重点。但却是问题的关键所在,下面分析jQuery源代码时会用到这个知识。
问题好像真的消失了,有那么一刻,我差点就要将Firefox的问题丢给 jQuery 了,但事实果真如此嘛?
深入 jQuery 源代码
俗话说:不入虎穴,焉得虎子,我们就来调试一把 jQuery.height 函数。
虽然用了十来年的jQuery,但真正去调试 jQuery 代码却没有几次,毕竟 jQuery 的代码可谓是千锤百炼,吹毛求疵想找个BUG都难。
这次就没办法了,既然怀疑到这里只好入手了:
1. 入口函数

2. 首先进入 style 函数:

3. 进入 set 函数

此时如果我们来执行一下 augmentWidthOrHeight:

得到的是一个负值,通过前面对 jQuery.height 的介绍我们知道,jQuery.height(200)是不包含padding和border的,最终还是要通过 $('#fieldset1')[0].style.height 来设置,所以我们需要先计算 fieldset 上下的padding和border。
4. 进入 augmentWidthOrHeight 函数:

这个截图可以印证我们之前的设想,通过 jQuery.css 函数来获取 paddingTop,borderTopWidth,paddingBottom,borderBottomWidth 四个值。
5. 最后回到 style 函数:

此时 value 值已经是计算后的值了,其中包含用户要设置的 200px,以及上下padding和border 17.6px,总计 217.6px
下面通过 style[ name ] = value,将 217.6px 设置到 fieldset 节点:

此时,我们来仔细观察下三个变量,说白了,这句话的意思下面的代码是一模一样的:
document.getElementById("fieldset1").style.height = "217.6px";
那就奇怪了,既然 jQuery.height 最终也是调用的 style.height,为啥直接用 style.height 设置就没问题呢?
全面复盘
最初,我怀疑是 try-catch 搞的鬼,后来发现不是。按照 jQuery.height 的调用流程,我们自己动手来重现一下:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
<style>
*, :after, :before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
</style>
</head>
<body>
<fieldset id="fieldset1" style="border:solid 1px red;width:500px;position:absolute;top:0;left:0;">
<legend>fieldset</legend>
</fieldset> <script> $(function () { var elem = $('#fieldset1')[0]; var view = elem.ownerDocument.defaultView;
if (!view || !view.opener) {
view = window;
}
var styles = view.getComputedStyle(elem); var val = 0;
val -= jQuery.css(elem, "paddingTop", true, styles);
val -= jQuery.css(elem, "borderTopWidth", true, styles);
val -= jQuery.css(elem, "paddingBottom", true, styles);
val -= jQuery.css(elem, "borderBottomWidth", true, styles); elem.style.height = (200 - val) + "px"; alert(parseInt($('#fieldset1').height(), 10));
}); </script>
</body>
</html>
在Firefox下可以重现问题:

简化下代码:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
<style>
*, :after, :before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
</style>
</head>
<body>
<fieldset id="fieldset1" style="border:solid 1px red;width:500px;position:absolute;top:0;left:0;">
<legend>fieldset</legend>
</fieldset> <script> $(function () { var elem = $('#fieldset1')[0];
var styles = window.getComputedStyle(elem);
var val= jQuery.css(elem, "paddingTop", true, styles); elem.style.height = (200 - val) + "px"; alert(parseInt($('#fieldset1').height(), 10));
}); </script>
</body>
</html>
Firefox下问题依然存在,很明显是在 jQuery.css 中出现的问题,跟踪到 jQuery 的源代码:


说白了,也很简单。通过 styles.getPropertyValue(name) || styles[name] 来获取某个CSS样式的值。
下面,再次更新示例,去除 jQuery 的相关代码:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
<style>
*, :after, :before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
</style>
</head>
<body>
<fieldset id="fieldset1" style="border:solid 1px red;width:500px;position:absolute;top:0;left:0;">
<legend>fieldset</legend>
</fieldset> <script> $(function () { var elem = $('#fieldset1')[0];
var styles = window.getComputedStyle(elem);
var val = parseFloat(styles.getPropertyValue("paddingTop") || styles["paddingTop"]); elem.style.height = (200 - val) + "px"; alert(parseInt($('#fieldset1').height(), 10));
}); </script>
</body>
</html>
Firefox问题依然存在,而这里面我们设置 fieldset 的高度根本没用到 jQuery,只是调用了系统的 getCompotedStyle 方法等!!!
中间插播一个广告:
#######################################
# 9 年只做一件事
# 由三生石上亲自打造的 FineUI 控件库,现已支持 ASP.NET Core 2.0,跨平台 Windows、Mac、Linux 都能用!
# 在线示例:http://core.fineui.com/
########################################
广告结束,请继续....
上面还不是最简单,下面我们从页面中完全排除 jQuery ,3 行代码就能重现问题:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<style>
*, :after, :before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
</style>
</head>
<body>
<fieldset id="fieldset1" style="border:solid 1px red;width:500px;position:absolute;top:0;left:0;">
<legend>fieldset</legend>
</fieldset> <script> window.onload = function() {
var elem = document.getElementById('fieldset1'); window.getComputedStyle(elem)["paddingTop"]; elem.style.height = "200px";
}; </script>
</body>
</html>
在Chrome和Firefox下的显示效果对比(后面是Chrome,前面是Firefox):

小结
的的确确,这是 Firefox Quantum(v57) 以及很多老版本的BUG,和 jQuery 没有关系,jQuery只在做了该做的事情,碰巧遇到这个 Firefox 的BUG而已。
这个BUG在Firefox下重现需要满足如下几个条件:
- 设置CSS全局属性:box-sizing: border-box
- HTML标签为:fieldset(其他标签没问题,比如div就是正常的)
- fieldset绝对定位:position:absolute
在这 3 个条件下,调用JS代码 window.getComputedStyle(elem)["paddingTop"] 之后再设置 fieldset 标签的高度,页面上不会更新!
解决办法请看我的上一篇文章:【原创】抓个Firefox的小辫子,围观群众有:Chrome、Edge、IE8-11
点赞
喜欢三石的文章,你就给个推荐呗!
【续】抓个Firefox的小辫子,jQuery表示不背这黑锅,Chrome,Edge,IE8-11继续围观中的更多相关文章
- 【原创】抓个Firefox的小辫子,围观群众有:Chrome、Edge、IE8-11
前言 很多人都知道我们在做FineUI控件库,在这 9 年多的时间里,在和浏览器无数次的交往中,也发现了多个浏览器自身的BUG,并公开出来方便大家查阅: 分享IE7一个神奇的BUG(不是封闭标签的问题 ...
- (二)Fiddler抓取Firefox、Chrome浏览器上的https协议
Fiddler抓取Firefox.Chrome浏览器上的https协议 安装Fiddler后默认只抓取http协议,如果是https协议的话,浏览器就会提示"您的链接并不安全". ...
- fidder工具学习抓取Firefox包
fidder抓取Firefox的https请求 抓包之前需要设置fidder,我下面的截图是fidder4,打开fidder—>Tools—>Options如图: 选择https,勾选所有 ...
- JS 在页面上直接将json数据导出到excel,支持chrome,edge,IE10+,IE9,IE8,Safari,Firefox
JS 在页面上直接将json数据导出到excel,支持chrome,edge,IE10+,IE9,IE8,Safari,Firefox <html> <head> </h ...
- 针对firefox ie6 ie7 ie8的css样式中的line-height属性
针对firefox ie6 ie7 ie8的css样式中的line-height属性 以前我们大部分都是用!important来hack,对于ie6和firefox测试可以正常显示,但是ie7以上对! ...
- Jquery基本教程(背还是要背的)
Jquery入门学习 一.简介 1.Jquery是基于JavaScript的一种框架,兼容主流浏览器,提供了dom,animate(JQ+CSS),ajax; 2.Jquery2.0后版本不支持IE6 ...
- 使用Chrome快速实现数据的抓取(三)——JQuery
使用Chrome抓取页面一个非常方便的地方就是它可以执行JS,也就是说我们可以通过JS函数获取我们想要的数据.一个非常强大易用的库就是Jquery,本文就简单的介绍一下使用Chrome获取数据时Jqu ...
- 网页抓取解析,使用JQuery选择器进行网页解析
最近开发一个小功能,数据库中一个基础表的数据从另一个网站采集. 因为网站的数据不定时更新,需要更新后自动采集最新的内容. 怎么判断更新数据没有? 好在网站有一个更新日志提示的地方,只需要对比本地保留的 ...
- Fiddler设置抓取FireFox火狐的包
参考 http://blog.csdn.net/zhoutaohenan/article/details/8477993 亲测有效 Fiddler使用教程 http://blog.csdn.net/o ...
随机推荐
- Python学习笔记(四)
Python学习笔记(四) 作业讲解 编码和解码 1. 作业讲解 重复代码瘦身 # 定义地图 nav = {'省略'} # 现在所处的层 current_layer = nav # 记录你去过的地方 ...
- Java限流策略
概要 在大数据量高并发访问时,经常会出现服务或接口面对暴涨的请求而不可用的情况,甚至引发连锁反映导致整个系统崩溃.此时你需要使用的技术手段之一就是限流,当请求达到一定的并发数或速率,就进行等待.排队. ...
- 【ASP.NET MVC 学习笔记】- 20 ASP.NET Web API
本文参考:http://www.cnblogs.com/willick/p/3441432.html 1.ASP.NET Web API(本文简称Web API),是基于ASP.NET平台构建REST ...
- Java基础总结--泛型总结
-----泛型------JDK1.5出现的机制1.泛型出现的原因--简化书写,提高安全性技术的由来是为了解决问题,现在存在该问题,所有的容器定义类型为Object,所以任何对 象均可以放入容器--进 ...
- 关于js赋值给input解析
<script type="text/javascript"> //关于js中取值问题 $(function(){ //定义function函数 var firstDa ...
- JS框架设计读书笔记之-选择器引擎01
选择符 选择符是指CSS样式规则最左边的部分,例如 p{},#id{},.class{},p.class{} 等等 总共可以分为四大类: 并联选择器 => 逗号 => $('div,spa ...
- 如何在 Apple TV 上使用描述文件
您可以使用 OS X 上的 Apple Configurator 在 Apple TV 上安装配置描述文件. 开始前,请在 Mac 上安装最新版本的 Apple Configurator(如果尚未安装 ...
- VS2012 C#生成DLL并调用
1.创建一个C#工程生成DLL 新建->项目->Visual C#->类库->MyMethods 项目建好后,为了理解,将项目中的Class1.cs 文件 重命名为 MySwa ...
- 0_Simple__cppOverload
使用cuda内质结构 cudaFuncAttributes 来观察核函数的共享内存.寄存器数量. ▶ 源代码: /*cppOverload_kernel.cuh*/ __global__ void s ...
- (二)springboot整合thymeleaf模板
在我们平时的开发中,用了很久的jsp作view显示层,但是标签库和JSP缺乏良好格式的一个副作用就是它很少能够与其产生的HTML类似.所以,在Web浏览器或HTML编辑器中查看未经渲染的JSP模板是非 ...