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:
- 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.
- 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).
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. 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");
var viewport = $(window);
testEl.css({
width: "100vw"
});
if (testEl.width() == viewport.width()) {
$("html").addClass("vw-support");
} else {
$("html").append("vw-unsupported");
};
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
- David Storey: Responsive viewport units
Very nice! That’s a step forward for web typography layouts.
I made this a few days ago:
onresize=onload=function(){document.body.style.fontSize=window.innerWidth+”px”}
I also made a demo:
http://maloweb.com/snippets/responsivestuff.html
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.
This seems to work on Safari 5.2 (Beta 3) [Version 5.2 (7536.6.1)]
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.
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.
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?
VW and VH also work in IE9 though it uses VM rather than VMIN.
This is way too cool!
wondering how to get this working with a slider to change font size on website
What a kludge! If you’re going to resort to jQuery to implement a styling choice it should support a lot more browsers.
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.
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!
Ironic how IE is now ahead in the CSS3 race…
I can’t wait to see what uses people come up with for this and calc together.
I want to use it now lol
love new CSS3 Specs.
and I agree with Julian IE10 is taking major hurdles.
Exciting!!
The demo looks like it’s working for me in Chrome 19 beta. Can anyone else confirm?
using 20.0.1122.0 canary it scales smoothly
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.
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…
Very nice.
Very cool, I can really see a need for a responsive text sizing that isn’t effected by cascading…
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.
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?
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
I cannot wait to see this fully supported….in a few years :_(
It’s fantastic…
…every day goes the web a bit better!
> 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!
I think we can do it something like this (not exactly) by using em instead of px, isn’t that?
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.
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.
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.
What about min-font-size ?
With javascript, it’s possible :
http://blog.evolya.fr/public/divers/demo-textsize/demo-textsize.html
(In source code)
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.
I’m using FitText in a blog and it works very well (even on mobile devices)! But this one looks promising! Thanks for share…
When can we use it on iOS or Android?
I made this a few days ago:
onresize=onload=function(){document.body.style.fontSize=window.innerWidth+”px”}
what’s about it?
I like css3 and stuff, but when wil this work in all browsers …
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.
Awesome! Thanks. Implemented it today on a new dev. :)
Awesome. It works in chrome 19 :D
(which was released this week)
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…
I use that code and after I make my declaration in EM.
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.
yes please.