HTML5技术

【续】抓个Firefox的小辫子,jQuery表示不背这黑锅,Chrome,Edge,IE8-11继续围观中 - 三生石

字号+ 作者:H5之家 来源:H5之家 2017-12-01 12:15 我要评论( )

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

引子

昨天我发了一篇文章【抓个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> <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> <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下可以重现问题:

     

    简化下代码:

     

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • 特殊字符导致jquery-mobile 挂起(firefox控制台报错 malformed URI sequence)

      特殊字符导致jquery-mobile 挂起(firefox控制台报错 malformed URI

      2017-02-07 11:00

    网友点评
    a