惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - Franky
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
IT之家
IT之家
J
Java Code Geeks
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
W
WeLiveSecurity
B
Blog RSS Feed
V2EX - 技术
V2EX - 技术
H
Heimdal Security Blog
S
Security @ Cisco Blogs
博客园 - 叶小钗
月光博客
月光博客
Webroot Blog
Webroot Blog
H
Hacker News: Front Page
N
News and Events Feed by Topic
P
Proofpoint News Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Help Net Security
Help Net Security
S
Secure Thoughts
SecWiki News
SecWiki News
Last Week in AI
Last Week in AI
Hugging Face - Blog
Hugging Face - Blog
S
Schneier on Security
A
Arctic Wolf
博客园 - 司徒正美
T
Tor Project blog
T
Tenable Blog
量子位
D
DataBreaches.Net
PCI Perspectives
PCI Perspectives
T
The Exploit Database - CXSecurity.com
T
Threatpost
小众软件
小众软件
博客园 - 三生石上(FineUI控件)
Cloudbric
Cloudbric
T
The Blog of Author Tim Ferriss
N
News | PayPal Newsroom
Project Zero
Project Zero
S
Securelist
Forbes - Security
Forbes - Security
Hacker News - Newest:
Hacker News - Newest: "LLM"
B
Blog
L
LINUX DO - 热门话题
Security Archives - TechRepublic
Security Archives - TechRepublic
O
OpenAI News
C
Cisco Blogs
V
V2EX
P
Privacy & Cybersecurity Law Blog
Cisco Talos Blog
Cisco Talos Blog

CSS Wizardry

Front-End’s Missing Metric: The TBT Window Meet Your Users Where They Are with Obs.js Better Browser Caching with No-Vary-Search font-family Doesn’t Fall Back the Way You Think What Is CSS Containment and How Can I Use It? When All You Can Do Is All or Nothing, Do Nothing Obs.js: Context-Aware Web Performance for Everyone Low- and Mid-Tier Mobile for the Real World (2025) The Fastest Site in the Tour de France Making Sense of the Performance Extensibility API Why Do We Have a Cache-Control Request Header? HTML Is Not a Programming Language… Build for the Web, Build on the Web, Build with the Web Licensing Code on CSS Wizardry A Layered Approach to Speculation Rules Designing (and Evolving) a New Web Performance Score Core Web Vitals Colours The Ultimate Contract Templates for Tech Consultants: Protect Your Business and Get Paid Optimising for High Latency Environments Cache Grab: How Much Are You Leaving on the Table? blocking=render: Why would you do that?! Correctly Configure (Pre) Connections The Three Cs: 🤝 Concatenate, 🗜️ Compress, 🗳️ Cache What Is the Maximum max-age? How to Clear Cache and Cookies on a Customer’s Device The Ultimate Low-Quality Image Placeholder Technique Core Web Vitals for Search Engine Optimisation: What Do We Need to Know? The HTTP/1-liness of HTTP/2 In Defence of DOM­Content­Loaded Site-Speed Topography Remapped Why Not document.write()? Speeding Up Async Snippets Critical CSS? Not So Fast! Measure What You Impact, Not What You Influence Optimising Largest Contentful Paint Measuring Web Performance in Mobile Safari Site-Speed Topography Speed Up Google Fonts Real-World Effectiveness of Brotli Performance Budgets, Pragmatically Lazy Pre-Browsing with Prefetch Making Cloud.typography Fast(er) Time to First Byte: What It Is and How to Improve It Self-Host Your Static Assets Tips for Technical Interviews Cache-Control for Civilians Bandwidth or Latency: When to Optimise for Which ITCSS × Skillshare What If? CSS and Network Performance The Three Types of Performance Testing Getting to Know a Legacy Codebase Image Inconsistencies: How and When Browsers Download Images Identifying, Auditing, and Discussing Third Parties My Digital Music Setup Measuring the Hard-to-Measure Finding Dead CSS The Fallacies of Distributed Computing (Applied to Front-End Performance) Ten Years Old Relative Requirements Airplanes and Ashtrays Performance and Resilience: Stress-Testing Third Parties Refactoring Tunnels Little Things I Like to Do with Git Writing Tidy Code Configuring Git and Vim Base64 Encoding & Performance, Part 2: Gathering Data Base64 Encoding & Performance, Part 1: What’s Up with Base64? Code Smells in CSS Revisited Typography for Developers Moving CSS Wizardry onto HTTPS and HTTP/2 Ack for CSS Developers A New Year, a New Focus Preparing Vim for Apple’s Touch Bar Choosing the Correct Average CSS Shorthand Syntax Considered an Anti-Pattern CSS Wizardry Newsletter Nesting Your BEM? Improving Perceived Performance with Multiple Background Images Continue Normalising Your CSS Pure CSS Content Filter Pragmatic, Practical, and Progressive Theming with Custom Properties Refactoring CSS: The Three I’s Speaker’s Checklist: Before and After Your Talk Improving Your CSS with Parker The Importance of !important: Forcing Immutability in CSS Mixins Better for Performance Managing Typography on Large Apps White October Events Workshop Partnership BEMIT: Taking the BEM Naming Convention a Step Further Travelling Like You Want to, When You Have To Contextual Styling: UI Components, Nesting, and Implementation Detail Subtleties with Self-Chained Classes Cyclomatic Complexity: Logic in CSS Immutable CSS Can CSS Be Too Modular? More Transparent UI Code with Namespaces When to use @extend; when to use a mixin The Specificity Graph CSS Wizardry Ltd.: Year 1 in review
Pragmatic, practical font sizing in CSS
Harry Roberts · 2012-03-01 · via CSS Wizardry

Written by on CSS Wizardry.

Table of Contents

Independent writing is brought to you via my wonderful Supporters.

  1. Double-stranded heading hierarchy
  2. Extending this?
    1. Preset font sizes
    2. Non-standard font-sizing
    3. Going the other way?
    4. Vertical rhythm
  3. Bringing it together
  4. Where does that leave us?

One thing I’ve been thinking a lot about lately is how to build sites properly. Not what we have been told is proper, but what actually makes sense for us as developers. I recently spoke at The Digital Barn on exactly this; my talk—Breaking Good Habits—dealt with how we as developers need to solve problems not only for our users and clients, but for ourselves as well.

Nicole Sullivan has laid a lot of new foundations for us in her work on OOCSS and her ‘unconventional’ but absolutely spot-on approach to building websites. Gems like the media object have seriously changed how I build websites and, if you take the time to study it for yourself, I think it might just do the same for you as well.

Double-stranded heading hierarchy

Another absolutely stellar nugget of wisdom she’s given us is what I call double-stranded heading hierarchy. This is the practice of defining a class every time you define a heading in CSS.

For example, if—for whatever reason—we want our h2s in our sidebar to be the same size as a h1, and the h4s in our footer to be the same size as a h3, we might have had some code like this:

<div class=content>
  <h1>Lorem</h1>
</div>

<div class=sub-content>
  <h2>Lorem</h2>
</div>

<div class=footer>
  <h4>Lorem</h4>
</div>


h1,
.sub-content h2 { [font styles] }
h2 { [font styles] }
h3,
.footer h4 { [font styles] }
h4 { [font styles] }
h5 { [font styles] }
h6 { [font styles] }

But now we’d have:

<div class=content>
  <h1>Lorem</h1>
</div>

<div class=sub-content>
  <h2 class=h1>Lorem</h2>
</div>

<div class=footer>
  <h4 class=h3>Lorem</h4>
</div>


h1,.h1 { [font styles] }
h2,.h2 { [font styles] }
h3,.h3 { [font styles] }
h4,.h4 { [font styles] }
h5,.h5 { [font styles] }
h6,.h6 { [font styles] }

As you can see, the former is far more arbitrary and those lists of selectors can soon become unwieldy, especially over a larger project. By assigning a class along with each heading style we now have those styles attached to a very flexible selector that can be moved anywhere, rather than to a very specific and non-movable one.

Now, I’m not such a fan of the .hN notation, I much prefer a solution that I believe to have been suggested by Mr Jeremy Keith, and that is to use abstract classes made up of the first six letters of the Greek alphabet, thus:

h1,.alpha   { [font styles] }
h2,.beta    { [font styles] }
h3,.gamma   { [font styles] }
h4,.delta   { [font styles] }
h5,.epsilon { [font styles] }
h6,.zeta    { [font styles] }

Which now gives us:

<div class=content>
  <h1>Lorem</h1>
</div>

<div class=sub-content>
  <h2 class=alpha>Lorem</h2>
</div>

<div class=footer>
  <h4 class=gamma>Lorem</h4>
</div>

Neat, huh?

So now .alpha can carry the style information of a h1 wherever you wish; it doesn’t depend on location or a type of element. A double-stranded heading hierarchy; lovely.

Extending this?

Okay, so now we have our heading styles all nice and portable we’ve won most of the battle. I’ve been using this method for months now and I love it. My CSS is so much more efficient, more portable, more powerful, I can build faster, I’m not repeating font styles over and over, but what next?

The other night whilst working on faavorite with Nick I came up with a full on font-sizing micro-framework.

The problems I found I had with font-sizing on any site include (but are not limited to):

  • Repetition of font-size, line-height etc declarations.
  • Overly-specific and/or location-dependent selectors (e.g. .sidebar h2 {}).
  • Arbitrary font sizes could and did creep into my CSS.
  • When using rem with px fallbacks, there is a lot to type!

And a few important things to remember:

  • Font sizes, like colour palettes, should be limited, preset and non-arbitrary.
  • Vertical rhythm is important and easy.
  • DRY code is important for both efficiency and maintainability.
  • It’s important to save yourself as much time as possible.
  • Classes are neither semantic or insemantic.

With this in mind, I decided that I wanted to use font-sizing much like a grid system; define it once in the stylesheet and just constantly reuse it.

Preset font sizes

Like colour palettes are, font sizes should be strict, predefined and intentional. From both a code and design point of view, you shouldn’t deviate from your scale—you shouldn’t really ever need to and doing so will just make code harder to work with.

Presetting your font sizes is pretty easy; typically you might have requirements for:

  • Normal body copy
  • Headings 1–6
  • Small print
  • A few other sizes for larger-than-normal headings etc.

Setting the base font size is simple, just pop it on the html and everything will inherit it, paragraphs, lists, tables, you name it.

For your headings you define a series of hN and its corresponding Greek letter class, e.g. h1, .alpha {}.

Non-standard font-sizing

You ever had that need to turn a design up to 11? When you have a masthead promo and even a h1 ain’t big enough? I think we all have…

It’s tempting to create a new, unique selector to cater for this new requirement, perhaps something like:

.masthead h1 { font-size:5em; }

And whilst this will work, you’ll only ever get that 5em goodness if you use specifically a h1 that is specifically in a .masthead. This isn’t very reusable at all. Sadface.

To combat this, I decided to create some new abstract classes, this time borrowing SI prefixes. Now we have the h1, .alpha {} through to h6, .zeta {} that we did before, but as well as those we have:

.giga { [font styles] }
.mega { [font styles] }
.kilo { [font styles] }

These classes are the ones above h1 and are the seldom used ones that make stuff massive!

Going the other way?

Okay, so far we’ve worked with body copy to headings to beyond; what about small print? Well I opted to use:

small,.omega.milli{ [font styles] }

small has been redefined in HTML5 so that’s an element we can use again freely and .omega is simply the last letter in the Greek alphabet.

Addendum

Tom Hudson suggested I use .milli for this as it goes below the regular scale. So, anything on the normal scale is Greek letters, anything off the scale (above or below) is SI prefixes.

Vertical rhythm

To maintain vertical rhythm we need two key ingredients; consistent line heights and consistent bottom margins. We need a magic number. This number is typically defined by the line height of your body copy, so if you have html { font-size:16px; line-height:1.5; } then your magic number is 16 x 1.5 = 24.

Now you know that all your line heights and margin bottoms have to be a multiple of 24px.

Bringing it together

It really is imperative to take a look at an actual example of all the above brought together in order to fully ‘get’ it. I made this jsFiddle demo of just CSS; you can add HTML and tinker with it yourselves, combining elements with classes to create double stranded, portable font sizing framework stuff!

Where does that leave us?

We now have a self-contained font-sizing framework which should hopefully mean we never need to define another font-size declaration again! We can manage our brand specific type rules from one place, we can build stuff faster, we can build faster stuff, we can keep our code DRYer, we can keep our styling a lot more consistent, we can keep styling location _in_dependent and we can make far reaching changes in one fell-swoop!

Feel free to take the code and modify or improve it.

Also please note that I am not suggesting we all use these specific classes; experiment, find your own, see what you’re comfortable with and report back!