Fluid Frontend Calculator

©2011 Martin Rinehart

Here are some screenshots of my shirt-pocket-sized fluid equation calculator in popular (with me at least!) browsers:

Screen shot of special-purpose, fluid frontend calculator. Screen shot of special-purpose, fluid frontend calculator. Screen shot of special-purpose, fluid frontend calculator.

You can get this calculator by punching "Fluidulator" on the menu above.

If you are using one of your better browsers, right click and Pin the calculator tab. Then drag the tab out of the browser. Turn off as many toolbars as you can and resize as small as you can without getting scroll bars. One of these browsers wins the prize for getting out of the way, but everything turned off in the app is also turned off in the full-size browser. Ugh. Another has bugs. (Hey! Wait a minute! Standards-based browsers all work the same, don't they?) A third loses the race to be smallest, but otherwise works well. I tried a fourth, but without much success. It didn't have a "Pin" option.

P. S. My bug! Firefox corrected the bogus globals issue. Bug in my code required bogus globals to work. All better now.

You can put the "fluidulator" in an unused corner of your monitor, or keep it open on a small mobile device. Save it on your machine and you can customize your own defaults, which will speed your work considerably.

What is it for? I want my pages to support every device that will ever be used! (Let's define "forever" in hardware to be at least the next few months.) My long-term hardware forecast is this: devices at every size for every need, every budget. Sizes below 176 pixels wide are disappearing. Sizes above 640 are good for multiple, siumultaneous pages and I won't be a pig taking pixels I don't need.

Necessity Begets Invention

My goal was simple: create "fully fluid" pages: pages that could be read on devices as narrow as 176 pixels or as wide as 640 pixels. Between those points I would interpolate and not worry about the next manufacturer creating a new device at a new size.

You face the same issue, even if you target smaller slices of the device market. A 1.5" iPod Nano is a lot smaller than a 2.25" iPod Nano, for example and there are lots of other manufacturers inside that range.

The Chase Begins

I started toward "fully fluid" by examining each item. As an example, consider my logo, the "MR" in the top-left corner of this article. It could be 120 pixels square if space were plentiful, but as little as 32 pixels square if we were on a scrunchy small device. (Go ahead and scrunch the page you're reading to see an example. Pause briefly at interesting sizes to get a fresh layout.)

That starts the math. Given a minimum and maximum device width and a min/max element size you have two (x,y) points: (device min, element min) and (device max, element max). A little high-school algebra yields a slope/intercept equation that fixes every point between min and max. (Yes, I was prepared to replace that straight line with a curve, but I was very happy this wasn't necessary. High school math is a long way back in my rear-view mirror.)

Math by Hand

I worked out the first few equations by hand. Back to the logo. For overall size I knew that f(640) = 120; f(176) = 32;. (Watch the logo as you shrink and expand this page.) In addition to the overall size (pixels), you need the size of the letters (points), and the top and left offsets of both letters (pixels). That's a dozen points which reduce to six equations. It becomes a royal PITA (that's also a Mediterranean sandwich bread) when you realize that most of the values require a good deal of experimenting, not just math. (Slick logo gradient, right? It's JavaScript painting 1 pixel tall divs; it's not an image.)

Note to W3C: CSS is woefully inadequate when you approach typography. What, for example, is the height/width ratio of an "M" in a default, sans-serif typeface?

How many points for a nice letter height? Where should the "R" go so the "M" behind it is readable? I wanted a tool to make the math effortless because the rest of the job was not going to be easy.

Math by Machine

It took about an hour to make a micro page that did the calculations, reducing two points to slope and intercept in a formula I could just copy into my code. Since I'd decided on 176 and 640 as device minimum and maximum, and 320 was a common intermediate size for testing, I really had only two variables to key in. Type in two values, click "Compute" and the equation is ready for copying into my code. What a saving!

Brutal Testing

How did I do? You tell me. Take a lower corner of this page and drag it in and out. Are we getting a good range of sizes? Open this page on your mobile device. Is it readable? (No? Uh, maybe it's time to upgrade that device, yes?)

Actually, this page is more fluid than the calculator. I have a single JavaScript file that handles all my new articles, adding the top-left logo, the top-right medallion, sizing the body font and line height and so on. My site is generally used on laptops or desktops, not mobile devices so the really small stuff is academic. But as one JavaScript file handles hundreds of pages it seemed like it was worth a little extra effort to go for the big range. (At present, all sizes are laid out well initially. Firefox needs manual intervention—F5—when you expand sizes. Opera needs manual intervention—Ctrl+Tab, twice—when you scroll up.)

Programming Notes

Here's the top of the function that (re)sizes my standard article page:

/** Create layout object based on current width. */
function compute_layout( wid ) {

    // layout for sizes between 176 and 640 pixels
    if ( wid < 176 ) { wid = 176; }
    if ( wid > 640 ) { wid = 640; }

    // body, 2 to 8 pix
    compute_layout.margin =
            Math.round( wid * 0.01293 - 0.27586 );
    // 8 to 11 pts
    compute_layout.fontSize =
            Math.round( wid * 0.00647 + 6.86207 );
    // 9 to 14 pts
    compute_layout.lineHeight =
            Math.round( wid * 0.01078 + 7.10345 );

    // logo, 32 to 120 pix
    compute_layout.logo = Math.round( wid * 0.1897 - 1.4 );

There are a couple dozen more formulas in compute_layout(). This is not rocket science, but that "fluidulator" definitely earns its keep.

Did you notice that compute_layout() uses itself as a giant corkboard? Everything it calculates it "pins" to itself (compute_layout.margin = ...) for use by the routines that actually use its calculations. I am never going back to functions that ride in the back of the bus.

Feedback: MartinRinehart at gmail dot com.

# # #