Reputation: 7961
Somehow, merely setting a font-family: sans-serif
style in the following document is causing li
tag contents to wrap in IE 11.0.9600.16438 and FireFox 25.0.1 but not in Chrome 31.0.1650.57. I first noticed it when I noticed that some li
tags were wrapping unnecessarily while using SimpleModal 1.4.4. I managed to reproduce this by adding, piece-by-piece, markup and CSS styles to a standalone document. Finally, I used jQuery's outerWidth
and outerHeight
methods to retrieve a calculated size, which I've confirmed is just what SimpleModal uses.
EDIT: Just to be clear, I am using the outerWidth
and outerHeight
results to set an explicit size on the modal dialog. This is what SimpleModal does and it's apparently crucial to the proper functioning of dialogs. My question is in the context of SimpleModal but I've narrowed down the strange behavior to jQuery.
Here's the markup without font-family: sans-serif
:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<style>
* { -moz-box-sizing: border-box; box-sizing: border-box; font-size: 16px; font-weight: normal; font-style: normal; font-family: sans-serif; }
ul { margin: 0 0 0.5rem; padding: 0 0 0 2rem; list-style: disc; }
p { margin: 0 0 0.5rem 0; padding: 0 }
.simplemodal-wrap { height: 100%; outline: 0; width: 100%; overflow: visible; }
.simplemodal-data { background-color: #ddd; padding: 1rem; }
</style>
</head>
<body>
<main>
<div class="simplemodal-container" style="position: fixed; left: 25px; top: 75px; z-index: 1002;">
<div class="simplemodal-wrap">
<div class="simplemodal-data">
<p>Lorem ipsum Lorem ipsum Lorem ipsum:</p><ul><li>Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum</li><li>Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum</li><li>Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum</li><li>Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum </li><li>Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum</li><li>Lorem ipsum Lorem ipsum Lorem ipsum </li></ul><p>Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum :</p><ul><li>Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum </li><li>Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum </li></ul>
</div>
</div>
</div>
</main>
<script>
$(function() {
var sc = $(".simplemodal-container");
var outerWidth = sc.outerWidth(true);
var outerHeight = sc.outerHeight(true);
$("main").append("<div>outerWidth(true) x outerHeight(true):<br>" + outerWidth + " x " + outerHeight + "</div>");
sc.css({ width: outerWidth, height: outerHeight });
});
</script>
</body>
</html>
The results in all three browsers look correct (here's Chrome as an example):
Now, simply add font-family: sans-serif;
to the *
selector and refresh all three browsers. Suddenly, the width calculation is wrong!
Increasing the width by one pixel in IE and FireFox causes the li
tags to no longer wrap.
What's going on here? Is this some kind of rounding bug with font size calculations?
EDIT: Here's the code I ended up adding to jquery.simplemodal-1.4.4.js on line 553:
// jQuery truncates subpixel width and height calculations
// Fixed incorrect wrapping in Mozilla
var userAgent = navigator.userAgent.toLowerCase();
if (userAgent.length >= 7 && userAgent.substring(0, 7) === "mozilla") {
dw++;
dh++;
}
Such a hack, but a necessarily one, apparently. :(
Upvotes: 1
Views: 524
Reputation: 35074
What's going on is that jQuery's outerWidth
API is broken by design: it returns an integer number of CSS pixels.
In a browser that does subpixel text shaping and positioning (which Firefox and IE do and Chrome does not), the width of a string of text is not going to be an integer number of CSS pixels, in general. And even in Chrome, if you have a high-DPI screen, so that one CSS pixel corresponds to two or more device pixels, the width of a string of text can end up being a non-integral number of CSS pixels.
What jQuery then does is effectively take the actual width and round down to an integer. Which means the number you get is too small if the text wasn't exactly an integer number of pixels wide.
What you probably want to do is use getBoundingClientRect()
to get the actual dimensions of the box without rounding. And complain to the jQuery authors about jQuery not providing a convenient API for that. ;)
Upvotes: 1