Typically, for the foreseeable future, any design composite you receive or create will have fixed dimensions. Currently we measure (in pixels) the element sizes, margins, and so on within the graphics files from Photoshop, Fireworks, and so on. We then punch these dimensions directly into our CSS. The same goes for text sizes. We click on a text element in our image editor of choice, note the font size, and then enter it (again, often measured in pixels) into the relevant CSS rule. So how do we convert our fixed dimensions into proportional ones?
It's possible I'm coming off too much of an Ethan Marcotte fan boy, but at this point it's essential that I provide another large tip of the hat (it should probably be a bow, maybe even a kneel) to him. In Dan Cederholm's excellent book, Handcrafted CSS, Mr. Marcotte contributed a chapter covering fluid grids. In it, he provided a simple and consistent formula for converting fixed width pixels into proportional percentages:
target ÷ context = result
Smells a bit like an equation to you? Fear not, when creating a responsive design, this formula soon becomes your new best friend. Rather than talk any more theory, let's put the formula to work converting the current fixed dimension for the And the winner isn't... site to a fluid percentage based layout.
If you remember, back in Chapter 2, Media Queries: Supporting Differing Viewports, we established that the basic markup structure of our site looked like this:
<div id="wrapper"> <!-- the header and navigation --> <div id="header"> <div id="navigation"> <ul> <li><a href="#">navigation1</a></li> <li><a href="#">navigation2</a></li> </ul> </div> </div> <!-- the sidebar --> <div id="sidebar"> <p>here is the sidebar</p> </div> <!-- the content --> <div id="content"> <p>here is the content</p> </div> <!-- the footer --> <div id="footer"> <p>Here is the footer</p> </div> </div>
Content was later added but what's important to note here is the CSS we are currently using to set the widths of the main structural (header, navigation, sidebar, content, and footer) elements. Note, I've omitted many of the styling rules so we can concentrate on structure:
#wrapper { margin-right: auto; margin-left: auto; width: 960px; } #header { margin-right: 10px; margin-left: 10px; width: 940px; } #navigation { padding-bottom: 25px; margin-top: 26px; margin-left: -10px; padding-right: 10px; padding-left: 10px; width: 940px; } #navigation ul li { display: inline-block; } #content { margin-top: 58px; margin-right: 10px; float: right; width: 698px; } #sidebar { border-right-color: #e8e8e8; border-right-style: solid; border-right-width: 2px; margin-top: 58px;padding-right: 10px; margin-right: 10px; margin-left: 10px; float: left; width: 220px; } #footer { float: left; margin-top: 20px; margin-right: 10px; margin-left: 10px; clear: both; width: 940px; }
All the values are currently set using pixels. Let's work from the outermost element and change them to proportional percentages using the target ÷ context = result formula.
All our content currently sits within a div with an ID of #wrapper
. You can see by the CSS above that it's set with automatic margin and a width of 960 px. As the outermost div, how do we define what percentage of the viewport width it should be?
We need something to "hold" and become the context for all the proportional elements (content, sidebar, footer, and so on) we intend to contain within our design. We therefore need to set a proportional value for the width that the #wrapper
should be in relation to the viewport size. For now, let's knock off a naught and roll with 96 percent and see what happens. Here's the amended rule for #wrapper
:
#wrapper { margin-right: auto; margin-left: auto; width: 96%; /* Holding outermost DIV */ }
And here's how it looks in the browser window:
So far, so good! 96 percent actually works quite well here although we could have opted for 100 or 90 percents—whatever we felt and set the design within the viewport in the most aesthetically pleasing manner.
Now changing from fixed to proportional gets a little more complicated as we move inwards. Let's look at the header section first. Consider the formula again, target ÷ context = result. Our #header
div (the target) sits within the #wrapper
div (the context). Therefore, we take our #header
(the target) width of 940 pixels, divide it by the width of the context (the #wrapper
), which was 960 px and our result is .979166667. We can turn this into a percentage by moving the decimal place two digits to the right and we now have a percentage width for the header of 97.9166667. Let's add that to our CSS:
#header { margin-right: 10px; margin-left: 10px; width: 97.9166667%; /* 940 ÷ 960 */ }
And as both the #navigation
and the #footer
divs also have the same declared width, we can swap both of those pixel values to the same percentage-based rule.
Finally, before we take a peek in the browser, let's turn to the #content
and #sidebar
div's. As the context is still the same (960 px) we just need to divide our target size by that figure. Our #content
is currently 698 px so divide that value by 960 and our answer is .727083333. Move the decimal place and we have a result of 72.7083333 percent—that's the width of the #content
div in percentage terms. Our sidebar is currently 220 px but there's also a 2 px border to consider. I don't want the thickness of the right-hand border to expand or contract proportionately so that will stay at 2 px. Because of that I need to subtract some size from the width of the sidebar. So in the case of this sidebar, I have subtracted 2 px from the sidebar width and then performed the same calculation. I've divided the target (now, 218 px) by the context (960 px) and the answer is .227083333. Shift the decimal and we have a result of 22.7083333 percent for the sidebar. After amending all the pixel widths to percentages, the following is what the relevant CSS looks like:
#wrapper { margin-right: auto; margin-left: auto; width: 96%; /* Holding outermost DIV */ } #header { margin-right: 10px; margin-left: 10px; width: 97.9166667%; /* 940 ÷ 960 */ } #navigation { padding-bottom: 25px; margin-top: 26px; margin-left: -10px; padding-right: 10px; padding-left: 10px; width: 72.7083333%; /* 698 ÷ 960 */ } #navigation ul li { display: inline-block; } #content { margin-top: 58px; margin-right: 10px; float: right; width: 72.7083333%; /* 698 ÷ 960 */ } #sidebar { border-right-color: #e8e8e8; border-right-style: solid; border-right-width: 2px; margin-top: 58px; margin-right: 10px; margin-left: 10px; float: left; width: 22.7083333%; /* 218 ÷ 960 */ } #footer { float: left; margin-top: 20px; margin-right: 10px; margin-left: 10px; clear: both; width: 97.9166667%; /* 940 ÷ 960 */ }
The following screenshot shows what it looks like in Firefox with the viewport around 1000 px wide:
All good so far. Now, let's go ahead and replace all the 10 px instances used for padding and margin throughout with their proportional equivalent using the same target ÷ context = result formula. As all the 10 px widths have the same 960 px context, the width in percentage terms is 1.0416667 percent (10 ÷ 960).
Can't we just round the numbers?
Some critics of responsive design techniques (for example, see http://tripleodeon.com/2010/10/not-a-mobile-web-merely-a-320px-wide-one/) argue that entering numbers such as .550724638 em into stylesheets is daft. You may wonder yourself, why aren't these simply rounded to something more sensible? The counter argument is that it's a more accurate answer to the question being asked. Providing a browser with the most accurate answer should make it more able to display that answer in the most accurate manner. As a related aside, if you stayed awake through more than a couple math classes I'm sure you've heard of the Golden Ratio (http://en.wikipedia.org/wiki/Golden_ratio)? The mathematical ratio, found and used throughout almost every discipline we know, is expressed as approximately 1:1.61803398874989 (if you want it to 10,000 decimal places, knock yourself out here http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/phi10000dps.txt). Not a neat number by any means but quite an important one. If the Golden Ratio can suffer such precise measurements, I'm inclined to believe our web designs can too.
Everything still looks fine at the same viewport size. However, the navigation area isn't behaving. If I bring the viewport size in, just a little, the links start to span two lines:
Furthermore, if I expand my viewport, the margin between the links doesn't increase proportionally. Let's take a look at the CSS associated with the navigation and try and figure out why:
#navigation { padding-bottom: 25px; margin-top: 26px; margin-left: -1.0416667%; /* 10 ÷ 960 */ padding-right: 1.0416667%; /* 10 ÷ 960 */ padding-left: 1.0416667%; /* 10 ÷ 960 */ width: 97.9166667%; /* 940 ÷ 960 */ background-repeat: repeat-x; background-image: url(../img/atwiNavBg.png); border-bottom-color: #bfbfbf; border-bottom-style: double; border-bottom-width: 4px; } #navigation ul li { display: inline-block; } #navigation ul li a { height: 42px; line-height: 42px; margin-right: 25px; text-decoration: none; text-transform: uppercase; font-family: Arial, "Lucida Grande", Verdana, sans-serif; font-size: 27px; color: black; }
Well, on first glance, looks like our third rule there, the #navigation
ul
li
a
, still has a pixel-based margin of 25 px. Let's go ahead and fix that with our trusty formula. As the #navigation
div is based on 940 px our result should be 2.6595745 percent. So we'll change that rule to be as follows:
#navigation ul li a {
height: 42px;
line-height: 42px;
margin-right: 2.6595745%; /* 25 ÷ 940 */
text-decoration: none;
text-transform: uppercase;
font-family: Arial, "Lucida Grande", Verdana, sans-serif;
font-size: 27px;
color: black;
}
That was easy enough! Let's just check all is OK in the browser…
Oh, wait, that isn't exactly what we were gunning for. OK, the links aren't spanning two lines but we don't have the correct proportional margin value, clearly. The navigation links look like one big word, and not one I can find in my dictionary…
Considering our formula again (target ÷ context = result), it's possible to understand why this issue is occurring. Our problem here is the context. Here's the relevant markup:
<div id="navigation"> <ul> <li><a href="#">Why?</a></li> <li><a href="#">Synopsis</a></li> <li><a href="#">Stills/Photos</a></li> <li><a href="#">Videos/clips</a></li> <li><a href="#">Quotes</a></li> <li><a href="#">Quiz</a></li> </ul> </div>
As you can see our <a href="#">
links sit within the <li>
tags. They are the context for our proportional margin. Looking at the CSS for the <li>
tags, we can see there are no width values set:
#navigation ul li { display: inline-block; }
As if often the case, it turns out that there are various ways of solving this problem. We could add an explicit width to the <li>
tags but that would either have to be fixed-width pixels or a percentage of the containing element (the navigation
div), neither of which allows any flexibility for the text that ultimately sits within them.
We could instead amend the CSS for the <li>
tags, changing inline-block
to be simply inline
:
#navigation ul li {
display: inline;
}
Opting for display: inline;
(which stops the <li>
elements behaving like block level elements), also makes the navigation render horizontally in earlier versions of Internet Explorer (versions 6 and 7) that have problems with inline-block
. However, I'm a fan of inline-block
as it gives greater control over the margins and padding for modern browsers so instead I'm going to leave the <li>
tags as inline-blocks (and perhaps add an override style for IE 6 and IE 7, later) and instead move my percentage based margin rule from the <a>
tag (which has no explicit context) to the containing <li>
block instead. Here's what the amended rules now look like:
#navigation ul li {
display: inline-block;
margin-right: 2.6595745%; /* 25 ÷ 940 */
}
#navigation ul li a {
height: 42px;
line-height: 42px;
text-decoration: none;
text-transform: uppercase;
font-family: Arial, "Lucida Grande", Verdana, sans-serif;
font-size: 27px; color: black;
}
And the following screenshot shows how it looks in the browser with a 1200 px wide viewport:
So the navigation is getting there now, but I still have the problem of the navigation links spanning two lines as the viewport gets smaller, right until I get below 768 px wide when the media query we wrote in Chapter 2, Media Queries: Supporting Differing Viewports, then overrides the current navigation styles. Before we start fixing the navigation I'm going to switch all my typography sizes from fixed size pixels to the proportional unit, "ems". Once that's done we'll look at the other elephant in the room, getting our images to scale with the design.
3.22.61.30