UX Design and Development course

Breakpoints and ems

If you are using pixels for media queries, then you are pretty much doing it wrong.

A phrase I like to say is, "Responsive web development isn't about the viewport, it's abut the device. And it's not about the device, it's about the viewport!"

Really, what the hell does that mean? Basically, when we as developers and designers need to consider the web in a vastly growing responsive space, we can't get locked into concepts like writing code for device and viewports specifically. This will only lock us into specific experiences and not really solve the issue at hand.

It was when I read this article The ems have it, this was a game changer. This article reshaped my perception of how you engineer experiences for the responsive web.

Before we can get into this too far and just start writing code examples, we need to understand what ems have to do with viewport space. In short, 1em is == to whatever your base font size is for your app. If you don't reset anything, 1em === 16px. Simple enough.

At this setting, there is a certain amount of characters that can fit within a given space. This basically determines your em width. Now don't get all hung up at this point to say that you need to count how many characters you can type across the view. There are tools we can use to determine this space.

The real mind bender is, we will use breakpoints at specific em widths that will determine our experience breakpoints between small, medium and large. But we aren't worried about the physical dimensions of a device, it's pixel ratio or it's position (horizontal or vertical). What we care about is thee readability of the content. What is the font size and what point do we need to enhance the experience based on how much content can comfortably fit in any given space.

Enough already, examples please

This is pretty abstract, I get that. It took me a while to get my head wrapped around this as well. Time for examples.

A common breakpoint would look like the following:

@media (min-width: 900px) {
  .block {
    background-color: green;

This is pretty common using pixels to determine breakpoints. But what is happening here? We are hardcoding this experience to the physical form of a device. What if our app ends up on a device that is not that size? How does our app respond? Even better, what if our app is on a device that supports a different breakpoint and the user zooms in? How does the content respond there?

In most cases, when you are using pixels as values, as the resolution and/or zooming of the device changes, the experience does not. If the content and layout get too large for the zoomed in experience, so be it. Sorry folks, nothing I can do here!

Measure the space, not the pixels

So what does using ems for breakpoints give us? Well, simply put, ems measure the available space the content can fit within the viewport, not the size of the viewport.

Let's look at that previous media query and see how I would update this for ems:

@media (min-width: 56.25em) {
  .block {
    background-color: green;

Not much different really, just changing the unit of measurement. All the other concepts are exactly the same.

How does this make things different? It's in the experience. What if the browser being used is zoomed in? What if it has a CSS reset installed that resets the default font-size? For whatever reason, just know that you are not in control of everything in regards to the experience at the other end.

When you use ems to measure the available space, this will trigger the breakpoints and you will get an experience that is appropriate for that environment, regardless of physical size and/or device.

Browsers are getting smarter, or are they?

In the article I point to, at the time of writing that the only browser that supported triggering a breakpoint at a zoom setting was Firefox. That was 2011.

Today, just about all browsers support this as a 'feature'. Once more, when doing further testing, I have notices that even when using pixels as breakpoints, when zooming in, browsers will also trigger the breakpoint. What does this mean? Well, it appears that browser developers are getting smarter about what's happening in the world and also are aware that not all developers are using correct coding habits.

I have mixed feelings about this. On one had, I am happy that more and more users will be able to get the appropriate experiences they are looking for when performing actions that the developers did not anticipate. But on the other hand, I have concerns when browsers add 'features' that fudge the lines between code that does work and code that shouldn't work.

What if we need to target handheld devices? I know we like to live in a world where everyone has a iPhone, but that's not reality. To apply a style specifically to handheld devices with a 15-character or narrower display I would do the following:

@media handheld and (grid) and (max-width: 15em) {

I should also note that handheld does not mean all mobile devices.

Intended for handheld devices (typically small screen, limited bandwidth).

MDN reference

The soapbox

We lived though this once already. It was called IE6 - IE9. Microsoft was known for putting browsers out there that catered to shitty code. When these things happen, most devs young and experiences will simply throw their hands up in the air and say, "Well, it's shitty but it works!" This is the core frustration with front-end development. There is no hard standard. There is a spec, but there is no official "this will break, this won't" standard of coding.

In JavaScript, if I write shitty code, it will cause problems. In Ruby, if I write shitty code, it probably won't work. The list goes on. In HTML and CSS, you write shitty code, the answer typically is, "Well, it looks ok in the browser?"

I'll get off my soapbox now, but I just want to say this. Regardless of the browser fudging the lines between what does work and what shouldn't, I say that we as professional still need to advocate for code that is explainable and consistent.

After all, what happens when you try and run your code through a browser that doesn't support this zooming pixel breakpoints non-spec 'feature'? You throw your hands up in the air and exclaim "This browser SUCKS!!! Why doesn't it do what all the others do?"