Grow your CSS skills. Land your dream job.

Viewport Sized Typography

Published by Chris Coyier

CSS3 has some new values for sizing things relative to the current viewport size: vw, vh, and vmin. It is relevant to bring up now, because it's shipping in Chrome 20 (canary at the time of this writing). And not behind a flag, it just works. Production usage isn't quite there, but it will be soon enough.

Why is this awesome?

There are many reasons. Here are two:

  1. There is a such thing as a comfortable line length for reading text on screens. I don't want to kick a hornet's nest, but let's say its around 80 characters. These units allow you to get it feeling perfect and then have that experience scale to any size screen.
  2. They allow you to tightly couple the size relationship of, say, a typographic header and the content it goes with. Like your classic Trent Walton style blog post.

How they work

One unit on any of the three values is 1% of the viewport axis. "Viewport" == browser window size == window object. If the viewport is 40cm wide, 1vw == 0.4cm.

For use with font-size, I guess it's one "letter" that takes on that size, but as we know, in non-mono-spaced fonts the width of a letter is rather arbitrary. I find you just need to tweak around with the values to get it how you want it. Which is basically what we do anyway, right?

1vw = 1% of viewport width
1vh = 1% of viewport height
1vmin = 1vw or 1vh, whichever is smaller
1vmax = 1vw or 1vh, whichever is larger

Using them

Easy cheezy:

h1 {
  font-size: 5.9vw;
}
h2 {
  font-size: 3.0vh;
}
p {
  font-size: 2vmin;
}

Demo

Here's a video of a simple layout using vw units for the font-size.

Check out the demo yourself (see browser support).

Or here's a GIF for a super simple header:

Bugs!

The support is there in Chrome 20+ / Safari 6+, but it fails in one rather significant way. When the browser window is resized, the font doesn't adjust itself according to the new viewport size. The spec says:

When the height or width of the viewport is changed, they are scaled accordingly.

I bugged it. It's fixed in Chrome... 34? But still an issue in Safari. Perhaps not a huge disaster as it's pretty much just us design nerds that go around adjusting browser windows, but still. The font does adjust on a fresh page load.

To fix this issue (allow resizing without page refresh) you need to cause a "repaint" on the element. I used jQuery and just fiddled with each elements (irrelevant, in this case) z-index value, which triggers the repaint.

causeRepaintsOn = $("h1, h2, h3, p");

$(window).resize(function() {
  causeRepaintsOn.css("z-index", 1);
});

Browser Support

IE 10+, Firefox 19+ - Supported

Chrome 20+, Safari 6+ - Supported but has repaint issue

iOS 6+ - Supported but I'm not sure how relevant repaint issue is (does viewport size change on orientation change?)

Most notably no support in Android yet.

Not just font-size

For the record, these are just units. Just like em, px, whatever. You can use them on anything, not just font-size.

I think font-size is the most compelling use case, since things like margin, padding, and width can already essentially react to browser window size by using % units. There is the case where perhaps a more deeply-nested element needs to react to the browser window size instead of its direct parent size.

Using it now

Native usage

You'll at least want to provide a fallback:

h1 {
  font-size: 36px; /* Some tweener fallback that doesn't look awful */ 
  font-size: 5.4vw;  
}

Testing for support

Modernizr doesn't have a test for it yet, but you can test for it yourself by using some throw-away element that you see to some narrow width in CSS but then re-set to 100vw in JavaScript, then measure to see if the width of it is equal to window.width. Something like:

var testEl = $("#vw-test");

testEl.css({
  width: "100vw"
});

if (testEl.width() == window.innerWidth) {
   // Supported
} else {
   // Not Supported
};

Here's that test on CodePen, but note it only works in Full Page view otherwise the calculation might be off because of iframe issues.

Mimic the functionality with FitText.js

This idea of binding the overall width of a header with the width of its parent element is exactly what FitText.js does. Only it does it through fancy JavaScript and math and spans and stuff. Theoretically, you could run the test and use Modernizr.load to load up FitText.js if no support is detected.

More Information

Comments

  1. Very nice! That’s a step forward for web typography layouts.

  2. William malo
    Permalink to comment#

    I made this a few days ago:

    onresize=onload=function(){document.body.style.fontSize=window.innerWidth+”px”}

    • Chuck

      This works but how would you stop it at a minimum size because it gets too small in smaller screens.

  3. William malo
    Permalink to comment#
  4. Permalink to comment#

    Thats a pretty interesting idea, but but could you not do almost the same thing with media queries?

    • Yes, but it would look choppy. With transitions, it isn’t so bad, but you need a lot of media queries then and that means lots more CSS fat to deal with.

      I’m looking forward to being able to use this.

  5. David
    Permalink to comment#

    This seems to work on Safari 5.2 (Beta 3) [Version 5.2 (7536.6.1)]

  6. If you are maintaining a line length of 80 characters regardless of screen size, wouldn’t readability become an issue on smaller screens?

    When I view this site on my mobile I get around 40 characters per line and that is small enough, I can’t imagine being able to read the content if it was scaled down to fit 80 characters per line.

    • Sure, but I think the use would be for those “in-between” media queries, or for when that client is a stickler.
      Otherwise, you are exactly right, this just turns into the device-zoom all over again.

    • cnwtx

      True, but I think he was talking more about, say, 1800px wide screens that you would get something like 250 characters per line, which would be very hard to read.

    • James

      That was such a stupid example of how to use this – unreadably tiny fonts on a small screen, or gigantic ones on a large screen – please don’t use this for anything other than headings!
      As an aside, how is this then affected if the user deliberatly re-sizes the screen font?

  7. VW and VH also work in IE9 though it uses VM rather than VMIN.

  8. This is way too cool!

    h1 {
      font-size: 5.9vw;
    }
    h2 {
      font-size: 3.0vh;
    }
    p {
      font-size: 2vmin;
    }

    wondering how to get this working with a slider to change font size on website

  9. What a kludge! If you’re going to resort to jQuery to implement a styling choice it should support a lot more browsers.

  10. Patrick Down

    This is good but line character length isn’t the only issue with text readability. Actual physical line length is also important. It can be harder to read text when the eye has to travel a farther distance back to the beginning of the next line. I’d like to see sites that can switch between one or two column layouts when resizing the browser width.

    • Patrick is right. The bigger issue for ease of reading is how much the eyeball needs to rotate back and forth in its socket to read the text. On large screens, this technique will make reading hard very quickly. And on small screens (as someone mentioned), the text will be far too small to read.

      That’s not to say that there isn’t a range where this will be useful, but I don’t think it’s going to make things significantly easier to read.

    • Santosh Kumar
      Permalink to comment#

      Hi,

      You are right, i also saw this problem….

  11. This is awesome proof that the responsive design techniques WE created with CSS is now being appropriated and improved natively by the CSS development community!

  12. Julian Cizmic

    Ironic how IE is now ahead in the CSS3 race…

  13. I can’t wait to see what uses people come up with for this and calc together.

    • Hans
      Permalink to comment#

      Have someone found a polyfill for supporting Chrome (viewports units and calc) ?

  14. I want to use it now lol

    love new CSS3 Specs.

    and I agree with Julian IE10 is taking major hurdles.

  15. Exciting!!

  16. The demo looks like it’s working for me in Chrome 19 beta. Can anyone else confirm?

  17. Lukas

    em’s?

    Why not to use font sizing (and everything else) in em’s?

    Just play with base font size and you get basically the same result For now JS can do the job in a few lines, calc() could do this in near future.

    The bonus of em’s are that its easy to have min/max limits. Imagine you develop something in vh or vw on 23″ screen, and then what same thing on 6″ smartphone, it does mean we get 4x smaller element. So anything on readable 24px size on desktop becomes 6px “hidden text”?

    Or I’m missing something?

    • One word – simplicity. Ems are great for that stuff, but generally, it’s much easier to use pixels.

      For some developers, though, it’s worth the extra hassle.

    • Lukas

      I was more like em’s vs vh’s, rather than px vs all relative stuff.

      My point was more like by using em’s and base font size we could get non-linear scaling, like getting it bigger slower on big screens and faster on small.

      By the way, aren’t px kind of responsive by now? I mean if you set up 12px font on iPhone retina display, it definitively wont be actual 12px, but scaled up based on DPI…

  18. Very nice.

  19. Very cool, I can really see a need for a responsive text sizing that isn’t effected by cascading…

  20. Interesting demo, but is should be used with care. I see the use for this mainly for headline scaling, for paragraph text it shouldn`t be used.

    1em = 16px, the browser default font size is a perfectly legible size. Even larger sizes can work well depending on the used font.

    I often encounter responsive websites which scale down the paragraph font-size to 14px or even less in the mobile layout.

    Larger line-width + decreased font size = Very bad very legibility, especially since there are usually no tools to increase the font-size on a mobile browser.

    Just my 5cent.

  21. Jeremy Lawson

    This is a great new tool in the impressive css3 spec.

    There are plenty of cases where using this isn’t appropriate, but you don’t have to do every job with your 1 shiny new screwdriver. Carry on using px, %, (em, ex, ch, rem, cm, mm, in, pt, pc, px).

    I’d like to see how it pans out on the iPhone. Will 1vh be 1% of the screen height, or the viewport height?

  22. Finally :) it was somewhat expected that something like this should be made “mainstream” in light of the responsive design frenzy :) for me a bit overdue, glad its here

  23. I cannot wait to see this fully supported….in a few years :_(

  24. It’s fantastic…

    …every day goes the web a bit better!

  25. > For use with font-size, I guess it’s one “letter” that takes on that size, but as we know, in non-mono-spaced fonts the width of a letter is rather arbitrary.

    My guess is that the em would be the letter that takes on the size. I’m sure you could work it out with a ruler and a magnifying glass!

  26. I think we can do it something like this (not exactly) by using em instead of px, isn’t that?

    • Jeremy Lawson

      ems are actually relative to other font-sizes, Jimba. There wasn’t a CSS way to get any font-size to be relative to the size of it’s container.

  27. Great technique, however I see one problem here: the font-size gets too tiny for small devices. Because, when I have a text with a size of 13px it’s big enough for a widescreen device but also appropriate for a mobile device.

    But if the text gets resized accordingly to the screen size it will eventually be at 8px or something at a narrow screen. So you will still have to alder the font-size there. I may be wrong here, but that’s the first thing that came into my mind when I saw your video.

  28. Mathieu

    I am glad to see this move to more fluid design. The popularity of fixed design over the years has been agonizing! Designers are finally realizing viewports are not all the same size, and designing as if the page was on paper is limiting and frustrating to many users.

  29. Fred

    What about min-font-size ?

    With javascript, it’s possible :

    http://blog.evolya.fr/public/divers/demo-textsize/demo-textsize.html

    (In source code)

    • Jeremy Lawson

      You can use viewport-relative font sizes without compromising design on low resolution devices.

      Using CSS media queries you can provide a minimum font size for low resolution devices.

      body { font-size: 1vw; }
      @media screen and (max-width: 1000px) {
      body { font-size: 10px; }
      }

      This sets the font to be 1% of the viewport width.
      e.g. at 1280×1024 the font-size will effectively be12.8px.

      But if the viewport width is 1000px or less, the font-size will stick at 10px.
      e.g. at 800×600 the font-size will be 10px, and NOT 8px, as you’d expect from 1vw.

      If you have a browser which supports it (I use Google Chrome’s Dev channel), you can try it out below.
      e.g. Shrink the window up small, and toggle between fullscreen and windowed mode.

      
      <!DOCTYPE html>
      <html>
      	<head>
      		<title>Testing Viewport-Relative Sizes
      		<style>
      			body { font-size: 1vw; }
      			@media screen and (max-width: 1000px) {
      				body { font-size: 10px; }
      			}
      		</style>
      	</head>
      	<body>
      		<div>Hello World</div>
      		<div style="font-size:1vw;">Hello World (control: forced to 1wv)</div>
      		<div style="font-size:10px;">Hello World (control: forced to 10px)</div>
      		<div style="width:1000px; background-color:red; text-align:center;">(control: 1000px width box)</div>
      		<div style="width:1280px; background-color:green; text-align:center;">(control: 1280px width box)</div>
      	</body>
      </html>
      
  30. I’m using FitText in a blog and it works very well (even on mobile devices)! But this one looks promising! Thanks for share…

    • At FitText website it’written:

      “Oh, and don’t you dare let us catch you using FitText on paragraph text. This is for gigantic display text only!”

      Loved that kkkkkkk

  31. When can we use it on iOS or Android?

  32. I made this a few days ago:

    onresize=onload=function(){document.body.style.fontSize=window.innerWidth+”px”}

    what’s about it?

  33. I like css3 and stuff, but when wil this work in all browsers …

  34. Ben

    Awesome stuff. But I have to say the possibilities that come to my mind for this unit have less to do with type, and more to do with responsive animation and graphics. The chief downside of specifying a font-size in something other than ems is that it almost certainly invites weirdness with user-initiated zooming. This ain’t for body text, folks. Let’s not go down this rabbit hole. Stick with ems and media queries.

    But it’s great to be able to specify an nifty animated element’s width in terms of the viewport’s width, and not just in terms of a percentage of its parent container. Even more awesomely, you can mix and match height and width: spec both an element’s height and width in terms of just the viewport height, etc. Tons of responsive sizing possibilities here.

  35. Jon Spencer

    Awesome! Thanks. Implemented it today on a new dev. :)

  36. Alfred Larsson

    Awesome. It works in chrome 19 :D
    (which was released this week)

  37. Ben

    Chris– playing with this a bit more and looking at the W3 spec, one glaring omission comes to mind: why is there no ‘vmax’ unit? Only ‘vmin’?

    Once people really dig into the this stuff, if you’re really trying to design for both vertical and horizontal screens, you know there’s going to be a time when we wish you had it in your toolkit. Any insight as to why this has been left out of the spec? Hey- if browsers can support one comparison natively why can’t they support the other?

    A quick search for “vmax css” turns up zero discussion on the topic. Hmmm…

  38. hugo

    I use that code and after I make my declaration in EM.

    @media only screen and (min-width: 480px) {
    	body { font-size: 12px;}
    }
    @media only screen and (min-width: 768px) {
    	body { font-size: 13px;}
    }
    @media only screen and (min-width: 1000px) {
    	body { font-size: 14px;}
    }
    @media only screen and (min-width: 1170px) {
    	body { font-size: 15px;}
    }
    @media only screen and (min-width: 1340px) {
    	body { font-size: 16px; }
    }
    @media only screen and (min-width: 1580px) {
    	body { font-size: 17px; }
    }
  39. Nathan
    Permalink to comment#

    Really cool! Though I am curious why you used different units, i.e., vw and vh for h1 and h2 elements respectively? Depending upon the orientation of your display, it seems the h2 font-size could end up larger than the h1, e.g., 1920×1080 vs 1080×1920.

    Using Chrome Canary, I didn’t notice the font-size responding to a change in the viewport-height only the viewport-width, so it may be a non-issue. I expected that as the viewport narrowed the h2 size would remain the same if the viewport height remained the same. Thanks.

    • Permalink to comment#

      Wouldn’t you be doing things wrong if you are using header elements(h1, h2, etc..) to size your font? Semantically the h1 would be used to indicate more importance for the element than an h2 or h3, not increased font size.

  40. yes please.

  41. Stefan Huber
    Permalink to comment#

    starting with Modernizr 2.6.2 you get the tests:
    Modernizr.cssvhunit
    Modernizr.cssvwunit
    Modernizr.cssvmaxunit
    Modernizr.cssvminunit

  42. Kseniya
    Permalink to comment#

    Tried to use it – faced an issue:
    On the phone, when the keyboard is on, the screen height (device height?) changes and everything gets squashed with vh units. Have no idea how to fix it.. yet.

  43. omer
    Permalink to comment#

    OK got it work with vh vw… but can’t get it done without a manual refresh/reload of page.
    how can I make the Jquery thing work properly so I wouldn’t have to use manual refresh and as window scale is resized the text simultaneously resize in order ???

  44. Hey Jeremy Lawson, thanks a lot for the solution you brought us up using** media queries** to set a font size for small devices.

    In fact, that was exactly the first doubt that came into my mind: if “vw” is zooming in, ok for TV screens, but what about small devices? Will we have very small font?

    I tested it in Android and didn’t notice any change, now I’m aware it doesn’t work in Android yet (yet…).

    So it’s great to see how inovations go really fast with CSS3 and HTML5. First we were concerned about smartphones and tablets, now it the Big Tvs and Smart Tv’s turn!!

  45. Permalink to comment#

    Anybody seeking a pure Javascript implementation of the repaint script might find this useful:

    causeRepaintsOn = ["h1", "h2", "h3", "p"];
    elems = [];
    window.onload = function() {
        for (i = 0; i < causeRepaintsOn.length; i++) {
            var a = document.getElementsByTagName(causeRepaintsOn[i]);
            for (j = 0; j < a.length; j++) {
                elems.push(a[j]);
            }
        }
    };
    window.addEventListener("resize", function() {
        for (i = 0; i < elems.length; i++) {
            elems[i].style.zIndex = 1;
        }
    }, !1);
    
  46. Gunther
    Permalink to comment#

    Using the Viewport units for font sizes has an accessibility issue, as it “overrides” any base font size setting of the user! And at least for Desktop browsers it also breaks the browser’s zoom functionality which negatively affects the usability!
    But already the first point should be reason enough to never use it for font size settings.

    At the moment I can’t imagine any reasonable usage.

    Especially when it comes to font sizing we would rather need things like ‘min|max font-size’ and ‘font-size: fit’.
    And also an option to define values in an anti-proportional way, e.g. to set a padding on a link element which grows the smaller the font size is.

  47. Nice! I thought this wasn’t possible until I saw this post. I was thinking of an image instead of text to replace my font-type logo. :D I do hope that android devices will also support it soon.

  48. You can fix the Chrome resize bug with vm/vh using pure css. As long as a @keyframes animation is active the UI repaints…

    @keyframes forceRepaint { 0% { z-index:1; } 100% { z-index:1; } }

    p { animation:forceRepaint 60s infinite; }

  49. ryan joyce
    Permalink to comment#

    Its prolly worth noting, it goes without saying the perma-repaint CSS is not suitable for actual production code, nor is it good practice . Its just an interesting thing you can do with CSS!

  50. Permalink to comment#

    Android supports it now. See: http://caniuse.com/viewport-units

  51. This is awesome! Though, I’m still wishing to someway, similar to flex box, but that applies to text, i.e. scale the text contents of an element such that it fits entirely within the parent element.

    I haven’t had a chance to test this, but I think I could achieve the same effect by wrapping every character in span and then using display:flex on the parent element. Would be kind of a hack though..

  52. Steve
    Permalink to comment#

    How can I use vw and vh at the same time to control both the height AND the width of a font’s vertical AND horizontal sizes at the SAME time, rather than only controlling EITHER the width OR the height separately?

    I find that if I use vw, then as I alter only the height of the viewport, then the size of the font does not change (until I change the width of the viewport), and vice versa for using vh and altering only the width of the viewport.

  53. sergio
    Permalink to comment#

    Please make a note ASAP about the DIFFERENCE with an ACTUAL IOS device (at least IOS7 which my iPhone 5 has).
    IOS7 (maybe from IOS5?) renders everything TWICE as BIG.

    VW are based on the ACTUAL pixels of the screen, I.E. 640, while IOS requires us to provide all pixel sizes as if the screen had 320.

    So everything ends up double as big.

    • Steve
      Permalink to comment#

      Sergio, so is there a way to detect the operating system and then use a media query based on that to adjust the size??

  54. socialblogsite

    Steve, Yes, there is, using media queries you can target the resolutions, but it won’t calculate for you the different compensations. Then you need to adjust the size for EVERY resolution out there other than 1:1

    New iPhones are 2:1 (twice the resolution of regular displays) and there are 1.25, 1.3…
    I guess my next test will be with a .parent container setting the size to VW, and then a rule to adjust ALL its direct children : e.g.

    .parent {
    font-size: 3vw;
    }
    @media (-webkit-min-device-pixel-ratio: 2) {
        .parent &gt; * {
    font-size: .5em;
    }
    

    That way I don’t have to create 5 rules for each flexible font size I define (one main and 4 compensations for each resolution)

  55. Patrick

    Hum… Tried this on a phonegap app: it doesn’t work.
    In fact, it works on desktop in Chrome, but doesn’t work when the app is encapsulated in phonegap and tested on device (android).
    It is a very promissing techno, but needs to be better implemented in various browsers and webview.

  56. Adam Crockett

    How about this font-size: calc(1rem + 2vw); on the body, it allows for a very subtle scaling effect. there is probably some sort of way better maths but has anyone mentioned calc in the usage of vw?

  57. J.J.
    Permalink to comment#

    Hi,
    the reisize bug is fixed now in WebKit Nightly.

    https://bugs.webkit.org/show_bug.cgi?id=87846

  58. hamid
    Permalink to comment#

    Hi Cris’
    i am looking a css hack where i can compress font Horizontally when i am checking this on internet but i am not getting idea of this. can you help me out this, this is just as Photoshop style to compress font size horizontally like 100% compressing to something like 95% or 85%

    please help in this regard

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".