Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

em support has incorrect breakpoints when font-size on :root != 100% #128

Closed
pdaoust opened this Issue · 10 comments

4 participants

@pdaoust

Awesome work on the em-support branch; I like how it respects the user's font size setting rather than relying on a hard-coded 16px value. However, I have come across some issues when the root element's font-size does not equal 100%.

For me, this doesn't matter; I always use font-size: 100% on the root element; however, I know some people like font-size: 62.5% to make 1em = 10px.

I've set up a test demonstrating this issue. I've yanked out the getEmValue() function and modified it ever so slightly to not need the rest of Respond. (At least I'm pretty sure that it doesn't rely on it; let me know if I'm wrong!)

http://heliosstudio.ca/basefont-test.php (works fine)
http://heliosstudio.ca/basefont-test.php?rootsize=62.5 (font-size: 62.5% applied to root element; has issues)
http://heliosstudio.ca/basefont-test.php?rootsize=120 (font-size: 120% applied to root element; has issues also)

I've set up two breakpoints: @media (max-width: 19.99999em) and @media: (min-width: 20em), which match the device-width of most mobile browsers to make testing easy. The header (and the 'According to the browser') will change depending on the width of the window/viewport using a browser's built-in media query support. The 'According to Respond.js' line, however, changes based on the reported em size from getEmValue(). (It updates on the window.onscroll event, so you can play around with it live.)

In the first link, you'll see that Respond calculates media query ems exactly the same as the browser. (Incidentally, changing the browser's base font size doesn't affect anything; it still works great.)

In the second and third links, however, you'll see that Respond changes its breakpoint at a slightly different place from the browser. This has to do with the browser basing its media query ems on the user's base font size, but Respond basing its media query ems on the document's base font size.

I'm observing this issue in Chromium 18, Firefox 11, IE9, Android 2.3 Webkit, and Opera Mobile 12, so it seems to be standard practice to pull em values for media queries from the user's stylesheet irrespective of the document's stylesheet.

Honestly, I'm not sure how to go about addressing this issue. Because Respond is already parsing CSS, perhaps it could nab the root element's font-size declaration as it's hunting for media queries. Or maybe there are possible solutions that involve creating an iframe with no styling and drawing the em value from that? Or (I don't know enough about the DOM to say whether this is possible) perhaps there's a parent element of the document that allows you to access the user's default font size?

(By the way, feel free to play around with different base font size values -- append ?rootsize=50, for example, to make the base font size 50%, and ?rootsize=.5em to make it half an em.)

@scottjehl
Owner
@pdaoust

Hi, Scott. No prob; this bug-hunting is fun, and I've been worried for a while whether JavaScript can be relied upon to accurately give us em values. This experiment settled my chief concern -- that a smaller or larger font-size setting in the user's stylesheet would throw things off (it doesn't, as long as the document's base font size is 100%) -- but uncovered the above issue.

I pulled the getEmValue() function directly from the current master -- I didn't want to use the entire respond.src.js because I was only concerned about that one function, and wanted it to report the exact em value to me. I also get that same function to return the document's clientWidth property in both ems and px, using the same eminpix calculations Respond uses.

The only other thing that I changed was to change the function's declarations of doc (and hence docElem) so that they would work without the rest of the script.

However, I am wondering if I should be using the entire respond.js script -- are there any side effects in the rest of the script that getEmValue() relies on? Maybe I should test it out with the entire script and see what happens...

@pdaoust

Hi, Scott. I downloaded a copy of respond.js from master and tested out my assumptions in Chromium and IE8. It turns out that it's still following that same pattern -- Respond.js gets its em size from the em size of the root element, rather than the em size of the user agent's stylesheet.

Here's an expanded test (using current master):

http://heliosstudio.ca/respond-test/respond-test.php?rootsize=75

This creates a stylesheet with the following rule: html { font-size: 75%; } plus a few media queries. Respond sees the breakpoint at 240px, whereas browsers that support media queries see the breakpoint at 320px.

I think that, until a clever technique for grabbing the user stylesheet's base font size can be discovered, maybe the simplest solution is to tell people about this issue in the README, and to suggest scaling the base font size in their #container element rather than the <html> element. This does, however, prevent people from setting their base font size to 62.5% for the 1em = 10px trick.

@DesignByOnyx

Hey, I wrote the em support for respondjs - I wrote it under my previous employer's account (NetEffect), but it was me doing the coding. This issue is one those that came to me while I was just walking around one day... and I figured I'd wait for someone to bring it up before trying to fix. If someone is still interested, please respond to this post and I will test it out. The fix should be to temporarily set the root element's font size to 100%, run calculations, and then restore the original font size.

@pdaoust

Hi, @DesignByOnyx. Thanks for the response! I know the experience -- having some code-related epiphany come to you when you're nowhere near a computer. Anyhow, that's a clever idea, but I wonder if you might get a flash of resized text. What about this: creating an empty <iframe> (which would of course have no styling except the user stylesheet) and doing the em test in there? I tried it out in a fork, and it worked quite well (after encountering issues with iframes containing no document element until you did something weird to them; I forget the details). I submitted a pull request, but it hasn't been pulled yet -- I suspect the author is probably pretty busy with real-life concerns, like doing actual paid work for one of the most respected web dev companies around :)

In my tests, it worked on IE6, IE8, and Firefox 3. No success on Safari 3 or 4 though.

@DesignByOnyx
@pdaoust

Hi, Ryan. There was only a few extra lines of code in the iframe version. But if you say that the font-size on the root element can be temporarily changed without a redraw, that would probably be the superior solution -- I felt uncomfortable about creating an entirely new empty DOM just to check the base font size.

Would one need to temporarily change the font-size on the <body> element as well, or does your code create a new body?

@DesignByOnyx
@pdaoust

:) I like your pragmatic outlook -- a small redraw is the least of their problems. I'm going to try out that strategy, when I have the chance -- it's less of a priority for me right now, as I've moved to just adding an .unresponsive class to the root element for IE 6-8 and duplicating the styles, the weight of which (in my tests) is minimised by gzipping.

(And of course this wasn't an issue to me in the first place, because I always go body { font-size: 100%; }.

@jefflembeck
Collaborator

Fixed the PR referenced above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.