Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does $('#foo').css('width', $('#foo').css('width')) change the width?

Tags:

jquery

css

One would think that after the following bit of jQuery, the width of the div selected by #foo would not change at all; after all, we are setting this width to the value it supposedly already has:

var original_width = $('#foo').css('width');
$('#foo').css('width', original_width);

In fact, this reasonable guess appears to be wrong, as shown in this page. I give the code below. The important thing to note is that the four main sections, corresponding to the four .level-0 divs, all have the same structure and content. The second and fourth of them (which have the jqbug class) have their width "re-set" (with a bit of JS, as described above) to the value it supposedly already has. For the second one case, the width is actually changed by this operation; for the fourth case, the width remains unchanged, as expected. The only difference between the definitions of the second and fourth cases is that the former has border-box for its box-sizing parameter.

<div class="level-0 border-box">
    <div id="i1" class="level-1">
      <p>Lorem ipsum dolor sit amet</p>
    </div>
</div>

<div class="level-0 border-box">
    <div class="level-1 jqbug">
      <p>Lorem ipsum dolor sit amet</p>
    </div>
</div>

<div class="level-0">
    <div id="i1" class="level-1">
      <p>Lorem ipsum dolor sit amet</p>
    </div>
</div>

<div class="level-0">
    <div class="level-1 jqbug">
      <p>Lorem ipsum dolor sit amet</p>
    </div>
</div>

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js">
</script>


  (function ($) {
    $('.jqbug').each(function () {
      $(this).css('width', $(this).css('width'));
    });

  }(jQuery));


*{
  outline:3px solid green;
}

.border-box, .border-box *{
  -webkit-box-sizing:border-box;
     -moz-box-sizing:border-box;
          box-sizing:border-box;
}

.level-0{
  position:relative;
  margin:10px auto;
  width:300px;
  height:100px;
  font-family:consolas,monaco,courier,monospace;
}
.level-1{
  position:absolute;
  padding:10px 20px;
  background-color:#0aa;
  font-size:15px;
}

In this jsFiddle, which uses exactly the same code as shown above, all the divs end up with the same width. On the one hand, this is good: the results have the appearance one would expect. On the other hand, the fact that jsFiddle's result is not representative of what the browser produces directly is just as puzzling as jQuery's behavior.

My questions are:

  1. Is this a bug in jQuery, or is this puzzling behavior somehow in agreement with the CSS spec?

  2. What does one need to do to get the result produced by jsFiddle to look like that produced by the browser?

EDIT: I modified the JS (in both the page linked above and the jsFiddle, as well as in this post) to match that given in Marco Biscaro's answer; this made no difference to the appearance of the page as displayed directly by the browser, but it did affect the appearance of the jsFiddle's result. Now the latter shows no difference in the widths of the various divs. This result still differs from that produced directly by the browser, so the situation is not much better than it was before: we still have that jQuery produces surprising results, and jsFiddle produces results that do not match the browser's results.

like image 593
kjo Avatar asked Dec 21 '13 19:12

kjo


1 Answers

You have two different divs with the same class. When you do:

$('.jqbug').css('width')

The width of one of the divs is returned (I don't know exactly how jQuery determines which of two). In your hosted page, the value returned is 234px while in jsFiddle the value is 274px (again, I don't know exactly why). This is why the behaviour is different between the two pages.

This returned value is applied as width of both divs, but because one div has the box-sizing: border-box and the other hasn't, one div gets bigger than the other.

jQuery won't change the width of any div, as expected, if you set the width as the original width and use $(document).ready (http://bugs.jquery.com/ticket/14084):

$(document).ready(function () {
    $('.jqbug').each(function () {
        $(this).css('width', $(this).css('width'));
    });
});
like image 138
Marco Biscaro Avatar answered Nov 10 '22 04:11

Marco Biscaro