Typography

Typographic Contrast and Flow in Modern CSS

By Aigars Silkalns Updated 6 min read

Typographic Contrast and Flow in Modern CSS

Typographic contrast is the difference between the pieces of text on a page, and flow is the order in which the eye moves through them. You create contrast with six levers (size, typeface, color, case, weight and style) and flow with a seventh, space. Used together they make a page scannable, because readers skim for the heading, the key phrase and the next action before they commit to a paragraph.

The principles are the ones this article taught in 2007. What changed is the toolkit: variable fonts, fluid sizes with clamp(), OKLCH colors and better line breaking now do the work that image replacement, Flash and a handful of web-safe fonts once did. Below is each lever in modern CSS, then a before-and-after you can copy.

Two text cards side by side. The left one uses one size, weight and color for everything. The right one has a large bold serif heading, a small red uppercase label, muted metadata and a highlighted link.
Same words, left with no contrast, right with the five levers and spacing applied.

Why contrast matters more than the font you pick

Not every line on a page has the same value. A page where everything shouts, or where everything whispers, gives the reader no entry point. Contrast encodes priority: the biggest, heaviest, most colorful element reads first, the quiet ones read last. A reliable test is to squint at the page or blur a screenshot. If you can still tell what the three most important things are, the hierarchy works.

Choose two or three levels of emphasis per screen and apply them consistently. Contrast only works when it is rare, so every extra level dilutes the others.

A specimen sheet showing the same words changing in weight, size, case with tracking, color and style.
The levers on one sheet: weight, size, case, color and style.

1. Size: fluid, not fixed

Larger text signals higher priority, which is why headings are big. Smaller text signals support material such as captions and bylines. Instead of fixed pixel sizes per breakpoint, use clamp() so a heading scales smoothly between a minimum and a maximum.

h1 {
  font-size: clamp(1.75rem, 1.2rem + 2.5vw, 2.75rem);
  line-height: 1.1;
}
.meta {
  font-size: 0.875rem;
}

Mixing rem with vw inside the preferred value keeps the text responsive to the user’s own font-size setting, which a pure vw size does not. It is not a free pass, though: WCAG 1.4.4 (Resize Text) still requires text to scale to 200% without loss of content, and the W3C lists sizing text with viewport units alone as a failure (F94). Keep a rem term in the preferred value and test with browser zoom and a larger default font size. Aim for a clear step between levels, roughly 1.25 to 1.5 times, not a one-pixel difference nobody notices.

2. Typeface: pair by contrast, not similarity

In 2007 contrast between typefaces meant serif against sans-serif, because only a few fonts were safe, and anything else needed CSS image replacement or the Flash-based sIFR. Both techniques are obsolete. @font-face lets you load any licensed font, and variable fonts pack many weights and widths into one file. The mechanics are covered in our @font-face design guide.

The pairing rule still holds: combine two families that are clearly different, such as a serif headline with a sans-serif body, and avoid two that are almost alike, which looks like a mistake. Two families are enough for nearly any site.

@font-face {
  font-family: "Body Sans";
  src: url("/fonts/body-sans-var.woff2") format("woff2");
  font-weight: 100 900;   /* range declares a variable axis */
  font-display: swap;
}
h1, h2 { font-family: Georgia, "Times New Roman", serif; }
body   { font-family: "Body Sans", system-ui, sans-serif; }

Declaring a weight range tells the browser the file is variable, so font-weight: 350 or 650 works, not only 400 and 700. That gives you much finer contrast control than the old regular-or-bold choice.

Two details help when you pair faces. If the font has an optical size axis, font-optical-sizing: auto (the default) lets the browser pick the right design for each size, and you can set it by hand with font-variation-settings: "opsz" 48 for display headings. And when two families have different x-heights, font-size-adjust evens them out so the pair looks balanced at the same font-size, and a fallback does not jump when the web font loads. It is Baseline 2024.

body {
  font-family: "Body Sans", system-ui, sans-serif;
  font-size-adjust: from-font;  /* match x-height to the first available font */
}
h1 { font-variation-settings: "opsz" 48; }

3. Color: use OKLCH and check the ratio

Color separates navigation, headings, links and body text, fades what is disabled and lifts what is urgent. oklch() is a good fit for this because lightness is perceptually even: raising L lightens and lowering L darkens the same hue without a hue shift.

:root {
  --ink:    oklch(0.22 0.02 260);  /* body and headings */
  --muted:  oklch(0.48 0.02 260);  /* meta text */
  --accent: oklch(0.52 0.20 25);   /* links, labels */
}
p     { color: var(--ink); }
.meta { color: var(--muted); }

De-emphasis has a floor. Under WCAG 2.2, body text needs a contrast ratio of at least 4.5:1 against its background, and large text 3:1. Muted text that fails that is not subtle, it is unreadable. Only genuinely disabled controls are exempt.

4. Case: caps for labels, never for paragraphs

Uppercase draws attention and suits short labels, kickers and buttons. Set it with text-transform rather than typing capitals, so the underlying text stays normal for screen readers and search. Capitals need extra tracking to stay legible.

.kicker {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

Never set a paragraph in capitals. Word shapes disappear and reading speed drops. For animated headline treatments built on this idea, see our CSS animated text effects.

5. Style: italic for emphasis, underline for links

The old advice survives untouched: do not underline text that is not a link, because readers will try to click it. Use italic for emphasis, titles and foreign words, and keep underlines for links. Make links visible without relying on color alone, and offset the underline so it clears descenders.

a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}
a:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
}

In HTML, use <em> and <strong> for meaning and CSS for presentation.

6. Weight: bold the phrase, not the paragraph

Heavier weight creates emphasis, and the 2007 warning still applies: bolding an entire line cancels the emphasis because nothing stands out against it. Bold the two or three words that carry the point. With a variable font you can go beyond regular and bold. A heading at 700 with body text at 400 is a strong, safe baseline, and a semibold 600 label sits nicely between them.

7. Space: the lever that creates flow

Contrast says what matters, space says where to start, where to pause and where to go next. Every spacing tool has a CSS property:

Typographic term CSS Use it for
Block break margin, padding, gap Separating sections and cards
Paragraph break margin-block Rhythm between paragraphs
Leading line-height About 1.5 to 1.7 for body, 1.1 to 1.2 for large headings
Tracking letter-spacing Looser for caps, slightly tighter for big headings
Measure max-inline-size in ch Keeping lines around 45 to 75 characters
Indentation padding-inline Blockquotes and lists

Two newer properties help flow directly. text-wrap: balance evens out the lines of a short heading so it does not end on a single orphaned word, and text-wrap: pretty asks the browser to avoid awkward last lines in paragraphs. Both are progressive enhancements: if a browser ignores them, the text simply wraps the old way. Support is uneven, so treat them as such. balance works in current Chrome, Firefox and Safari (Baseline 2024). pretty is in Chrome and Safari 26 but not yet in Firefox, so it stays a progressive enhancement: the layout must hold up without it. Check MDN for the current table.

Put it together

This is the right-hand card from the first image. Five levels, two typefaces, one accent color:

:root {
  --ink: oklch(0.22 0.02 260);
  --muted: oklch(0.48 0.02 260);
  --accent: oklch(0.52 0.2 25);
}
.kicker { font: 700 0.75rem/1 system-ui, sans-serif;
          letter-spacing: 0.12em; text-transform: uppercase;
          color: var(--accent); }
h2      { font: 700 clamp(1.75rem, 1.2rem + 2.5vw, 2.75rem)/1.1 Georgia, serif;
          letter-spacing: -0.02em; text-wrap: balance; }
.meta   { color: var(--muted); font-size: 0.875rem; }
p       { max-width: 62ch; line-height: 1.6; text-wrap: pretty; }
a       { color: var(--accent); text-underline-offset: 0.2em; }

The order of reading is now obvious: label, headline, byline, body, link. None of it needed an image or a script.

Checklist

  1. Pick two or three levels of importance for the page, and name them.
  2. Give each level a distinct size, and add one more lever (weight, color or case) for emphasis.
  3. Limit yourself to two type families.
  4. Check body and muted text against 4.5:1 contrast.
  5. Keep paragraphs to a 45 to 75 character measure.
  6. Reserve underline for links and bold for key phrases.
  7. Test at phone width, where fluid sizes matter most.

For more CSS habits that pay off in the same way, read 20 pro CSS tips and 5 useful CSS tricks for responsive design.

75 comments from the archive
  1. Very well put and easy to read.

    I might just add that the cause of design clutter is trying to give equal prominence to a lot of items using one or more of the techniques presented in this article. The basic rule is: if you emphasize one item on a page, you need to de-emphaisize another.

  2. sIFR (Flash replacement)
    I wondered how other sites did it until you told us!

  3. Nice Article.

    Gives a short to the point round up of possibilities with type and some of the dangers… Especially on a site with multiple columns and different block of text the blance is always important.

  4. Really great article, all the bases that a webdesigner has to know in just 1 page.

    Great work and nice blog !

  5. Hey I like your blog and your articles are grate! But I think it schould be normal for a good designer, to pay attention to those basics… but nevertheless its a good and helpful article!!

  6. This is a wonderful writeup. I love to read about web typography, and you’ve summed up all of the most important points right here in one article.

    Your website is always a great read. I look forward to checking it every morning when I come in to work :) Thank you!

  7. Great post! Good typography tips are always good to read! Except tracking is the control of the space between characters in an entire line of text, Leading (led-ing) would be the space between lines of text. Good stuff!

  8. # Kerning (letter-spacing) is the space in between the characters.
    # Tracking (line-height) is the space in between the lines.

    This is incorrect, The correct Definitions are as follows:

    Kerning, is the space in between A PAIR of Letters, manipulation at this level is not really possible with standard HTML / CSS.

    Tracking, is the space between letters in a body of text. This is different than kerning, because kerning is just a pair of letters.

    Leading, is the space between to lines of text, and is set with the line-height attribute in CSS.

  9. Everything you publish on your site seems to go hand in hand with either what I am interested in at the time or something I want to learn more about…I’ve been looking around, studying source code and asking for feedback about my own typography, and wanting to improve my knowledge about it, and your article has helped me loads, thanks Nick!

  10. I don’t get what the point of this is. This is all common sense, this is a tutorial for beginners right? Cause everyone pretty much knows this stuff. Write something else that is more useful you nut.

  11. Now this is a good post! Its very informing and I am sick of people using horrible text. This is perfect and makes me want to make a very CSS based layout oh so soon!

    Good work, again!
    Nathan

  12. Great article, what amazes me is that your final design (where you bring it all together) looks exactly like the Scribbish theme I currently use. Great minds think alike eh? Great read, will be visiting often.

  13. another surperb article – dont normally post comments… but you keep coming up with such interesting posts/articles that i just wanted to say keep up the good work. You have help me out alot over recent months – so a big thank you!

  14. @Fearz
    Perfectly valid comment / opinion even if many may (and do appear to) disagree with you. That is until the last two words (you nut). That just devalued your comment, reducing any validity or credence anyone may have given it, and demeaned you into the bargain.

    And think a bit more before putting forehead to keyboard next time. You say “I don’t get what the point of this is.” But then you say (ask) “This is all common sense, this is a tutorial for beginners right?” so perhaps you were nearly there and you rather DO get the point.

  15. Excellent article, very interesting for me. The CSS to hide the text and replace with a background image is really nice !
    Thanks for sharing.

  16. @Fearz – I think this tutorial has helped me think about choosing fonts more carefully. Not just using anything I can think of at the time, or always using the same thing over and over.

  17. Good piece on some of the basics of typography. It seems to be a topic that’s finally getting some much needed attention from web designers. In addition to the things you highlight in the Space section of the post, I would also be tempted to do some playing around with the word-spacing properties. You can really improve the readability (or…scanability?) of your content with a bit of work there.

    On a side note, just wanted to say that I find the overall design of this site to be really inspirational and engaging.

  18. Certainly great hints and guidance. I find this very easy to understand. Thanks for putting this together.

    I’m currently creating a new layout for my website so I’ll be gathering various things from this site.
    Thanks

  19. Great job! This was a very precise and informative article. You should think about adding a Float button to your site, so people vote for your article on design float.

  20. According to the Windows User Interface guidelines (see ) disabled buttons have grayed out text, where enabled buttons have black (or default color) text. Most people are used to this, and that is why I would advise not to use gray text on buttons. Actually for best readability I would never use gray text, but it seems more popular than ever :-(.

  21. Good ideas about font types and contrast. It’s especially good for those (like me) who are starting out ;D

  22. Michiel van der Blonk raised important issues and I would like add one more:

    When small font size combined with lighter tone color, the importance of the text is further de-emphasized.

    Small fonts needs to have greater contrast to be readable and I would be very careful with this particular tip. Please use Colour Contrast Analyser tool/Firefox extension to check readability because small light grey letters are hard to see even on well calibrated monitors. Uncalibrated monitors can make it invisible and yes, invisible text is really not important ;)

    Overall this article is really good, thanks for sharing :)

  23. Good article. While I already practice these guildlines – I really needed something like this to share with others. Consider it bookmarked ;)

  24. This tips really good. It really help a lot.

    I got tips guys on how to make row and column. visit my blog.

  25. Yes, this is first axiom for great design work…:-)
    1. Contrast
    2. Justification
    3. Propinquity
    4. Repetition

  26. I check this site every day and no updates for 23 days :( What’s happening, Nick? Hope you’re ok!

  27. This is the good tutorials. I see some websites they do it very good.

  28. 可惜我看不懂英文.
    my English is poor .so sorry i like this page.

  29. Space plays the most important part in maintaining flow of your design. Good use of space will tell the reader where to start, when to pause, where it ends, and what to do next.

    I will remember this words add to my work. Some times I completely ignored this would help a lot to our design.

  30. Thank you for your great work and some ideas for the modern text structure.

    Ralph

  31. Typography is/was becoming one of the key ingredients of the big web design cookie. This article is well written and a very informative resource for understanding, how much typography matters.
    Thanks for your conclusion.

  32. Thanks for the nice article. Can you published the code for that last example screen shot you have put. The source will be really helpful to beginners.

  33. Con este post explicaste muchas cosas profundas. Si todo la gente van a respectar tu palabras vamos a tener un internet mas lindo! Gracias!

  34. Can you please put some example code for the last image you have put in conclusion section. It will be really helpful.

  35. thanks for this great post ; very clear, useful. I will stard to use some of your advices today !

    thanks

  36. Found you thru Annie at Blog U. It is sites like this and Annie among others that make me want to make creative changes on my site. You have a great talent. Thanks for sharing it! I will be visiting more often.

  37. all tutorials, tips and advices are greately appreciated,and very inspiring as well, esp.for a beginner like me who wants to be like you, i hope that anyone who finds it boring, or people who doesn’t appreciate effort of others, should keep quiet and refrain from talking like a mocking bird, air head like # 97, 96.
    show your talent dude….!!!

  38. simple typographic tips like this are always good to keep at the tip of a designers fingers even if you have been working for type for years, it never hurts to review the basics from time to time :)

  39. I like the tip where you mention:
    “Tips: avoid using uppercase in the body text or in long sentence because it will reduce readability.”

    It’s also important to remember that uppercase body text will also slow down reading.

  40. I’m definitely going to show this to some of my friends, definitely something that is essential to learn.

  41. I was in the process of creating a new case study on our website when I came across your website. It gave me a few ideas for my typography.

    Thanks!

  42. Outstanding post. I’m webdesigner but didn’t know about few things… I’m ashamed.

  43. This is very helpful info! I find myself actually doing most of these. I would like to see a post on typography but mostly analyzing quotes, sometimes, well a lot of times I have worked with adding testimonials, and sometimes I get bored doing so, some inspiration in this typography would be NICE.

    Awesome post!

  44. Typographic contrast and flow is a very important issue to keep in mind. Good post

  45. Nice post. Thank you very much. Can you write more articles with more details about this topic?

  46. I just stumbled on this article via Web Design Ledger. Great article!

    I still run across sites that underline non-link text and it drives me batty. I always hover over underline text (even if I don’t plan on clicking) just to see the hover effect. Must be a nervous habit…

  47. Please, fellow designers, for the sake of sanity — do not mix serif and sans-serif typefaces when creating art.

  48. 2. Typeface :
    sIFR now has 100% JS equivalents like Cufon (or @font-face + Cufon) provided that the license of the font used permits this use.

  49. Nice post. Thank you very much. Can you write more articles with more details about this topic?

  50. The designs showed here show what simple and tasteful design is all about. Another one to consider

  51. Your website is incredibly beautiful and useful. I have taken liberty to add this article to my CSS aggregator site. I hope you wont mind that.

  52. Very nice article.

    Will use these tips in my own startup website (www.phonecurry.com) – it currently has good functionality but lacks seriously in design. I am therefore trying to learn good design practices online and your site has been very useful.

    Thanks!

  53. Very nice article…I have one question.

    What is that method called where colour or font style is used to break one word into two…
    for example…
    if the word “Example” is written… then the words ‘AMPLE’ within it, will be written in a different colour or font…. so that the person reads both…. and to make user read it as “Ample Example” the size of “Ample” would be bigger than the rest of the letter i.e. e and x, in this case….

    Does anybody know it?

  54. nice tut! im a newbie and this opens my mind about typography..i will put you on my tutorial page in my website, hope that’s ok? thanks again!

  55. Recently i am looking fot the white iphone 4 conversion kit. If you have any recommendation, plz tell me. I will be very grateful!

  56. I just heard the gossip that since there’s some technic problems on white iphone 4, iphone 4b is going to release. It that true?

  57. As much as the choice of type is important, the appropriate use of typographic measurements and white-space is an important tool of the trade when setting type for the web.

  58. Yup. Contrast does work to call attention. I prefer using bold and bright colors…

  59. Contrast does work for lengthy articles or pieces. Thanks for this tip.

  60. Excessive fear, anger, and work under stress last pregnancy, infants can lead to excessive hassaslığa. Intense emotions, going through the mother’s blood circulatory system and brain functions that affect the baby in some leads to the release of chemical

  61. You was talking about using italic font instead of underline for emphasizes.

    Well italic font does not really cut it for emphasizes.

    I have tried bold for verdana font. And it just looks ugly.

    There are places in sentences and words that no one would expect to be a link. If so, they would be a prime candidate for underline text.

    Or how about using ‘underline text’ for extra emphasizes.

    The only other choice is color. As you know a different color text means a link. And yet I see you use color text in this web page.

    The worst thing that can happen is the reader finds out it is not a link.

    So what other choices do we have when it comes to emphasizing words besides underline?

    1. LOL that was the most illogical argument ever. It’s ok to use underline (which is ALWAYS rendered for a link), but it’s not ok to use color because that could possibly maybe mean it’s a link? Don’t cross a side street, you might get run over by a car. I recommend crossing highways instead!

  62. I have learned result-oriented things out of your blog post. Yet another thing to I have noticed is that typically, FSBO sellers can reject a person. Remember, they can prefer to not ever use your providers. But if you actually maintain a comfortable, professional connection, offering assistance and being in contact for about four to five weeks, you will usually be capable to win a discussion. From there, a house listing follows. Thank you

  63. Good stuff.. typography is really important. A lot of start-up web designers aren’t familiar to this, but like me, as i go along, learning and discovering sites like this, I tend to realize that I still have lots to learn, even the basic ones that creates big impact on web design. Thank you for sharing this Nick.. :)

Comments are closed on this article.