【续】抓个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 ...
随机推荐
- Django之环境搭建以及初始配置
Django采用MVC架构,百度百科介绍如下: 全名Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业 ...
- 博客志第一天——判断一个整数N是否是完全平方数?
关注博客园很久,今天是第一次写博客.先附上一个C题目:写一个函数判断一个整数是否为完全平方数,同时是否该数的各位数至少两个相同的数字 #include <stdio.h> #include ...
- Oracle:sqlplus前缀显示当前用户
第一步:进入SQLPLUS的按照目录,cd $ORACLE_HOME/sqlplus/admin 第二步:查找ll vi glogin.sql 第三步:插入 命令行模式,Go, set sq ...
- 多服务器终端交互利器--polysh和atnodes到高逼格日志中心
最近博客更新的少了,相对而言,我在自己的个人公众号里还是挺活跃的,大家可以扫描旁边的二维码,或者微信搜索公众号:“编程一生”加关注. 在分布式的年代,一个应用需要部署到多台服务器上.那么要查看日志文件 ...
- RQPro 公募FOF策略实例——晨星基金筛选和风险平价配置
2017年9月8日,证监会公布首批公募FOF基金名单,标志着公募FOF产品正式落地.FOF(Fund of Funds)是一种通过投资基金,而非直接投资具体证券标的(股票或债券等)来实现分散化资产配置 ...
- C++中的endl
从开始接触C++到现在,一直以为语句 cout << "hello world!" << endl; 中的endl只是一个相当于C中的换行'\n':直到今天 ...
- 每天一个linux命令(26):用SecureCRT来上传和下载文件(转载自竹子)
用SSH管理linux服务器时经常需要远程与本地之间交互文件.而直接用SecureCRT自带的上传下载功能无疑是最方便的,SecureCRT下的文件传输协议有ASCII.Xmodem.Zmodem. ...
- PHP内写css样式
<1>php的两种输出方式 1,echo: 2,print; 栗子: <?php echo:"你好,我的名字是LHH"; print:"你好,我的名字是 ...
- Leetcode题解(五)
17.Letter Combinations of a Phone Number 题目 针对输入的数字串,每一个数字都对应对个字符可以选择.因此可以直接采用递归的思想,依次遍历数字串的每一个数字,处理 ...
- Shape of HDU
Shape of HDU Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...