Using CSS zoom and CSS Transforms For a Better “Increase Text Size” Button

So… the site I’m working on has one of those “increase text size” controls. On this project it’s turned out to be one of those features that shows up in comps and somehow falls through the cracks until later on in the project cycle. Situation normal, really, as it isn’t a big feature. It’s just one of those things that needs to be buttoned up before the site can go live.

Anyway, I was thinking about how to do implement it the other day. I haven’t done one of these in a long time and the only other time I did one it involved crafting separate, albeit small, style sheets for the larger text sizes. I didn’t want to go that way again. Basically, I just didn’t want to write new style sheets- even small ones.

What’s a fella to do?


So, thinking about it a little bit, I seized upon using the non-standard CSS zoom property. Supported in Internet Explorer (zoom:1 is often used for a hasLayout toggle) and Webkit browsers, it would represent a simple (1 line!) CSS solution to this problem. It’s also one that I like better aesthetically as the site looks the same, just bigger. I figure there’s a reason all browsers have moved to this behavior when hitting ctrl+.

The problem was figuring out an equivalent for FireFox and Opera which don’t support zoom

Enter CSS 2D Transform

A little searching and experimenting later I came up with the idea of using CSS Transforms and the scale value to approximate zoom in browsers that lack support.

Let’s see how I did it.

As you go through the following keep in mind this hasn’t actually gone through testing yet so something weird could yet shake out. I just wrote this code yesterday, so you guys can be my sanity check.

Also, is anyone else doing this?

Here’s the markup. We had this done weeks ago.

<!-- yes, we get the gas face for href=&quot;#&quot;
I don't like them either.
I'll rewrite it to use just LIs, I swear.
 <ul id="font-size"><li class="text">Text Size:</li>
<li><a href="#" class="default">default font size</a></li>
<li><a href="#" class="larger">larger font size</a></li>
<li><a href="#" class="largest">largest font size</a></li>

The first thing I did was write a small chunk of code that runs on $(document).ready()

(yes, this is a jQuery project.)

//using the jQuery cookie plugin to get a pre-set value;
var fontSize=$.cookie('font_size');
//if it exists, set the body.className right now
//the user gets their size of choice right away
if (fontSize) {
    	  .removeClass("largest larger default")
$("#font-size li a").click(
		var $body = $(document.body),
		newClass = this.className;
		//if it doesn't already have the chosen class
    	       if (!$body.hasClass(newClass)) {
               //clear any old ones and add the new one
				.removeClass("largest larger default")
                //saving the choice in a cookie
                //and finally, stop the clicks

Cool. So far so good. We’ve got classes on the body indicating how big the user wants to see the site.

Before we look at the CSS, there’s one more bit of JavaScript we need to look at as I almost immediately envisioned a problem with the above scenario.

If i was using CSS Transforms to scale the pages in Firefox and then Firefox eventually implemented zoom, things would get wonky. We don’t want that. I had to future-proof the code a little bit.

So, what I needed was a test for the presence of a valid zoom CSS property. Turning to Modernizr (since it was already in use on the site) I used the handy Modernizr.addTest method to test for zoom. Here’s the one I cobbled together.

     Modernizr.addTest('zoom', function () {
//create a div
        var test = document.createElement('div');
//if there's a valid property in the browser
//it will return ""
//undefined means the browser doesn't know
//what you're talking about
 	    if ( === undefined) {
		    delete test;
		    return false;
	    delete test;
        return true;

And finally, we’ve got the style sheet.

we add a .default class, so we can reset the page with
the mechanism defined above
body.default {
	font:13px/1.231 arial, helvetica, sans-serif;
	background:url(images/page-bg.jpg) center repeat-y;
here's our class for browsers without a zoom property,
this sets the transform's origin. In this case it defines
the point from which our scale will happen.
We want it to row from the center and from the top,
so 50% and 0 it is.
.no-zoom body {
	-o-transform-origin:50% 0;
	-moz-transform-origin:50% 0;
classes for browsers with zoom
.zoom body.larger {
.zoom body.largest {
and classes for browsers that don't support zoom
.no-zoom body.larger {
    -o-transform: scale(1.1);
    -moz-transform: scale(1.1);
    transform: scale(1.1);
.no-zoom body.largest {
    -o-transform: scale(1.25);
    -moz-transform: scale(1.25);
    transform: scale(1.25);

And that’s that. Here’s a quick demo to see it in action. You can also view source here.


I did a quick V8 Benchmark comparing scaled/zoomed performance in several browsers to see if there are any issues. The following table shows that there really isn’t much difference. Clearly this isn’t a definitive test as it’s only a small run of tests in one benchmark on one machine, but it was nice that nothing shook out in this first pass. I’m going to look at doing a DOM heavy test as well as something with some animation (maybe even Canvas?)

Browser no zoom/scale zoom:1.5 transform:scale(1.5);
Chrome 8.0.552.215 5587 5642 5782
Firefox 3.6.13 594 NA 653
Internet Explorer 8
Internet Explorer Platform Preview version 1.9.8023.6000
Safari 5.03 2839 2874 2796
Opera 10.63 4071 NA 4110

I kind of like it.

This entry was posted in CSS and tagged , , , , , , , , . Bookmark the permalink.

7 Responses to "Using CSS zoom and CSS Transforms For a Better “Increase Text Size” Button"

Leave a reply