jQuery 1.8 box-sizing: width(), css(“width”), and outerWidth()

Posted on by

One of the great new features in jQuery 1.8 is a built-in understanding of box-sizing: border-box which is supported by every modern browser. (Sorry, IE6 and IE7, please take one step back; I said modern browser.)

If you showed people an element with a border on the screen and asked them the width of that element, they would naturally measure from the outside edges of the border. Yet that’s not the way CSS works in its default content-box mode. Normally, CSS width and height only include the “content” inside the border and padding. As a result, designers (and jQuery) often need to add the width to the right/left padding and border to get the “natural” width of the element.

Using box-sizing: border-box changes the CSS notion of the width of an element to include both the padding and the border dimensions, just the way you’d naturally measure it. jQuery versions before 1.8 were not fully trained in the ways of the border-box, but we’ve fixed this bug.

One thing that hasn’t changed is the return value of the .width() method. As it’s always been documented, it gets and/or sets the “content” width of an element, and that is regardless of the CSS box-sizing being used by the element. However, jQuery 1.8 now needs to check the box-sizing property whenever you use .width() so that it can decide whether it needs to subtract out the padding and border width. That can be expensive—up to 100 times more expensive on Chrome! Fortunately, most code doesn’t use .width() enough times for this to be noticeable, but code that gets the width of dozens of elements at once could be impacted.

There is a very easy way to avoid this performance penalty if it does impact your code. Simply use .css("width") instead of .width() to make it clear you want to get or set the actual width of the element as specified by the CSS. That doesn’t require jQuery to look at box-sizing. Remember, however, that .css("width") as a getter returns a string with “px” at the end, so you’ll want to use something like parseFloat( $(element).css("width") ) for situations where the result must be numeric.

And of course, everything mentioned here about .width() also applies to .height() as well; use .css("height") to skirt the performance penalty there.

Using .outerWidth() as a setter

In other dimensionally related news, jQuery’s .outerWidth() and .outerHeight() methods have been updated in 1.8 so that they can be used as setters. (jQuery UI has supported them as setters since UI version 1.8.4, but now it’s built into core.) To use .outerWidth() as a setter, pass an argument that is a number representing the outer width (CSS “content” width, plus padding and border width). And yes, this handles the box-sizing: border-box situation fine as well; it’s basically the same as setting the .css("width") in that case.

We’ve received a few reports from people who had problems with .outerWidth() in jQuery 1.8 because it was returning the jQuery object instead of a numeric width. This happens if you call $(element).outerWidth(0) for example. Before jQuery 1.8, this was an invalid use of the API because it was documented to accept a single Boolean argument. However, it treated the invalid argument as a Boolean and returned the width. In 1.8, jQuery uses the value 0 to set the width, and like most setters it returns the jQuery object.

We’re in the process of updating the API documentation for all the changes to 1.8, but for now you can refer back to the changelog in the jQuery 1.8 announcement to see what’s changed.

16 thoughts on “jQuery 1.8 box-sizing: width(), css(“width”), and outerWidth()

  1. Mike Sherov on said:

    @Tim, all of the dimensions getters actually got a slight speed up (depending on browser). It’s mainly the setter case (which for 1.8, is new for outerWidth and innerWidth) that got slowed down.

    To summarize:
    setters:
    .outerWIdth(), .innerWidth(): NEW
    .width(): slower
    .css(“width”): unchanged

    getters:
    .outerWIdth(), .innerWidth(), .width(), .css(“width”): unchanged

  2. Viktor Snezhko on said:

    Ha ha, it did not work neither. It looks it is not possible to provide any html codes. Let me know if I should use >/< or whatever.

  3. Viktor Snezhko on said:

    <script type=”text/javascript” src=”http://code.jquery.com/jquery-1.8.0.js”></script>
    <script type=”text/javascript”>
    function check1() {
    var e = $(“#span1”);
    alert(“width():” + e.width() +
    “\ncss(width):” + e.css(“width”) +
    “\nstyle.width:” + e[0].style.width +
    “\noffsetWidth-border/padding:” + (e[0].offsetWidth – 14) +
    “\noffsetWidth:” + e[0].offsetWidth +
    “\nheight():” + e.height() +
    “\ncss(height):” + e.css(“height”) +
    “\noffsetHeight-border/padding:” + (e[0].offsetHeight – 14) +
    “\noffsetHeight:” + e[0].offsetHeight +
    “\nstyle.height:” + e[0].style.height);
    }
    </script>
    <style type=”text/css”>.css1 { border:2px solid blue;padding:5px;width:300px; }</style>
    <span class=”css1″ id=”span1″ style=”background:red;height:300px;”>span1</span>
    <input type=”button” id=”check1″ value=”check” onclick=”check1()” />

  4. I can’t believe I didn’t used CSS box-sizing: border-box till now, it would solve lots and lots of days of work till now. I do see now the point of reading “what’s new” as you mostly find useful stuff.

  5. “Sorry, IE6 and IE7, please take one step back; I said modern browser.”

    Ah, how we have come full circle. This is hardly the place to call out IE for being wrong, since actually they had it right in the first place. This feature that “modern” browsers support is, actually, just like “quirks” mode, which old IE browsers do by default.

    http://en.wikipedia.org/wiki/Internet_Explorer_box_model_bug

    Now, back to our regularly scheduled (and typically deserved) IE bashing.

  6. Frédéric Hamidi on said:

    Regarding your last paragraph, jQuery is now popular enough that we had http://stackoverflow.com/questions/12011925/pipe-and-then-documentation-vs-reality-in-jquery-1-8 before you got a chance to update the documentation (or maybe even while you were doing that, according to comments).

    That’s quite an achievement IMHO. I have a hunch many users will not expect the breaking change made to then(), and this is only the first of a series a questions about that change. Hope the new docs point that out, so we only have to link to them ;)

    Thanks for the great work, as always.

  7. Devin Dombrowski on said:

    @jamie as sad as it is, we have to be honest and recognize that IE did do certain things first. border-box, CSS gradients, transparency, and so on.

  8. shuangbao.li on said:

    I’m sure I didn’t pass any arguments to outerWidth function, but it return jquery object too!

  9. @shuangbao.li – I am experiencing this same behavior. Every time I call outerWidth() I receive the jQuery object in return.

  10. If you are having any issue with outerWidth and outerHeight returning the jQuery object in all instances don’t despair.

    Including jQuery UI version <= 1.8.21 (June 15 2012 release) causes outerWidth and outerHeight to break! Just upgrade jQuery UI and all should be fine.

    http://jsfiddle.net/MaCxx/3/ – broken – jquery ui 1.8.21 http://jsfiddle.net/Mk82e/1/ – fixed – jquery ui 1.8.23

  11. I’m not sure it’s the bug or intended feature (hope not). It doesn’t work for tag. Sample here.

    ….

    e = $(‘#svg1’)
    w1 = e.width() // NaNpx
    w2 = e.css(‘width’) // NaNpx

  12. As “-moz-box-sizing” property is used, the popular web-developer addon reports CSS error. I am perfectionist, and this is the only content-formatting error that I have on my site – and I hate it. Please solve this problem differently, and remove this junk.

  13. I cannot believe I did not used CSS box-sizing: border-box until now, it would fix a lot and many periods of execute until now. I do see now the aspect of learning “famous people” as you mostly find out useful factors.