Web Page Production 1 v1 3
Web Page Production 1 v1 3
Web Page Production 1 v1 3
Contents
Introduction to web page production Overview of the page structure Semantic HTML markup Slicing a design in Adobe Photoshop Styling the page with CSS
Note: It's impossible to cover every aspect of web production in a single book. This will be the first in a series of web production guides, each covering different aspects of the process. See http://webdesignfromscratch.com/downloads.cfm for the latest available ebooks. Subscribe to the RSS feed for automatic updates. Before we do anything else, let's take a quick look at the design that we will be converting into a useable web page:
There are many different text editors you can use to write your HTML and CSS, each with its own different benefits and drawbacks. You can use something as simple as Windows Notepad to write your code, but you'll have to type every single character by hand. Commercial web page editing software such as Adobe Dreamweaver gives you a helping hand with indented, colour-coded markup, and code hints to automatically finish your lines of code for you. I use Aptana, an opensource Java-based editor. It has most of the features of the commercial software, and best of all, it's free! In this book, I also use Adobe Photoshop, which is the weapon of choice for most web designers, but there are other graphics programs you can use to achieve similar results. Note: If you wish to follow along with the example in this book, the files are all available for download: Original sliced PSD design (.psd file, 1.24MB) Example site, including all images and CSS files (.zip file, 59KB) And you can see a working version of the site at http://webdesignfromscratch.com/webproduction1/index.html
Page Structure
Look before you leap
When producing a web page from a Photoshop document, it's always tempting to dive straight into the HTML and get some images on the page, maybe the logo and a background gradient, so that your page immediately starts to resemble the design. Stop right there! Before you even open your text editor, if you take a few moments to think about the overall structure of the page, and how this may affect the decisions you make, you will save valuable time later.
Fixed or fluid?
The first big decision you need to make is whether your page should be fixed-width or fluid (sometimes called zoom or elastic). A fixed-width layout is displayed within a container whose width is specified in pixels and can't be altered by the user, whereas a fluid layout has its width specified in ems, which means that the width will increase as the text-size is increased in the user's web browser. Generally speaking, it's always best to use a fluid layout if possible, as it enables text size to be increased without causing the design to break. If you increase the text size in a fixed-width layout, the large text has nowhere to go except down the page, which can leave you with unreadable long columns of large text. Some clients like to insist on their pages being fixed width so that they always fit inside an 800x600 pixel display, and therefore can be viewed by all users without the need for horizontal scrolling. It's a nice theory, but there are several drawbacks to this argument: Firstly, if you have an 800 pixel wide page stuck in the middle of a 1680 pixel wide screen (or wider), it's going to look lost among all that empty space, and as I mentioned earlier, increasing the text size will cause display problems. Also, according to w3schools.com's browser display statistics, as of January 2007, only about 14% of web users still use 800x600 pixel displays, so to design pages for this soon-to-be-negligible minority, to the detriment of the 80% of users with 1024x768 resolution or higher, makes no sense at all. Another option is to set the page width as a percentage of the display window width, but due to the vast difference in screen widths, this is not adviseable.
Header
The header is fairly simple, with just a logo and two links on the right hand side. The logo will be a link back to the home page (unless it's a one-page website). The header can be a fixed height, since the logo image won't change size and there is plenty of space to increase the size of the text links. One thing to note is that while we want the contents of the header to remain within a central container, the blue gradient background will stretch to the left and right edges of the window.
Navigation
It looks like the navigation will probably be the trickiest part of the production process. It will require expanding background images, hover states, and a nested list for the submenu! We'll tackle this later. One good thing about the navigation is that it uses standard text for the menu items, so we won't need to make images for each word. Again it's worth noting that the background bars will have to stretch to the edges of the window. Main Content
The content of the home page shouldn't cause too many problems. A simple text heading and introductory paragraph are followed by a two-column content section. The left column contains three repeated sections, and the right column is a list of links with corresponding icons. The only real decision we'll have to make is which content to include first in the markup. Footer
The big decision concerning any footer is whether to have it float underneath the content, or to make it stick to the bottom of the page. This is only an issue if you have pages where the content doesn't take up a whole vertical page. Considering the gradient on this footer, it would look a bit out of place floating halfway up the window, so I think we'll have it fixed to the foot of the page.
Let's do it!
Ok, now we've had a good look around our design, we have a general idea of how we'll tackle each section, and we've identified areas which might take a bit more thought. There are no other hidden elements waiting to take us by surprise later on. So grab a cup of coffee and let's write some HTML.
The main reason to use semantic HTML is that it forces you to think about the markup decisions more carefully, resulting in cleaner, more semantically-correct HTML.
For an in-depth look at why semantically correct HTML is a good idea, see Ben Hunt's ebook Semantic HTML
HTML first
By now you're probably itching to get some content on the page and style it so that you can see the page coming together as you go. As tempting as this is, I recommend that you save all the CSS styling for later, and at first concentrate on the HTML only. For one thing, it won't take you long at all. You won't have to worry about cross-browser compatability at this stage, or whether your display breaks at certain text sizes. You're simply getting all the content on the page in plain, semantically correct HTML with no bells and whistles. And once you're done it will be a much simpler process to implement the Cascading Style Sheet to make the page look like the design. Secondly, we need to ensure that if a user has CSS disabled, all the content is still accessible on screen. The same applies for blind or partially-sighted users. They aren't interested in the design of the site, only that their screen-reader is able to read them all the text on the page in a logical order, without including any unnecessary information.
Code syntax
Throughout the remainder of the book there will be a lot of sample markup, both HTML and CSS. Sections of HTML and CSS markup will be contained in a grey-bordered box with a text caption:
HTML
body { background: #fff; color: #000; text-align: left; }
CSS
New lines of code will be in bold:
<html> <body> <h1>This is an HTML section</h1> <p>This is a new line of code</p> </body> </html>
HTML
Getting started
Let's open a new blank HTML document. If you do this in a specialised text editor (like Aptana or Dreamweaver), you'll get the Doctype declaration and some essential HTML tags inserted automatically:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Untitled Document</title> </head> <body> </body> </html>
HTML
It's a good idea to save your document at this stage, and get into the habit of saving at regular intervals. I'll save the document as index.html in the root directory of my site.
10
... <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Mortgage Services</title> </head> ...
HTML
I won't worry about anything else within the <head> tags for now. It's mainly for <meta> tags, which contain information about the page, the <title> tag, and <link> tags, for any external files you may wish to reference in your page. Later on, I'll add a <link> tag to reference the CSS stylesheet containing the styles for the design, but since that page doesn't exist yet, I'll leave it out for now.
11
... <body> <div id="header"> </div> <div id="content"> </div> <div id="footer"> </div> </body> ...
HTML
Divs and ids
The <div> tag is used along with the id attribute to add structure to an HTML document. The <div> tag simply defines the content as block-level content, dividing the page into rectangular sections, and the id attribute gives each <div> tag a unique identifier, which will be used in conjunction with the stylesheet later to make the <div> appear as I want it to. Be careful to only use <div> tags where they are needed, and only use the id attribute with unique elements, which appear only once on each page. If you need to apply an identifier to an element which will be repeated throughout the page, then you should use the class attribute, which will be introduced later. Here I have added three <div> elements, and given them unique identifiers of header, content and footer respectively. Let's start to add content to these sections, starting with the header.
Header
12
Looking again at the header section of the page design, I can see that it contains the logo, and two links. A lot of designers use an <h1> tag for the website name, as it is the heading for the whole site, then use a CSS image replacement technique to display the logo image instead of the <h1> text. The problem with this method is that the <h1> ends up being the same for every page on the site. Your <h1> text should be a unique page header which accurately describes the contents of the page. The site logo is an image portraying the sites identity, and serving as a link to the homepage. Therefore it is fine to include the image in the HTML, as long as you remember to add some 'alt' text to describe the image to those who are unable to see it (I'll talk more about alt text later). I've left the image's 'src' attribute blank for now, as I haven't created the logo image from the Photoshop document yet. This will be covered in a later chapter on PSD slicing.
... <div id="header"> <a href="/"><img src="" alt="Mortgage Services home page" /></a> </div><!-- end header --> ...
HTML
Here, <a href=/> . . . </a> simply links to the root directory, which will automatically display the index page. Another good habit to get into is using HTML comments to show which <div> tag each closing </div> tag corresponds to. Here, I've used <!-- end header --> to show that this closing </div> tag corresponds to the opening <div> tag with id=header. It's not really necessary at this stage, as it's pretty obvious at a glance which <div> corresponds to which </div>, but if you have a page with a lot of content, the <div> elements can get really complex, with multiple nested lists, and these comments come in really handy for letting you know where you are in an HTML document. Now let's add the links for the right of the header. I'm going to use an unordered list for the links:
... <div id="header"> <a href="/"><img src="" alt="Mortgage Services home page" /></a> <ul> <li><a href="#">Site map</a></li> <li><a href="#">Client Login</a></li> </ul> </div><!-- end header --> ...
13
HTML
I've left the URLs set to '#' at this stage, as I don't have any other pages yet. This simply reloads the current page. I can change these to the actual URLs when I've created the other pages. You'll see from the design that there's a one-pixel vertical bar between the two links. This could easily be inserted as text with the 'pipe' character (|), but it's not good practice, because semantically, the pipe character only has meaning as a mathematical symbol, which is not applicable here. The bar in the design is purely for aesthetic purposes, to separate the two links, so I will add it later using CSS borders. If I open the index.html page in a web browser, we can take a look at the page so far:
Not much to look at, but that will all change later. For now I'm only concerned with the semantic HTML. The logo image doesn't exist yet, so we can see an image placeholder with the alt text displayed, and the links are displayed in our unordered list with the default bullet points. Again, I'll address these design issues later. I may find I need to add a few extra HTML elements in order to make the design work properly, but for now let's keep it as simple as possible.
14
Navigation
The structure of the navigation is straightforward enough. We have two horizontal bars, the main navigation menu on top, and a different subnavigation below, depending on which page is active. It looks like you could simply put two unordered lists on top of each other, and change the content of the lower one depending on which page you're on. This would work visually based on our design. However, in order for the navigation to make sense semantically, the subnav menu should be placed immediately after it's parent in the main navigation menu. To do this I need to use nested lists: Firstly, create an unordered list for the main navigation (directly under the header):
... </div><!-- end header --> <ul class="main-nav"> <li><a href="#">About us</a></li> <li><a href="#">Mortgages</a></li> <li><a href="#">Protection</a></li> <li><a href="#">Insurance</a></li> <li><a href="#">Loans</a></li> <li><a href="#">Conveyancing</a></li> <li><a href="#">Cut your bills</a></li> <li><a href="#">Contact us</a></li> </ul><!-- end main-nav --> ...
HTML
I've given the <ul> the class name main-nav, as I'll need to refer to it when styling the navigation. Note: Class and id names cannot contain any spaces or underscores. If you put a space in your class or id name, it will be treated as two separate names. At this point, you may have noticed that the footer navigation contains exactly the same links as the main navigation, so to save time, before I add the subnavigation, I'll copy the code for the main navigation and paste it into the footer section. I've removed the class name because the footer navigation will be styled differently from the main navigation:
15
... <div id="footer"> <ul> <li><a href="#">About us</a></li> <li><a href="#">Mortgages</a></li> <li><a href="#">Protection</a></li> <li><a href="#">Insurance</a></li> <li><a href="#">Loans</a></li> <li><a href="#">Conveyancing</a></li> <li><a href="#">Cut your bills</a></li> <li><a href="#">Contact us</a></li> </ul> </div><!-- end footer --> ...
HTML
Next, for each menu item which requires a submenu, I need to add another unordered list directly after the main menu link:
... <ul class="main-nav"> <li><a href="#">About us</a> <ul> <li><a href="#">About Mortgage Services</a></li> <li><a href="#">Our history</a></li> </ul> </li> <li><a href="#">Mortgages</a> <ul> <li><a href="#">Subnav link</a></li> <li><a href="#">Subnav link</a></li> </ul> </li> ...
HTML
If I do this for each menu item with a submenu (I've used Subnav link as a placeholder for now),
Web Design from Scratch, 2008
16
then view the page in a browser, we can see how an unstyled nested list looks:
Each submenu list will need its own class later, so that I can use CSS to display only one submenu at a time. But for accessibility and search engine optimisation purposes, it's good to have the entire navigation structure on the page.
17
... <div id="content"> <h1>Mortgage News</h1> <p>Vestibulum elit magna, sollicitudin in ...</p> ...
HTML
Note: All content on a web page should be contained between a pair of HTML tags. HTML tags tell the browser what type of content they contain, and allow us to specify how it should be displayed. Content which is outside of HTML tags (unformatted text) is still displayed but it will look terrible and have no meaning semantically. If you want to include plain text, you should use the <pre> tag, which displays text exactly as it is typed into the text editor, including spaces, tabs and carriage returns.
18
When adding the main content to a page, there will often be two or more columns, and you need to decide which column to include first. The columns will be positioned later using CSS floats, but for now you need to bear in mind that the most important and relevant content should appear first in the HTML. In our case, the sidebar containing three links is clearly less important than the wider column, which contains information about interest rates, tips and recommendations. So I'll put the wider column above the sidebar in the HTML document. The column features 3 sections with repeated elements. Each has an image, a heading and one or more paragraphs of text. I'll use <h2> for the headings as they are the most important headings after the <h1>. The headings will also serve as links to each article, so I'll include a link within each <h2>.
... <div id="content"> <h1>Mortgage News</h1> <p>Vestibulum elit magna, sollicitudin in, dignissim sit amet, consectetuer eget, nul. Vestibulum elit magna, sollicitudin in, dignissim sit amet, consectetuer eget, null</p> <img src="" alt="" />
19
<h2><a href="#">Interest rates set to rise</a></h2> <p>Duis laoreet commodo pede. Nulla nisl. Integer consequat massa bibendum augue. Mauris volutpat nonummy lectus.</p> <p>Vestibulum elit magna, sollicitudin in, dignissim sit amet, consectetuer eget, nulla.</p> <img src="" alt="" /> <h2><a href="#">Tips to organise your household bills in 2008</a></h2> <p>Mauris volutpat nonummy lectus.</p> <p>Duis laoreet commodo pede. Nulla nisl. Integer consequat massa bibendum augue. Vestibulum elit magna, sollicitudin in, dignissim sit amet, consectetuer eget, nulla.</p> <img src="" alt="" /> <h2><a href="#">Recommended: Alliance & Leicester</a></h2> <p>Duis laoreet commodo pede. Nulla nisl. Integer consequat massa bibendum augue. Vestibulum elit magna, sollicitudin in, dignissim sit amet, consectetuer eget, nulla.</p> </div><!-- end content --> ...
HTML
20
As you can see, because I left the alt attributes empty, and the images don't exist yet, the browser simply leaves them out altogether. This is what a user would see if they had images disabled. Now to put in the sidebar links. It's a list of links so I'll use an unordered list. Again, the images are merely icons which provide a visual clue as to the function of the link. If the stars image can't be seen, the user doesn't need to know that there's an image there, they will simply rely on the link text. So I could use images with empty alt attributes, just as I did for the images in the main column. But there is a better way. I can reference the images as background images in the CSS, which means the images won't appear in the HTML at all. This keeps our HTML clean, and cuts down on meaningless content. So all I need for now is a list of links:
21
... <p>Duis laoreet commodo . . .</p> <ul> <li><a href="#">Free quotes</a></li> <li><a href="#">Contact us</a></li> <li><a href="#">Our hot tips</a></li> </ul> </div><!-- end content --> ...
HTML
And that's it! I've already added the footer, so the page is now complete. I have clean, semantically correct HTML, which is valid, accessible and easy to manage. Now it's ready to have the CSS applied to it, so I can make it look like our original design, but before I start that, it's a good idea to get all the images I'll need from the design together in their own folder. There's a very simple way to do this in Photoshop. Using the slice tool, you can 'cut out' all the images you need, optimise them for the web and save them all at once. The next chapter will guide you through this process.
22
23
Slicing and exporting a Photoshop document is a piece of cake these days. You can do the whole process in one go, with no need for multiple saves or cropping.
I'll start from the top of the page, slicing the images I'll need for the design. Firstly I'll need an image for the light blue gradient of the header. As this is a simple vertical gradient which stretches right across the page, I can simply take a 1-pixel wide slice and use the CSS to have it repeat horizontally. This keeps the size of the image to a minimum, so the page will load faster. Position the cursor at the top edge of the page then click and drag down to the bottom of the header. If you turn on the 'snap' function (View > Snap) then your slice will automatically snap to the edge of the header. It doesn't matter how wide you make the slice, because you can easily resize it later.
You can see the slice outlined in brown. This is a user slice, which means it's a slice that I've created. The blue number two means that it is slice number two. That's because when you start to slice a page, Photoshop automatically slices up the rest of the page. These automatically generated slices are called auto slices, I can choose to ignore these when I come to save the images later. Still using the slice tool, I'll double-click inside the slice I've just created to open the Slice Options dialogue box. The only thing I need to change here is the name of the slice. This will also be the filename of the header background image, so I'll call it header-bg. The file extension will be added later, after I've optimised the image.
24
Click OK to change the slice name, then still using the slice tool, click and hold the right edge of the slice, and drag it to the left, until it's only 1 pixel wide. I changed the name before doing this because now it's impossible to double-click within the slice. If you need to open the Slice Options again, you'll either have to expand the slice again, or zoom in until you can see enough of the slice to select it.
Next let's slice the logo image. The problem with the logo is that it sits on top of the gradient background. If I slice the logo with the gradient background then it will have to line up perfectly with the header background. It would be better if the logo background was transparent. Then if for any reason I need to change the position of the logo in the future, I won't have to change the image. Fortunately, the logo is fairly simple, with plain colour and no photographic images, so I can save it as a gif with a transparent background, and the header background will show through. If the image contained complex gradients or photographic imagery, it would have to be saved as a jpg, which doesn't allow for transparent backgrounds.
25
You can save a complex image as a PNG file with a transparent background, but they are not supported on some browsers, so I don't recommend using them for important images such as logos. So first I need to remove the background from the logo. I've simply selected a rectangular portion of the gradient image with the marquee tool, and hit delete. The chequerboard pattern now shows through, meaning that there is no background in this area.
Now take the slice tool again, and drag out a slice around the logo. Double click in the slice and name it 'logo'.
Now I just need to repeat the process for all the images I require. I've made slices for the following images, and given them appropriate names:
Main menu background Main menu hover-state background Sub menu background (1 pixel-wide) 3 large images from main column (without grey borders they will be added using CSS) 3 icons from the sidebar links Footer gradient (1-pixel wide)
26
27
On the left you can see the original design, and on the right is a preview pane which shows you how your design will look when saved. As you change the settings for each slice, the quality of the preview image will change. You need to find the best balance between image quality and file size. I'll start with the image of the house on a hand to give you a good example.
As a general rule, use JPG for photos and complex gradients, and use GIF for images with areas of flat colour such as logos and illustrations.
28
In the preview pane, I'll click on the house image to select it. I can see on the right hand side that the current export settings are set to JPG with 60% quality. The image looks ok, pretty similar in quality to the original. The file size is displayed at the bottom-left of the preview pane. It's currently 4.369KB.
Now I'll take the quality slider and slide it all the way down to zero. You'll see that the file size has dropped to 1.641KB, but the image looks terrible.
I need to choose the lowest quality setting for the image which still looks the same as the original. For this image, about 55% quality is fine. Once you've decided on the optimum settings for a slice, you can select the next slice, and optimise that one. The settings for each slice are stored until you change them. If you have several slices which you know will require the same settings, you can shift-click slices to optimise multiple slices at once.
29
Now I'll optimise another image with a different file type. I click on the logo slice to select it. By default, the slice is set to JPG, so you can't see the chequerboard because JPG doesn't allow transparency. So I'll click the filetype dropdown and select GIF. For GIF images, instead of a quality slider, you can choose the number of colours, from 2 to 256. The more colours in a GIF, the higher quality it will be, but also the higher the file size. So I go through a similar process, reducing the number of colours gradually and choosing the lowest number of colours that still leaves the image looking good. For GIFs with a transparent background, you need to make sure you check the 'Transparency' checkbox, and also choose a 'Matte colour'. The matte colour is used to make the image blend into the background smoothly. A GIF image can't contain any semi-transparent pixels, only fully transparent or fully opaque. Instead of semi-transparent pixels, it will use the matte colour you specify to create the illusion of semi-transparency. You should choose your matte colour to match the colour that will sit behind the transparent GIF, this will give you the smoothest blending. If your background is a dark-to-light gradient, then neither colour will work as a matte colour, so you're probably better off using a JPG or a transparent PNG if necessary. This logo is pretty simple, so it'll be ok at 8 colours, giving us a nice small file size of just over 1KB. I'll repeat this process for each user slice, and then I'm ready to save the images.
30
Save settings
When you've optimised all your image slices, click Save to open the 'Save Optimised As...' dialog box. I need to change some of the settings here. First I'll click on the 'Save as Type' dropdown, and select 'images only'. Photoshop can automatically create HTML along with your slices to create a web page, but I've already written my nice clean HTML, so I don't need Photoshop's semantically incorrect HTML. Next I'll click on the 'Settings' dropdown, and choose 'other'. In the Output Settings dialogue box, you can choose how you want your files to be saved. In the 'File Naming' section, I'll select 'slice name' in the first dropdown, and '.ext' in the last, and make sure all the other dropdowns are set to 'none'. This ensures that the file name will be the slice name plus the file type extension. I'll make sure I deselect the 'Put Images in Folder' checkbox as I'll select the folder myself when I save. Click OK.
Now I'll click on the 'Slices' dropdown, and I can choose to save all slices (user and auto), all user slices (all the slices that I created) or selected slices (only the slices that I selected in the preview pane). Since I don't need any of the auto slices, I'll select 'All user Slices'. In future, if I need to edit an image, I just need to select the images slice in the preview pane and then choose 'selected slices' from the slices dropdown to save that slice only.
Web Design from Scratch, 2008
31
Now I'll navigate to the root folder of my site (where index.html is kept) and create a folder called 'images'. This is where all the sliced images will be kept. I hit save, and all my slices will be saved into the image folder. It's that simple. Now I have all the website images ready, so I just need to apply some styling to the page using CSS.
32
... <title>Mortgage News</title> /> <link href="css/styles.css" rel="stylesheet" type="text/css" </head> ...
HTML
This won't have any effect right now, but it means that when you start to add CSS styles to the stylesheet, the changes will automatically be reflected in the browser. I'll start with some general styles before I move on to styling specific page elements.
Global Reset
If you've built websites before, you're probably aware that different browsers have different rendering rules. Every browser puts a default margin or padding on certain elements, but it's different for each browser, which makes it difficult to apply your own styles. A lot of web designers get around this by putting what's known as a 'global reset' at the top of every stylesheet:
* {margin: 0; padding:0;}
33
CSS
This tells the browser not to apply a margin or padding to any element. It can be useful, since it means you can start from scratch and you won't get any unexpected margins throwing your design out of whack. But it's not an ideal solution, as there are certain form elements which can't have their margin and padding restored if it is removed in this way. A better way is to make a list of all the elements from which you want to remove the default margin and padding:
body, p, ul, ol, li, dl, dt, dd, h1, h2, h3, h4, h5, h6, a { margin: 0; padding: 0; }
CSS
If you find later that you've missed an element, you can just add it to the list. This leaves your forms looking tidy, while resetting all the main content elements to no margin or padding. Now I'll put some styles on the <body> tag:
... body { font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 76%; }
CSS
I've set the font-family to Verdana, as this is the font used for content text in the design. This font will now cascade down from the <body> tag, to all other tags, so I'll need to change the font for certain other elements. I've set the font-size to 76%. If I then set all other font-sizes in ems, then text will display at the same size across most browsers (see http://www.thenoodleincident.com/tutorials/typography/incremental_differences.html)
34
Cross-browser testing
Now I'm at the stage where I'm going to be making regular changes to the stylesheet, so it's important to test the page in several different browsers at regular intervals, to make sure it's behaving the same in all browsers, and if not, to fix the errors before you lose track of what has caused them. I test in Mozilla Firefox, Internet Explorer 6 and 7, Opera and Safari. Header Now I'll start from the top of the page and work down, applying styles as I go, while trying to keep my HTML semantically correct. I need to put the gradient background on the header. You might be tempted to apply it as a background image on the header <div>, but since the gradient needs to span the width of the page it 's a better idea to put it on the <body> tag. That means I can set the width of the header div without the need for an extra <div> tag. The width of the design (at normal text size) is 750px, which I found to be equal to about 62em.
... body { font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 76%; background: url(../images/header-bg.gif) repeat-x; text-align: center; } #header { height: 97px; width: 62em; margin: 0 auto; text-align: left; }
CSS
'repeat-x' makes the 1-pixel wide gradient image repeat horizontally across the page. I've added the height and width of the header, and I've set the left and right margins to auto, which will centre the header on the page. I've also set text-align to center on the body, because the automatic margins don't work on IE5. For this reason, I've set text-align to left on the header to get it back to normal. Note: Less than 2% of users are still using IE5 so you shouldn't spend a lot of time trying to get your designs to work on it, but if it's an easy fix then it's still worth doing.
35
From now on I'll be testing the design in different browsers, so I'll use icons on the screenshots to show which browser I'm using: Firefox Internet Explorer 7 Internet Explorer 6
Looking at the page in a browser now, you'll see that all the text below the header is centred on the page because of the text-align: center on the body. Don't worry about this, I'll fix it later. You can also see how there's no margin or padding on any of the text, as I intended, and the header background is in place. 36
Logo I'll put in the link to the logo image that I left out of the HTML earlier:
... <div id="header"> <a href="/"><img src="images/logo.gif" alt="Mortgage Services home page" /></a> <ul> ...
HTML
Images have a border around them by default, so lets take that off. I won't want the default thick blue border on any images, so I can apply the style to all <img> tags:
... img { border: none; }
CSS
Links The logo and the links need to be positioned side by side, with the logo on the left, and the links on the far right. This can be done by simply leaving the logo where it is but adding a top margin to push it into position, then absolutely positioning the <ul> from the right and bottom of the header. In this way, when the browser's text size is increased, the links will enlarge upwards into the header, instead of downwards out of the header:
... #header { height: 97px; width: 62em; margin: 0 auto; text-align: left; position: relative; } #header img { margin-top: 40px; } #header ul { position: absolute;
37
CSS
Note: When absolutely positioning an element within a parent element, be sure to set the parent element to position: relative. Here I want to position the <ul> within the header <div>, so I've made the header position: relative.
Now to make the links look like they do in the design. First I'll add a float: left to the <li> elements, so that they are positioned side by side. Then I'll add a 1-pixel blue border to the left of the <li> elements with some padding to keep it away from the text, and change the font and text colour of the links. I'll remove the underline from the links, but have it reappear when you hover over them, to make it obvious that they are links. I'll also remove the bullet points which Firefox automatically puts on a <ul>, using list-style: none
... #header li { float: left; border-left: 1px solid #000066; padding: 0 10px; list-style: none; } #header li a { color: #000066; font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; text-decoration: none; } #header li a:hover { text-decoration: underline; }
CSS
Almost there, but since I put the blue border on the left of the list items, I now have a vertical bar to the left of each link, whereas there should only be one between the links. I need an efficient way to remove the leftmost border. I used to think that the only way to do this was to give a class name to the first menu item only, and then remove the border on the first <li> only. I recently discovered another technique, which doesn't require a class name, and therefore leaves the HTML unchanged. Instead of removing the border, you can just hide it using the little-known CSS property, clip. The clip property allows you to take any element and specify a rectangular portion of it to be displayed. The rest of the element will be hidden, kind of like a mask in Photoshop.
Web Design from Scratch, 2008
38
... #header ul { position: absolute; bottom: 20px; right: 0; clip: rect(auto auto auto 1px); } ...
CSS
The clip property requires a shape value (rect is the only valid shape in CSS2, but other shapes are expected in CSS3), and 4 values (top right bottom left) to determine the offset of the clipping area from the edge of the element's box. A value of auto means that the given edge of the clipping area will be the same as the edge of the element's box (no clip). So here I have specified that the top, right and bottom edges of the clipping area will be the same as the edges of the <ul>, but the left edge should be clipped by 1 pixel, thus hiding the 1-pixel border which rests against the left edge of the <ul>. Note: The clip property can only be used on absolutely positioned elements. If the element can't be absolutely positioned then you may have to use another method. That's all there is to it. Now, even if more links are added to the list, the leftmost border will always be hidden automatically, and our HTML remains semantically correct. Note: You could achieve the exact same effect with the border on the right of the <li> elements, and by clipping 1 pixel off the right instead of the left.
39
Navigation
Now for the tricky part, the two level navigation menu. I'll first attempt to style the navigation as it is, but it may well be the case that I'll need to alter the structure of the submenu to achieve the required design. CSS comments Comments in CSS are written in a different way from HTML comments, instead of using the <!-- . . . --> notation, you use /* . . . */ Everything between the two asterisks will be ignored. You can (and should) use comments to explain certain CSS rules that might not be self-explanatory. If another web designer tries to edit your CSS later, these comments can be very useful. You can also use them to temporarily disable whole chunks of a stylesheet, if you're having trouble finding the cause of a problem. I also like to use comments as section headings, so I can easily find a certain section just by scrolling down the page. I'll add a comment to denote the start of the navigation section. Now, the main-nav <ul> needs to be contained within the same width as the header, but the background needs to stretch to both sides of the window, so I'll need to wrap the <ul> inside a <div> which will contain the background image. I'll give this <div> an id name of navigation, and set the background position to 100% vertical so that it sticks to the bottom of the main menu. I'll also put the same green from the gradient as the background colour, so that if the text is enlarged and the bar expands vertically, the green background will fill the gap. I'll give the navigation div a height of 3.1em, which corresponds to the 38 pixel background image.
... </div><!-- end header --> <div id="navigation"> <ul class="main-nav"> <li id="about"><a href="#">About us</a> ... </ul><!-- end main-nav --> </div><!-- end navigation --> ...
HTML
... /* ---- navigation ---- */ #navigation { background: #5EEC7F url(../images/mainnav-bg.gif) repeat-x; background-position: 0 100%; height: 3.1em;
40
CSS
Now, to position the menu in the center of the page, I use the same technique for the main-nav ul as I did for the header content:
CSS
Background images for hover states For hover state images, it's usually best to use a single image and change the position of the image on hover to display the hover state. e.g. Hover state Normal state This prevents the image from flickering when you hover over it, as can happen if you use two separate images and replace one with the other on hover. However, our menu design is quite complex, in that it contains a gradient on both the normal and hover states, and it is required to expand vertically as the text size is increased. So a single image for both states wouldn't work. Fortunately, I already have the light green gradient as a background stretching all the way across the screen, so I don't need to worry about the image flickering. I can go without an image for the normal state and simply add the following image for the hover state:
41
I've made it much wider than necessary, so that it will still look right at large text sizes, and I just need to position it at 50% horizontally and 100% vertically. Next I'll make the list items display inline and float left, so that they line up side by side instead of stacked on top of each other.
CSS
Your page is going to look messy for a while, but don't worry, it'll start to come together very soon.
Now I'll style the main-nav links. They need to be display: block so that they will stretch to fill the list item elements. I'll change the font properties to match the design, and remove the underline.
... ul.main-nav li a { display: block; color: #fff; font-family: "Myriad Pro", Arial, Helvetica, sans-serif; font-weight: bold; font-size: 1.3em; text-decoration: none; }
CSS
42
It's far too crowded in there, let's hide the subnavigation. Targeting any unordered list within the main-nav unordered list, I'll set the display to none so the browser won't show the submenus. I also need to set the width of the submenus, otherwise they will stay trapped inside the width of the parent menu item. I've realigned the text to the left, so that the submenus sit directly underneath their parent menu items.
... ul.main-nav ul { display: none; width: 62em; text-align: left; }
CSS
Better. Now I'll give the links some padding. I also need to get the text aligned to the vertical centre of the unordered list, so I need to make the link's line height the same as the list item's height. However, since I've increased the font-size to 1.3em, I need to decrease the line-height accordingly. Instead of 3.1em, I'll use 2.4em.
... ul.main-nav li a { display: block; color: #fff; font-family: "Myriad Pro", Arial, Helvetica, sans-serif; font-weight: bold; font-size: 1.3em; text-decoration: none; padding: 0 0.5em; line-height: 2.4em; }
43
CSS
Perfect! Now I need to deal with the subnav. I need a way to make it so that if you're on the mortgage page, say, then only the mortgage subnav is displayed. This can be achieved through the use of body classes. If you give the body tag on each of your pages a distinct class name, then it's possible to target a particular subnav by giving it's parent <li> the same class name, and have it display only if it's class name corresponds to the body class. An example will make things clearer. First I'll give the body tag a class name of about (let's imagine this is the about page, since there is no navigation item for the home page). I also need to give the list item which contains the about submenu the same class name.
... </head> <body class="about"> <div id="header"> ... ... <ul class="main-nav"> <li class="about"><a href="#">About us</a> <ul> <li><a href="#">About Mortgage Services</a></li> <li><a href="#">Our history</a></li> ...
HTML
Next I'll target the 'about' subnav by applying a style only to any unordered list which is within a list item with class name 'about', which in turn is within another element (in this case the body tag) with class name 'about'. In this way, if the body class is anything other than 'about', then the about submenu will stay hidden. In order to make it visible on the about page, I need to set display to block (to override the display: none that I set earlier). Now I need to position it. It needs to be positioned relative to it's parent menu item, and it also needs to be removed from the flow of the page so that it won't interfere with the subsequent menu items. For this purpose, the only solution is absolute positioning. I'll position it 3.1 em from the top of its parent <li> (which needs to be set to positon: relative) and 0 pixels from the left. I've also included a CSS comment to show that this
Web Design from Scratch, 2008
44
... ul.main-nav li { display: inline; float: left; position: relative; } ... /* display subnav for selected page */ .about li.about ul { display: block; position: absolute; top: 3.1em; left: 0; }
CSS
Well, there won't be any visible difference yet, because the subnav is currently white text on a white background, so I need to somehow implement the blue background from the design. Again, I can't put the background directly onto the subnav <ul> because it needs to span the width of the page, so I'll have to use an extra div after the navigation div to hold the background image, again including the blue background colour to fill the gap if the text is enlarged. The div needs a height on it to make it visible as it has no contents. You should try to avoid empty divs which are just used as background image holders. In some cases it is unavoidable for design purposes, but try to keep them to a minimum!
... </div><!-- end navigation --> <div class="subnav-bg"></div> <div id="content"> ...
HTML
... .subnav-bg { background: #94DDF6 url(../images/subnav-bg.gif) repeat-x bottom; height: 3.4em;
45
CSS
Ok, the blue background is in place, I just need to style the subnav links correctly.
... ul.main-nav li ul li a { font-weight: normal; }
CSS
Perfect. Now I'll have to repeat the process for each submenu, giving each list item a class and targeting it through the CSS. Since the styles will be the same for each submenu, I can just use one CSS declaration, and apply it to all of the submenus at once, separating them with commas:
... .about li.about ul, .mortgages li.mortgages ul, .protection li.protection ul, .insurance li.insurance ul, .loans li.loans ul, .conveyancing li.conveyancing ul, .cutyourbills li.cutyourbills ul, .contactus li.contactus ul { display: block; position: absolute; top: 3.1em; left: 0; }
CSS
Web Design from Scratch, 2008
46
I'll have to remember to change the body class when creating the new pages later. Now to add the hover states. Hover states As I mentioned earlier, to set the hover state for the main navigation, I just need to apply the background image at 50% horizontally to centre the asterisk and 100% vertically to make it stick to the bottom of the link element. I also need to add 10 pixels of padding to the bottom of the links to allow space for the asterisk image and blue background to show underneath the main navigation.
... ul.main-nav li a { ... padding: 0 0.5em 10px; line-height: 2.4em; } ul.main-nav li a:hover { background: #5ED67A url(../images/mainnav-bg-hover.gif) norepeat; background-position: 50% 100%; }
CSS
That works, but now the green arrow and asterisk are also displayed when you hover over the subnav, I need to make sure they only show up on the main navigation. Instead I'll restore the underline for the subnav hover state.
... ul.main-nav li ul li:hover, ul.main-nav li ul li a:hover { background: none; text-decoration: underline; }
CSS
47
Now, it would be nice if the main navigation link was highlighted whenever you are in that section, not just when you hover over a link. This is known as an 'on state', which makes it clear at a glance which section you are in at any time. To add an on state, I'll use the body classes and <li> classes that I set up earlier to display the submenus. Again, the styles will be the same for each one, so I only need one CSS declaration:
... /* on state for selected page */ .about li.about a, .mortgages li.mortgages a, .protection li.protection a, .insurance li.insurance a, .loans li.loans a, .conveyancing li.conveyancing a, .cutyourbills li.cutyourbills a, .contactus li.contactus a { background: #5ED67A url(../images/mainnav-bg-hover.gif) norepeat; background-position: 50% 100%; }
CSS
Now the on state is shown, but it also cascades down to the submenu links, so I need to remove the background from those links. Rather than doing this explicitly, I can just add child combinator selectors (>) to the code for the on state, so that it only applies to links that are direct descendants of the main-nav list items.
... /* on state for selected page */
48
.about li.about > a, .mortgages li.mortgages > a, .protection li.protection > a, .insurance li.insurance > a, .loans li.loans > a, .conveyancing li.conveyancing > a, .cutyourbills li.cutyourbills > a, .contactus li.contactus > a { background: #5ED67A url(../images/mainnav-bg-hover.gif) norepeat; background-position: 50% 100%; }
CSS
That completes the menu, but if you look at it in Internet Explorer 6 you'll see a problem:
49
This looks bad, but don't panic, it can be easily fixed. The problem is IE6 doesn't like the fact that I've made the links display: block inside the list items which are display: inline, so it's stacking them on top of each other. I can fix this by setting the links to display: inline-block, but I need a way to make this happen in IE6 only, while leaving the other browsers unchanged. Now would be a good time to discuss some of the ways you can tackle interoperability issues, and their various pros and cons.
Browser hacks
Browser hacks take advantage of invalid HTML markup and browser parsing errors in order to target certain browsers only so that you can specify different styles for browsers that are misbehaving. One of the most commonly used hacks is the '* html' hack, which is used to fix IE6 issues. The <html> tag is supposed to be the highest level element in any web page, but for some reason IE6 (and below) allows you to target a non-existent parent element, which all other browsers ignore. So any styles applied to * html, will only be displayed by IE6. e.g.
* html ul.main-nav li a { display: inline-block; }
CSS
This would apply the inline-block display in IE6, but other browsers would ignore it and leave the disply set to block. There are a variety of other hacks which use similar methods to fix browser bugs, but I try to avoid using them unless I can't find an alternative solution. One reason is that they rely on browser bugs, so there is no guarantee that they will still work correctly for future browser releases. They result in invalid CSS markup, and they're just plain messy. A cleaner way to achieve the same results is with alternate stylesheets.
50
Alternate stylesheets
Alternate stylesheets allow you to provide a separate CSS file for your buggy browser. You then use conditional HTML comments in your main page, to specify which browser should use this alternate stylesheet. e.g.
... /> <link href="css/styles.css" rel="stylesheet" type="text/css" <!--[if lt IE 7]> <link href="css/IE6.css" rel="stylesheet" type="text/css" /> <![endif]-->
HTML
The conditional statement [if lt IE 7] targets any version of Internet Explorer prior to version 7, and tells it to use the stylesheet called IE6.css You then need to create this stylesheet, and put in it any styles required to fix problems with IE6 or lower. This method still has it's problems. HTML comments were not designed to contain conditional statements, so it is still a hack of sorts, but it means you don't need any invalid CSS hacks, and it keeps the IE styles separate from the main styles, so I find this a much better solution than CSS hacks.
Javascript fix
It's also possible to use Javascript to make bad browsers behave better. Dean Edwards (http://dean.edwards.name) has written IE7 scripts, which make IE6 behave more like IE7, and even fix some of the problems still present in IE7. You can link directly to the scripts, which are hosted by Google, again using conditional comments to target IE6 only. This is a nice method, as in theory it means you don't need any alternative styles, but it's not a complete fix, and you will still find that there are some problems with IE6. For this example, I'm going to use an alternate stylesheet for IE6. So I'll create a new blank CSS file in the css folder, and save it as IE6.css In here, I need to put in the styles that need to be changed in IE6. So I'll change the display to inline-block for the links.
ul.main-nav li a {
51
display: inline-block;
IE6.CSS
That had the desired effect, but there's still a problem. The 10 pixel bottom padding I put on the links is showing background colour, so the main-nav bar appears bigger than the subnav bar. So, still in the IE6.css stylesheet, I'll apply a negative top margin to the subnav div.
IE6.CSS
So that's the navigation completed, and it wasn't quite as challenging as I expected. Let's move on to the main page content.
Main Content
First I'm going to need to wrap the 3 main sections inside another div so that it can be positioned to the left, separate from the sidebar links. I'll give this div a class name of main-content. Then I'll left-align all the text in the content section, and float the main-content div to the left, with a width of 42em . I'll also give the content div a width. It needs to be narrower than the header and navigation divs, so I'll set it to 54em.
Web Design from Scratch, 2008
52
... <div class="main-content"> <img src="" alt="" /> <h2><a href="#">Interest rates set to rise</a></h2> ... <h2><a href="#">Recommended: Alliance & Leicester</a></h2> <p>Duis laoreet . . .</p> </div><!-- end main-content --> ...
HTML
... #content { text-align: left; width: 54em; margin: 0 auto; } .main-content { float: left; width: 42em; }
CSS
This is going to cause the footer to also wrap to the right of the main-content section, so I need to apply a clear to the footer div. I only need to clear the left float, but it's a good idea to clear both anyway, just to make sure the footer won't be affected by any floats which might be added later. While I'm at it, I'll make the footer navigation list items display inline, and remove the bullet points.
... #footer { clear: both; } #footer li { display: inline; list-style: none; }
CSS
53
That puts everything in roughly the right place, now I just need to add some styles. The h1 tag will be the same on every page, so I can apply it's styles directly, I don't need to specify that it should only apply to h1 tags within the content area. I put these 'global styles' at the top of my stylesheet, so that they can be overridden by subsequent styles if necessary.
... h1 { font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; color: #009900; font-size: 2.7em; font-weight: normal; padding: 0.8em 0 0 0; }
CSS
Next I'll style all the <p> tags. The text in the paragraph under the main heading is bigger than the text in the main-content section. I'll set all <p> text to this larger size, and then specify that the text in the main-content section should be smaller. I'll also add some padding to the top and bottom of all paragraphs.
... p { padding: 0.5em 0;
54
font-size: 1.2em;
CSS
Since the main sections contain repeated elements, and I want to style them all at once, I'll wrap each one in a div element and give it a class name of 'article-summary', then I can apply styles to all of the elements within the article-summary divs. The images need to be floated left, so that the text will wrap around them. I'll give them a 1 pixel grey border, and some right and bottom margin to keep them away from the text. Also, if the paragraph text does not take up as much vertical space as the image, then the following image will also wrap to the right, so each article-summary div needs a clear:left to force it onto a new line.
/* ---- article summary boxes ---- */ .article-summary { clear: left; } .article-summary img { float: left; border: 1px solid #ccc; margin: 0 20px 20px 0; }
CSS
Now I'll add a margin to the left and right of the paragraphs and second-level headings, to keep them away from the surrounding content. Setting these margins in ems means that the line length with remain the same as text is enlarged. I'll also set the size and colour of the heading links. I've decided to change the design slightly. As these are links, I'll leave them as the default blue, so that they're obviously clickable, remove the underline, and restore it for the hover state.
... .article-summary p { margin: 0 3em 0 12.5em; } .article-summary h2 { font-size: 1.2em; font-family: Arial, Helvetica, sans-serif; margin: 0 1em 0 10.4em; } .article-summary h2 a {
55
text-decoration: none;
CSS
The introductory paragraph is too close to the header and the content div, so I need to add some padding to this <p> tag. I can use the child combinator selector (>) to target only those <p> tags which are direct descendants of the content div. That means the padding will be applied to the paragraph directly within the content div, but not to any paragraphs contained within other elements within the content div.
56
CSS
1em is enough padding between the paragraphs, but I still need more space between the paragraph and the start of the content, so I'll add some top margin to the main-content div and the sidebar content (I'll give the sidebar <ul> a class name of 'secondary-links'). It's good practice to use meaningful class names which describe the content, rather than the layout of any given element. For example, here I've used the name 'secondary-links', rather than 'sidebar' or 'rightcolumn', as they only describe the placement of the element, which could easily be changed later. For more on choosing meaningful class names, see Ben Hunt's ebook Semantic HTML)
... .main-content { float: left; width: 42em; border-right: 1px solid #ccc; } .main-content, .secondary-links { margin: 2em 0 0 0; }
CSS
I've also added the 1-pixel grey border to the right of the main-content div.
57
Now I'll style the secondary links. Firstly, notice that each link needs a different background image. This means I need to give each list item a unique id. Again I'll choose meaningful names based on the content of the link
58
... </div><!-- end main-content --> <ul class="secondary-links"> <li id="quotes"><a href="#">Free quotes</a></li> <li id="contact"><a href="#">Contact us</a></li> <li id="tips"><a href="#">Our hot tips</a></li> </ul> </div><!-- end content -->
HTML
Now I need to add a left margin to the list, to keep it away from the grey border on the maincontent div. That div is 42em wide, so the links will need to have a left margin of 44em. I'll also remove the bullet points.
... /* ---- secondary links ---- */ .secondary-links { margin-left: 44em; } .secondary-links li { list-style: none; }
CSS
Now I'll give the links some styles. They need to be display block, so that I can give them a height to make the background images show. I'll give them some left padding to make room for the images, and some top padding to push the text down slightly. The height is the height of the images, 75 pixels. I've also removed the underline, and restored it on hover.
... .secondary-links li a { display: block; padding: 10px 0 0 60px; height: 75px; text-decoration: none; } .secondary-links li a:hover { text-decoration: underline; }
59
CSS
Now I just need to add the background images for each link.
... .secondary-links li#quotes a { background: url(../images/quote-icon.jpg) no-repeat top left; } .secondary-links li#contact a { background: url(../images/mail-icon.jpg) no-repeat top left; } .secondary-links li#tips a { background: url(../images/tips-icon.jpg) no-repeat top left; }
CSS
60
61
Footer
It's a simple task to style a text-only footer. You just need to give it some top margin and space out the links a bit and you're done. But in this example, I have a gradient background on the footer, and I want to make it stick to the bottom of the page, even if the content doesn't take up the vertical length of the screen. I'm going to show you a nice trick which lets you achieve this effect. First I need to put an extra <div> around everything which is NOT the footer. I'll give this the descriptive class name 'non-footer'.
... <body class="about"> <div class="non-footer"> ... </div><!-- end content --> </div><!-- end non-footer --> <div id="footer"> ...
HTML
Then, in the stylesheet, I need to specify that both the body tag and the html tag should have 100% height.
CSS
I'll then add some styles to .non-footer, making it position relative (the footer also needs to be set to position relative), and a minimum height of 100%. The footer div needs a height of 3.75em to contain the background image, and an equal line-height to align the text in the vertical centre. Now the 100% min-height on .non-footer will push the footer off the bottom of the page, so I need some negative top margin to bring it back up. I'll also add some padding to the bottom of the main-content div, to keep it away from the footer.
... .main-content { float: left;
62
#footer { clear: both; background: url(../images/footer-bg.gif) repeat-x bottom; height: 3.75em; line-height: 3.75em; margin: -3.75em 0 0 0; position: relative; }
CSS
The problem is that IE6 does not support the min-height property, so in my IE6.css alternate stylesheet, I'll specify that the height of .non-footer should be 100%.
... .non-footer { height: 100%; }
IE6.CSS
Then I'll just style the links appropriately . . .
... #footer li a { color:#0066cc; text-decoration: none; padding: 0 0.8em; font-size: 0.9em; } #footer li a:hover { text-decoration: underline; }
CSS
Comparing with the original Photoshop document (see page ), I'm happy that the page is true to the original, and a quick check tells me that it works in all major browsers, so that's it, we're done! You can check out the working version of the page at http://webdesignfromscratch.com/webproduction1/index.html
Web Design from Scratch, 2008
63
64
65
Summary
I hope this book has been useful in helping you understand the best way to approach web page production. We've looked at the choices you need to make when deciding how to structure your page, the benefits of starting the process with semantic HTML, how to slice up a Photoshop design, and how to style your page using CSS. There is still a lot more information about web page production, but it's impossible to fit it all into a single ebook, so keep an eye on http://webdesignfromscratch.com/downloads.cfm for future releases. Thanks for reading!
66