CSS Units: Stuff I wish Someone Had Told me

CSS Units: Stuff I Wish Someone Had Told Me

CSS Units: Stuff I Wish Someone Had Told Me

May 19, 2025 • Running on: caffeine overload & regret

Damn it. I just wasted another weekend fixing a website because I screwed up the CSS units. AGAIN.

Can I confess something? I've been building websites for over 10 years, and I *still* get confused about when to use px vs rem vs em. It's embarrassing. Like, I should know this stuff by now, right?

So last month I built this site for a law firm. Everything looked perfect... on MY screen. Then the client calls me all angry: "Your website's broken!" Turns out he had his browser font cranked way up, and my beautiful layout was a total mess - buttons overlapping text, things running off the screen, a complete disaster.

Yeah, I know. Totally preventable. So I'm writing this down partly to get it straight in my own head, and partly in case you're making the same stupid mistakes I keep making.

Quick note: I'm not writing some dry explanation of what each CSS unit is technically defined as. There's plenty of that boring crap online already. This is the practical stuff - when to actually USE each unit in real life, based on my own painful mistakes.

Why Should You Actually Care About CSS Units?

So for years I thought CSS units were just, like, a design detail. Y'know, 16px or 1em, whatever, just pick one and move on to the interesting stuff.

Turns out it's waaaaay more important than that. Here's the thing - when you pick the wrong CSS units:

  • Your site breaks when people change their font size (which more people do than you'd think)
  • Your "perfect" layout falls apart on different screen sizes
  • Your spacing gets all weird when people zoom in
  • People with disabilities can't use your site properly

My brother can't see well, so he cranks his browser font size WAY up. Half the websites he visits are completely unusable. "This text is cut off..." "I can't click that button..." "The form fields are overlapping..." It's awful. And it's because some developer (like me, too often) used the wrong CSS units.

I learned this lesson the hard way last year. A client's fancy new e-commerce site was losing sales because older customers couldn't use it with larger text. Literally LOSING MONEY because I was lazy with CSS units. Not a fun conversation to have.

Pixels: My Guilty Addiction

OK confession time: for way too long, I was a total pixel addict. I'd slap px units on everything. Headers, paragraphs, margins, padding... EVERYTHING was in pixels.

I mean, I get it. Pixels are super easy to understand. The designer says "make that space 24px" and you just type 24px. Done! No thinking required!

So. Many. Problems. With. This. Approach. Here's what nobody told me:

  • CSS pixels aren't even real pixels anymore (they're reference pixels that vary by device density)
  • When users change their default font size in the browser (which LOTS of people do), pixel values IGNORE that setting
  • Fixed pixel values are a total nightmare for responsive design
  • Pixels don't scale when they need to

Pixels are like concrete. Great for things that should NEVER change size (like a 1px border), terrible for everything else.

Here's some embarrassing code I wrote for a client site last year:

/* oh god why did I do this */
.site-header {
  height: 80px; /* ugh fixed height */
  padding: 0 20px; /* pixels everywhere */
}

.main-nav .link {
  font-size: 16px; /* face palm */
  margin: 0 24px;
  padding: 8px 12px;
}

Looks fine, right? Nope! As soon as someone increased their browser font size, the text got bigger but that 80px header height stayed the same. Text got cut off, things overlapped, it was a mess. So embarrassing.

Here's how I should've written it:

/* much better approach */
.site-header {
  min-height: 5rem; /* allows growth with text size */
  padding: 0 1.25rem; /* relative to text */
}

.main-nav .link {
  font-size: 1rem; /* scales with user preferences */
  margin: 0 1.5rem;
  padding: 0.5rem 0.75rem;
}

I still use pixels for tiny details though:

  • Border widths (1px just works)
  • Box-shadows (0 2px 4px rgba(0,0,0,0.1) etc)
  • Sometimes for really small fixed decorative elements

For everything else? I've kicked the pixel habit. Mostly.

EMs: The Sneaky Tricksters

God, ems confused me for SO long. They're supposed to be relative to font size, but they never seemed to work how I expected.

I'd try to use the same value in two different places, and get totally different results. Made me feel like I was going crazy.

The lightbulb moment finally came: ems are based on the PARENT element's font size, and they f***ing COMPOUND in nested elements.

I learned this while building a comment thread where I wanted each nested reply to get slightly smaller:

/* innocent-looking code that caused me hours of confusion */
.comment {
  font-size: 1em; /* sure, whatever the parent size is */
}

.comment .comment {
  font-size: 0.9em; /* I thought this meant "90% of the original size" */
}

The second level was 90% size as expected. But then the THIRD level wasn't 90% of the original - it was 90% of the ALREADY REDUCED second level (so like 81% of original). By level four, the text was tiny!

And here's the weird part about ems - when you use them for padding or margins, they're based on the font size of the ELEMENT ITSELF, not the parent. So:

/* this still trips me up sometimes */
.button {
  font-size: 20px;
  padding: 1em; /* this equals 20px, not the parent's font size */
}

After banging my head against this for years, I've found ems are actually perfect for:

  • Component padding that should scale with the component's own text
  • Spacing inside buttons, form fields, cards, etc.
  • When you actually want that compounding effect (like my nested comments)

REMs: Why Didn't Anyone Tell Me Sooner?

REMs are basically my best friend now, but it took me way too long to appreciate them. Honestly, I wish someone had just grabbed me by the shoulders years ago and screamed "USE REMS FOR ALMOST EVERYTHING!"

Here's the deal with rems - they're like ems but they ONLY relate to the root element's font size (that's the R in rem), which defaults to 16px in most browsers. They don't compound or do any of that tricky em stuff.

This is SO useful when the marketing team comes in with "can we make ALL the fonts a bit bigger across the site?" With pixels, you're manually updating hundreds of values. With rems, you just tweak the root:

/* before */
html { font-size: 16px; } /* default */

/* after - everything using rems gets bigger! */
html { font-size: 18px; }

I still remember this health insurance site I built where a lot of users were elderly. We used rems everywhere, so when they bumped up their browser font size, everything scaled perfectly - the text, the spacing, the form fields, everything. Compare that to the pixel-based nightmares I built before...

These days, this is how I start every project:

/* this has saved me SO many headaches */
html {
  font-size: 100%; /* browser default, usually 16px */
}

body {
  font-size: 1rem; /* base for the whole site */
  line-height: 1.5; /* unitless is best for line height */
}

h1 { font-size: 2.5rem; } /* 40px by default */
h2 { font-size: 2rem; }   /* 32px by default */
h3 { font-size: 1.5rem; } /* 24px by default */

Since switching to rems, I hardly ever use font-size media queries anymore. If I need a bigger base size on mobile, I can just adjust the html font-size in a media query, and everything scales.

Viewport Units: The Cool Stuff

I was way late to the viewport unit party. I first discovered them when a client insisted on one of those full-height hero sections that was so trendy a few years back.

I was doing dumb crap like this:

/* please don't judge me */
.hero {
  height: 700px; /* ugh, fixed height */
}

@media (max-width: 768px) {
  .hero {
    height: 500px; /* slightly less dumb fixed height */
  }
}

@media (max-width: 480px) {
  .hero {
    height: 300px; /* yet another fixed height */
  }
}

What a waste of time! Then I stumbled on viewport units and realized I could just do:

.hero {
  height: 100vh; /* full viewport height, boom, done */
}

Mind. Blown.

But the really cool thing about viewport units isn't full-height sections - it's fluid typography. Check this out:

/* this blew my mind when I first saw it */
.headline {
  font-size: calc(1.5rem + 3vw);
}

This gives you text that starts at 1.5rem and smoothly gets larger as the screen width increases. No media queries needed!

These days I'm obsessed with the clamp() function combined with viewport units:

/* this is like magic */
.headline {
  font-size: clamp(1.5rem, 1rem + 3vw, 3rem);
}

This basically says: "Never smaller than 1.5rem, never larger than 3rem, but scale fluidly in between." It's like having built-in constraints on fluid text.

Just watch out for the mobile browser "jumping viewport height" problem - when users scroll, the address bar can hide/show and change the viewport height. For critical full-height elements, you might need a JS fix.

What I Actually Do in Real Projects

After years of screwing things up, here's my current approach:

For Text:

/* base typography */
html {
  font-size: 100%; /* default, can be overridden by user settings */
}

body {
  font-size: 1rem; /* everything builds from here */
  line-height: 1.5;
}

/* responsive headings */
h1 {
  font-size: clamp(2rem, 1.5rem + 3vw, 3.5rem);
  /* smallest: 2rem (32px), largest: 3.5rem (56px) */
}
h2 {
  font-size: clamp(1.5rem, 1.2rem + 2vw, 2.5rem);
  /* smallest: 1.5rem (24px), largest: 2.5rem (40px) */
}

For Layout:

/* I got tired of inconsistent spacing */
:root {
  --tiny-space: 0.25rem; /* 4px */
  --small-space: 0.5rem;  /* 8px */
  --med-space: 1rem;     /* 16px */
  --big-space: 2rem;     /* 32px */
  --huge-space: 4rem;    /* 64px */
}

/* basic container */
.wrapper {
  width: 90%;
  max-width: 75rem; /* 1200px at normal size */
  margin: 0 auto;
  padding: var(--med-space);
}

For Components:

/* I use a mix for components */
.button {
  font-size: 1rem;  /* rem for the font size */
  padding: 0.6em 1.2em; /* em to scale with the button's text */
  border-radius: 4px; /* px for tiny details */
  border: 1px solid #333; /* px for borders */
  box-shadow: 0 2px 4px rgba(0,0,0,0.1); /* px for shadows */
}

My general rules are:

  • Font sizes → rems (always, no exceptions)
  • Padding inside components → ems (so they scale with the component's text)
  • Layout/page structure → rems and percentages
  • Tiny details like borders → pixels
  • Full-screen sections → vh/vw
  • Fluid text → clamp() with vw

Just Use REMs and Call It a Day

OK so if all this feels like too much, here's the TL;DR version:

Just. Use. REMs. For. Almost. Everything.

Seriously, if you switch all your font sizes, margins, and paddings from pixels to rems, you'll fix like 90% of the problems. You can optimize further later, but that's a solid start.

Remember, CSS units aren't about being perfect - they're about creating relationships between elements that can survive different conditions. Stop thinking so much about exact sizes and think more about how things should BEHAVE when conditions change.

And PLEASE, for the love of all that is holy, stop using pixel values for font sizes. Your users who need larger text (and future you who has to maintain your code) will thank you.

Now I gotta go fix that new project I started last week... yep, the one where I used pixels again because I was in a hurry. When will I learn?

P.S. - This px-to-rem conversion crap drives me nuts (like, is 22px... 1.375rem? 1.4rem? whatever). Finally broke down and bookmarked this CSS units calculator I found. Been a lifesaver, especially when I'm trying to match designs exactly.

Comments

Popular posts from this blog

Font Pairing Made Simple: How I Finally Stopped Making Typography Mistakes

JSON Formatter: The Tool That Saves Developers Hours of API Debugging

The Secret Power of Advanced Color Palettes: Real Results from Our Generator Tool

My Writing Got Better: How Text Analysis Changed My Work

The CSS Grid Generator That Finally Made Sense to Me

From Big Problem to Simple Fix: How I Made a Code Cleaner That Works

The CSS Units Converter That Finally Fixed My Responsive Design Problems

The Forgotten Math of Responsive Design: Why I Created the Aspect Ratio Calculator

Debugging Your Layout: How to identify and Fix Common CSS Grid Issues

CSS Shadow Techniques I Discovered While Building Our Shadow Generator