Recently I’ve come into existing projects that were not written to be responsive and added responsive styles to them. As much as I try to keep things clean, DRY, and organized, my media queries often end up being a mess of overrides and redundancy.
When I recently had the opportunity to work on a responsive feature from scratch, I decided to really make an effort to keep things tight. I learned some stuff in the process and abstracted it out to the demo that follows.
Let’s pretend for demo purposes that I’m shopping for a new credit card, and am presented with several to choose from. Each card is represented by a box (I’m calling it a “tile”) that shows its details. Each card is backed by a different company, and has its own interest rate and credit limit. I worked from this design mockup and knew the client wanted to adhere to it very closely:
But the mockup only represented a medium desktop-sized version, and I knew this thing would need to scale across many devices and resolutions. I realized because this layout was kind of complex, the most important thing would be for all these elements (image, text, lines, spacing) to maintain the same relative proportions, and scale up and down all together.
There are a few different units we can use to size things on the web. My unit of choice here is the em, which represents the size of an element relative to its parent element (the term “em” comes from the same source as the “em dash,” in that both are based on the width of the lower-case letter “m”). Most of the time, the parent is the body of the page, so 1em is equivalent to the default font size for the browser. But if you put your element inside a container and set the font size of the container, the element inside will take its sizing instructions from the that parent. (This is different from the rem unit, which is always relative to the root element, the
Starting with a base font size of 16px, I wrote the markup and styled the tile to be as close to the mockup as possible. Yeah, I know I used a table. But this is kind of tabular data, right? And it was the simplest way to achieve the fluidity and vertical alignment I needed. There’s no shame in my game.
So with everything in the tile looking good, and each element sized and padded in a proper, relative way, I added media queries to cover other resolutions. And all I had to do was add one rule for each size. On larger screens, scale up the base size to 20px. On smaller screens, scale it down to 14px. On extra-small screens, make it 4.0vw.
On extra-small screens, which I’m assuming are phones, I’m defining the base font size in vw’s, which is actually another relative unit. But this unit, a pretty recent addition to CSS, is relative to the size of the viewport. It’s pretty well supported, too, but since I’m really just concerned about phones at this resolution, I can assume the browser is modern.
I wanted this relative-to-relative sizing because on extra-small screens, we dispense with breakpoints and the layout goes 100% wide and fluid, so the most useful parent container is the viewport itself. It took some trial and error to find the right measurement, but you’ll see if you resize the demo window between 0px wide and 479px wide, the font size is completely fluid, and remains in proportion all the time.
So: write markup once. Write styles once. Make it responsive by changing one rule at each breakpoint. Squeaky clean, dry as a bone.
image credit: Official M.C. Escher website.