There are values in CSS that are for sizing things in relation to the viewport (the size of the browser window). They are called viewport units, and there are a number of them that do slightly different (all useful) things. One unit is 1% of one of the axes of the viewport. These can be useful for responsive design, that is, designing websites that look good across different screen sizes, taking advantage of the space available to them.
There are many things you can do with viewport units, but let’s look at one in particular: typography.
It’s worth looking at our more recent post Simplified Fluid Typography for practical, clamped, viewport-based type sizing.
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 width1vh
= 1% of viewport height1vmin
=1vw
or1vh
, whichever is smaller1vmax
=1vw
or1vh
, 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. 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);
});
UPDATE: Don’t worry about this anymore and definitely don’t be forcing those repaints. This resizing issue is fixed in Chrome 34+ and Safari 7+. It’s not common to change the viewport size on mobile devices, so I’m not sure if this bug ever affected them or not.
Browser Support
IE 10+, Firefox 19+, Chrome 34+, Safari 7+, Android 4.4+, iOS 6+ – Supported
Chrome 20-34, Safari 6 – Supported but has repaint issue
There are a couple of other specific cross-browser weirdnesses with them, documented on Can I Use.
font-size
Not just 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
- 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”}
This works but how would you stop it at a minimum size because it gets too small in smaller screens.
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.
Hi,
You are right, i also saw this problem….
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.
Have someone found a polyfill for supporting Chrome (viewports units and calc) ?
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…
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
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.
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.
yes please.
starting with Modernizr 2.6.2 you get the tests:
Modernizr.cssvhunit
Modernizr.cssvwunit
Modernizr.cssvmaxunit
Modernizr.cssvminunit
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.
@Kseniya: You can fix this using the following viewport-tag:
I saw it on StackOverflow: div-element-wont-stay-at-the-bottom-when-ios-7-virtual-keyboard-is-present
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 ???
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!!
Anybody seeking a pure Javascript implementation of the repaint script might find this useful:
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.
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.
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; }
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!
Android supports it now. See: http://caniuse.com/viewport-units
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 usingdisplay:flex
on the parent element. Would be kind of a hack though..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.
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.
Sergio, so is there a way to detect the operating system and then use a media query based on that to adjust the size??
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.
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)
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.
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?Hi,
the reisize bug is fixed now in WebKit Nightly.
https://bugs.webkit.org/show_bug.cgi?id=87846
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