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 width
s of all those li
s 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 li
s 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
How to Read an External Local Json File in JavaScript
How Does This JavaScript/Jquery Syntax Work: (Function( Window, Undefined ) { })(Window)
Settimeout Calls Function Immediately Instead of After Delay
Difference Between Synchronous and Asynchronous Programming (In Node.Js)
Crockford'S Prototypal Inheritance - Issues With Nested Objects
Converting JavaScript Object With Numeric Keys into Array
What Are Alternatives to Document.Write
Use :Hover to Modify the CSS of Another Class
How to Fetch the Value of a Non-Standard CSS Property via JavaScript
How to Make Jquery UI Tabs Scroll Horizontally If There Are Too Many Tabs
Get the Size of a CSS Background Image Using JavaScript
Disable Underline for Lowercase Characters: G Q P J Y
Using JavaScript in Android Webview
How to Install Jslint on Ubuntu
.Trim() in JavaScript Not Working in Ie
How to Define Global Variables in Coffeescript