I have a Bootstrap navbar. Inspecting with Chrome DevTools I noticed that this (and other browsers, I suppose) returns decimal box widths instead of integers (i.e. 83.06 instead of 83).
For a pixel-perfect alignment with some other elements I need to 'convert to integer' this number, and to avoid button collapse in 2+ words items I need to 'round up' it: in short, 83.06
should become 84
(and not 83
).
The only way I'm aware of is with JavaScript, so I did this script:
$(window).on('resize', function(){ // recalculate when resizing window
if (window.innerWidth > 768) { // only in 'desktop' version(s), smaller devices don't need recalculation
$('.navbar-nav').find('> li:not(.hidden-sm)').each(function(){
var width = $(this).children('a').outerWidth(); // for each valid 'li', take its 'a' descendant width
console.log(width); // watch what happens
$(this).width(Math.ceil(width)); // change item width with a 'rounded up' value
})
}
}).resize();
Here is the code snippet (jsFiddle):
$(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).children('a').outerWidth(); // for each valid 'li', take its 'a' descendant width
console.log(width); // watch what happens
$(this).width(Math.ceil(width)); // change item width with a 'rounded up' value
})
}
}).resize();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<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>
Pretty straight, right? But it doesn't work as expected: items' original widths (86.05
, 124.17
and 107.7
according to Chrome DevTools) are not always rounded up despite the Math.ceil()
function and I end up with 86
, 124
and 108
(only the latter is right; the first two items 'collapse' because there is not enough space). Shouldn't Math.ceil()
always round up? Very weird...
"Ok", I thought, "let's find a workaround": so I swapped Math.ceil()
with parseInt()
and add at least +1
pixel, like this other snippet (jsFiddle):
$(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).children('a').outerWidth(); // for each valid 'li', take its 'a' descendant width
console.log(width); // watch what happens
$(this).width(parseInt(width)+1); // change item width with a 'rounded up' value
})
}
}).resize();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<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>
Good, buttons don't collapse but... try to resize the window: buttons grow forever, maybe because I'm adding 1 pixel to each iteration: this is worse than before...
Now I am stuck and can't imagine other ways to go: any solution to get integers rounded up without ending with all these crazy results, please? Thank you