引子

昨天我发了一篇文章【抓个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下重现需要满足如下几个条件:

  1. 设置CSS全局属性:box-sizing: border-box
  2. HTML标签为:fieldset(其他标签没问题,比如div就是正常的)
  3. fieldset绝对定位:position:absolute

在这 3 个条件下,调用JS代码 window.getComputedStyle(elem)["paddingTop"] 之后再设置 fieldset 标签的高度,页面上不会更新!

解决办法请看我的上一篇文章:【原创】抓个Firefox的小辫子,围观群众有:Chrome、Edge、IE8-11

点赞

喜欢三石的文章,你就给个推荐呗!

【续】抓个Firefox的小辫子,jQuery表示不背这黑锅,Chrome,Edge,IE8-11继续围观中的更多相关文章

  1. 【原创】抓个Firefox的小辫子,围观群众有:Chrome、Edge、IE8-11

    前言 很多人都知道我们在做FineUI控件库,在这 9 年多的时间里,在和浏览器无数次的交往中,也发现了多个浏览器自身的BUG,并公开出来方便大家查阅: 分享IE7一个神奇的BUG(不是封闭标签的问题 ...

  2. (二)Fiddler抓取Firefox、Chrome浏览器上的https协议

    Fiddler抓取Firefox.Chrome浏览器上的https协议 安装Fiddler后默认只抓取http协议,如果是https协议的话,浏览器就会提示"您的链接并不安全". ...

  3. fidder工具学习抓取Firefox包

    fidder抓取Firefox的https请求 抓包之前需要设置fidder,我下面的截图是fidder4,打开fidder—>Tools—>Options如图: 选择https,勾选所有 ...

  4. JS 在页面上直接将json数据导出到excel,支持chrome,edge,IE10+,IE9,IE8,Safari,Firefox

    JS 在页面上直接将json数据导出到excel,支持chrome,edge,IE10+,IE9,IE8,Safari,Firefox <html> <head> </h ...

  5. 针对firefox ie6 ie7 ie8的css样式中的line-height属性

    针对firefox ie6 ie7 ie8的css样式中的line-height属性 以前我们大部分都是用!important来hack,对于ie6和firefox测试可以正常显示,但是ie7以上对! ...

  6. Jquery基本教程(背还是要背的)

    Jquery入门学习 一.简介 1.Jquery是基于JavaScript的一种框架,兼容主流浏览器,提供了dom,animate(JQ+CSS),ajax; 2.Jquery2.0后版本不支持IE6 ...

  7. 使用Chrome快速实现数据的抓取(三)——JQuery

    使用Chrome抓取页面一个非常方便的地方就是它可以执行JS,也就是说我们可以通过JS函数获取我们想要的数据.一个非常强大易用的库就是Jquery,本文就简单的介绍一下使用Chrome获取数据时Jqu ...

  8. 网页抓取解析,使用JQuery选择器进行网页解析

    最近开发一个小功能,数据库中一个基础表的数据从另一个网站采集. 因为网站的数据不定时更新,需要更新后自动采集最新的内容. 怎么判断更新数据没有? 好在网站有一个更新日志提示的地方,只需要对比本地保留的 ...

  9. Fiddler设置抓取FireFox火狐的包

    参考 http://blog.csdn.net/zhoutaohenan/article/details/8477993 亲测有效 Fiddler使用教程 http://blog.csdn.net/o ...

随机推荐

  1. 基于FFMPEG的跨平台播放器实现(二)

    基于FFMPEG的跨平台播放器实现(二) 上一节讲到了在Android平台下采用FFmpeg+surface组合打造播放器的方法,这一节讲一下Windows平台FFmpeg + D3D.Linux平台 ...

  2. mysql 中select for update 锁表的范围备注

    mysql的锁表范围测试 1.主键明确时,行级锁: 解释:指定主键并且数据存在时,仅锁定指定的行,其它行可以进行操作 实例:指定了锁定id=1的行且数据存在①,在更新1时lock wait超时②,但是 ...

  3. 通过 ODBC 访问数据库获取数据集

    Step1:(window 中完成): 控制面板/管理工具/ODBC 数据源/用户 Step2:(window 中完成): 添加/SQL Server Step3:(window 中完成): 自己定义 ...

  4. 使用element ui 日期选择器获取值后的格式问题

    一般情况下,我们需要给后台的时间格式是: "yyyy-MM-dd" 但是使用Element ui日期选择器获取的值是这样的: Fri Sep :: GMT+ (中国标准时间) 在官 ...

  5. ubuntu-17.10 安装 FANN

      因为想用C语言写神经网络,不用已有的库的话,又太难了,所以准备安装一个夸平台的FANN库, 源文件下载地址http://leenissen.dk/fann/wp/download/,我下载的是最新 ...

  6. 借助csv用PHP生成excel文件

    当你将xml文件改为csv后缀会发现原先的表格结构都变成用逗号隔开的一行一行数据,就像这样 编号,姓名,年龄 001,王宇,28 002,刘三,20 由此看来,如果能将PHP数据输出为这样的格式,然后 ...

  7. 哈尔滨理工大学第六届程序设计团队 E-Mod

    /* 成功水过,哈哈哈,可能数据水吧 */ #include <stdio.h> #include <algorithm> #include <string.h> ...

  8. Is It A Tree?

    Is It A Tree? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total ...

  9. Unity3D手机斗地主游戏开发实战(03)_地主牌显示和出牌逻辑(不定期更新中~~~)

    Hi,之前有同学说要我把源码发出来,那我就把半成品源码的链接放在每篇文件的最后,有兴趣的话可以查阅参考,有问题可以跟我私信,也可以关注我的个人公众号,互相交流嘛.当然,代码也是在不断的持续改进中~ 上 ...

  10. Cisco VPN Client Win10无法使用的解决办法

    http://files.cnblogs.com/files/Flyear/VPN_Win10_ByDuke.zip 1. 关闭系统所有窗口,控制面板一定要关闭. 2. 运行winfix.exe, 按 ...