How to Make Jquery to Not Round Value Returned by .Width()

Getting the actual, floating-point width of an element

If you already have a reference to the DOM element, element.getBoundingClientRect will get you the values you want.

The method has existed since Internet Explorer 4, and so it's safe to use everywhere. However, the width and height attributes exist only in IE9+. You have to calculate them if you support IE8 and below:

var rect = $("#a")[0].getBoundingClientRect();

var width;
if (rect.width) {
// `width` is available for IE9+
width = rect.width;
} else {
// Calculate width for IE8 and below
width = rect.right - rect.left;
}

getBoundingClientRect is 70% faster than window.getComputedStyle in Chrome 28, and the differences are greater in Firefox: http://jsperf.com/getcomputedstyle-vs-getboundingclientrect

Getting integer box widths instead of decimal values: Math.ceil() doesn't round up

Your problem is that jQuery's .width() already internally rounds the width values to the closest integer (so: 86.05 => 86 , 124.17 => 124 , 107.7 => 108).

So the values you retrieve using .width() and perform your rounding calculations on, are already integers, and therefor they have no effect whatsoever:)

This can be resolved by using JavaScript's native .getBoundingClientRect():

This will return the actual floating-point width (got it from this answer).

var width = $(this).children('a')[0].getBoundingClientRect().width;

You could leave it at that, but now the widths of all those lis are always reset, whether they already have been or not.

To prevent that, I used an if-clause to check if the width is not already an integer, and only then gets the element actually resized.

This is all you need for that (which I got from this answer):

if (width%1 !== 0) {$(this).width(Math.ceil(width));}

But to be safe I would also remove .children('a'), and measure the lis themselves:

var width = $(this)[0].getBoundingClientRect().width;

Apparently the a automatically fills the entire li, but the li also auto-scales to the a, and since you're performing the .width() operation on the li, it seems safer and more logical to also check the width of that same element.
Alternatively, you could set the width() of the a instead of the li.


See code snippet for a demo  (put snippet in "Full page" to test):

$(window).on('resize', function(){ // recalculate when resizing window

if (window.innerWidth > 768) { // only in 'desktop' version(s)

$('.navbar-nav').find('> li:not(.hidden-sm)').each(function(){

var width = $(this)[0].getBoundingClientRect().width; // for each valid 'li', take its 'a' descendant width

if (width%1 !== 0) {$(this).width(Math.ceil(width));} // if width isn't already an integer, round up

console.log(width, 'resize: '+(width%1 !== 0));

});

}

}).resize();
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

<nav class="navbar navbar-default">

<div class="container-fluid">

<!-- Collect the nav links, forms, and other content for toggling -->

<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">

<ul class="nav navbar-nav">

<li class="active"><a href="#">Link One<span class="sr-only">(current)</span></a></li>

<li><a href="#">Link Two, Long</a></li>

<li class="dropdown">

<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>

<ul class="dropdown-menu">

<li><a href="#">Action</a></li>

<li><a href="#">Another action</a></li>

<li><a href="#">Something else here</a></li>

</ul>

</li>

<li class="hidden-sm"><a href="#">Link Three: too long to fit, hide on small devices</a></li>

</ul>

</div><!-- /.navbar-collapse -->

</div><!-- /.container-fluid -->

</nav>

Formatting a number with exactly two decimals in JavaScript

To format a number using fixed-point notation, you can simply use the toFixed method:

(10.8).toFixed(2); // "10.80"

var num = 2.4;
alert(num.toFixed(2)); // "2.40"

Note that toFixed() returns a string.

IMPORTANT: Note that toFixed does not round 90% of the time, it will return the rounded value, but for many cases, it doesn't work.

For instance:

2.005.toFixed(2) === "2.00"

UPDATE:

Nowadays, you can use the Intl.NumberFormat constructor. It's part of the ECMAScript Internationalization API Specification (ECMA402). It has pretty good browser support, including even IE11, and it is fully supported in Node.js.

const formatter = new Intl.NumberFormat('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});

console.log(formatter.format(2.005)); // "2.01"
console.log(formatter.format(1.345)); // "1.35"


Related Topics



Leave a reply



Submit