The Tutorials
Tutorial 6 - Divs / CSS Layout
Tutorial 6 - Divs / CSS Layout
In our previous tutorials, we've seen lots of little elements that can be part of a page. Now, we're coming to the end of what there is know about HTML, and we'll start exploring more advanced concepts in CSS. As you'll soon see, CSS is the key to making our webpages look exciting! But, before we can really go into it, we're going to need a powerful new element called <div>.
Getting started.
- Download the Tutorial 6 files. Unzip them so that you see the "Tutorial 6" folder.
A simple div
We're going to start thinking of website development in a whole different way, so, to signal this new beginning, we're going to start with a familiar-looking example. Go ahead and look at the code for simple.html. It looks pretty much the same as "Hello World!", the first HTML page we ever made, right? Only now, the paragraphs are surrounded by a <div> ("division") tag. But, if you look at the page in your web browser, it doesn't look like the <div> changed anything.
So, what's a div, anyway? A div is like an invisible box that we can surround elements with to sort of group them together. To prove that the div's there, let's add in a CSS rule that will color the div's background:
.simple {
background-color: #ABC;
}
We can see that there is, in fact, a div around the two paragraphs. We can also see that the default width of the div is "as wide as possible," while the default height of the div is "as tall as necessary." Let's go ahead and nail down the width of the div, while keeping the height the same:
.simple {
background-color: #ABC;
width: 300px;
}
The result should look like the following screenshot. Congratulations! This is like "Hello World!", only for the rich world of CSS and div-based layout, which we'll start exploring more now.
The box model
It turns out all elements in HTML are like little boxes. And by "all," we really do mean everything. For example, you know that the <strong> tag puts the text you've surrounded in bold. However, what if we also want these strongly emphasized words to be boxed in red? Try this with simple.html:
Surround the word "world" in a <strong> tag.
Add in this CSS rule:
strong { border: 1px solid red; }The result should look like this:
Even something surrounded with a <strong> tag is a box!
For the next few examples, we're going to be working with two-divs.html.
Border
We've used borders a lot in some of the earlier tutorials, but here, we'll introduce it properly. First, take a look at what two-divs.html looks like. It's just two divs of equal size, with one stacked directly on top of the other. Now, let's add a border to the bottom box:
.box2 {
width: 200px;
height: 200px;
background-color: #007BAD;
border-style: solid;
border-color: black;
border-width: 4px;
}
A border consists of three properties: a style, and color, and a width.
- Style: This specifies what the border looks like. In all our examples, we've said the border should just be a solid block of color, but other popular values are "dotted" and "dashed". Try changing border-style to one of those values, and see what it looks like. You can also look up a complete list of available border styles here.
- Color: The color of the border, which is just like any other CSS color.
- Width: How thick the border is. You can use any standard CSS unit of length, like px, em, or %.
We can also set all three of these properties as follows:
border: 4px solid black;
We can also set the top, left, right, and bottom borders individually. For example, there exist border-top-style, border-top-color, and border-top-width, which only affect the top border. Similarly, they can all be combined into one by saying:
border-top: 4px solid black;
And so one for border-right, border-left, and border-bottom.
Notice that, at this point, the bottom box is wider than the top box. But, didn't we say that they were both 200 pixels wide? It turns out that the border is outside the box, so the total width of the box is 200 + 8 pixels (4 on each side) = 208 pixels. Knowing this detail will be useful when we're doing CSS layouts with divs that have borders.
What we've got so far:
Margin
One thing we might notice is that the boxes are awfully close to each other. In fact, there's no space whatsoever between them. We can add in some space by using the margin property:
.box2 {
width: 200px;
height: 200px;
background-color: #007BAD;
border: 4px solid black;
margin: 10px;
}
As you can see, margin puts space around the outside of the box. Just as with border, we can set the margins on the top, right, left, and bottom sides individually, using margin-top, margin-right, margin-left, and margin-bottom. If we want to set different borders all at once, we can also do that, by giving margin more than one length, summarized by W3Schools as follows:
-
margin: 25px 50px 75px 100px;
- top margin is 25px
- right margin is 50px
- bottom margin is 75px
- left margin is 100px
-
margin: 25px 50px 75px;
- top margin is 25px
- right and left margins are 50px
- bottom margin is 75px
-
margin: 25px 50px;
- top and bottom margins are 25px
- right and left margins are 50px
-
margin: 25px;
- all four margins are 25px
Notice that the bottom box is not lined up with the top box. This is because it has a margin to the left, while the top box doesn't. Let's get rid of this left margin using one of the above rules:
.box2 {
width: 200px;
height: 200px;
background-color: #007BAD;
border: 4px solid black;
margin: 10px 0px;
}
This sets the top and bottom margin to 10 pixels, and the left and right margins to 0 pixels (ie, no margin at all). Let's also move the top box so that the blue parts of both boxes are lined up. That is, the left margin of the top box should be equal to the width of the bottom box's left border:
.box1 {
width: 200px;
height: 200px;
background-color: #ABC;
margin-left: 4px;
}
This is what we now have:
Padding
Finally, we might find it annoying that the text inside the boxes is right up against the blue edge, when it would look nicer if there were some space in between. This is where padding comes in. "Padding" is exactly like margin, only it adds in a space around the inside perimeter of the box, rather than the outside. So, try adding in this code:
.box2 {
width: 200px;
height: 200px;
background-color: #007BAD;
border: 4px solid black;
margin: 10px 0px;
padding: 10px;
}
See what it looks like! Now, there's space between the text and the edges of the box, which is what we wanted.
As with margin, you can set the top, right, left, and bottom paddings individually, or all at once, following all the same rules.
Now, have you noticed that the blue part of the bottom box is bigger than the blue part of the top box? How can this be, if we set both divs to have a width of 200 pixels? This is a tricky thing you have to be careful about. In order to make that 10 pixel padding, the text wasn't just "pushed" 10 pixels inwards. What happened was that we made the box 10 pixels bigger on each side inwards. So, while the actual div, which consists of the text, "This is the second box." is still 200 pixels wide, the box that holds it is now 200 + 20 (10 pixels on each side) = 220 pixels wide. As proof, make the top box 220 pixels wide, and notice that the blue parts line up, while the text doesn't.
.box1 {
width: 220px;
height: 200px;
background-color: #ABC;
margin-left: 4px;
}
This should be your final result:
Summary of the box model
This diagram summarizes the box model:
The red line on left proves that the text is not aligned, even if the blue parts are. The red box represents the actual 200px by 200px "content" area that we originally represented with our div. After adding in the padding, border, and margin, the div now takes up more space, but the content area stays the same size, so we'll always have 200 pixels for the text.
Now, let's just look at the bottom box. We said in our CSS rules that it would be 200 pixels high, but how much vertical space does it actually take up? Well, we know it also has 10 pixel padding on both the top and bottom, so that's 20 pixels extra. Then, it has a 4 pixel border on both the top and bottom, so that's 8 pixels extra. Finally, it has a 10 pixel margin on the top and bottom, so that's another 20 pixels extra. So, overall, it takes 200 + 20 + 8 + 20 = 248 pixels of vertical space!
Practice 1
Again, the space you set aside for content can be very different from the actual space the div takes up. Knowing the actual amount of space a div takes up by factoring in the margins, borders, and padding will be important for precise CSS layout, later on. Can you figure out the actual space taken up for the following things? Highlight the gray boxes for answers.
- Horizontal space of the bottom box:
228 pixels. It has a 4 pixel border on its left and right sides, as well as a 10 pixel padding on the left and right. It doesn't have any left or right margin. So, that makes 200 + 4 + 4 + 10 + 10 = 228.
- Horizontal space of the top box:
210 pixels. It has a left margin of 10 pixels, but no right margin. It has no padding or border, so that makes 200 + 10 = 210 pixels.
- Vertical space of the top box:
200 pixels. It has no borders or padding, and no top or bottom margin (it only has a left margin).
Some useful CSS
We're going to go over two extra things in CSS that will be useful for doing layouts. First, we're going to review and go more in-depth with CSS selectors. Second, we'll go over a major way in which elements can be classified. Finally, we'll go over an extremely handy CSS property known as float.
CSS selectors
We've already seen and used CSS selectors before. Open up selectors.html. You're probably already familiar with everything there:
-
p { ... }This rule applies to all p tags.
-
.quote { ... } #author { ... }.quote applies to all objects that are of the "quote" class. #author applies to the object specifically labeled with the ID "author".
-
One interesting thing you can do is that you can say an element belongs to more than one class. We just write in all the classes we want the element to belong to, separated by a space. For example, <p class="long quote"> means this paragraph belongs both to the "long" class, and to the "quote" class. This way, both the CSS styles for "long" and "quote" will apply to that paragraph.
-
p strong { ... }We haven't used this as much, but it will be very useful. This is known as a descendant selector. This rule will apply if the <strong> tag is anywhere inside a <p> tag. A descendant selector is slightly different from what we'll look at next, a child selector.
Note that you can string together as many descendant selectors as you want to narrowly target certain elements. For example, p a strong { ... } only applies to <strong> elements that are inside <a> elements that are inside <p> elements.
Now, here are some CSS selectors you might not know:
- Child selectors:
Computer scientists often make use of familial relations as analogies for their code. Consider the first pargraph of selectors.html, where we see this:
<p class="long"> Look again at that <a href="http://photojournal.jpl.nasa.gov/catalog/PIA00452"> <strong>dot</strong> </a> ...Here, we have an <a> tag inside a <p> tag. So, we say that <a> is a child of <p>. In turn, we have a <strong> tag inside the <a> tag, so we say <strong> is a child of <a>. In keeping with the family analogy, that means that <strong> is a grandchild of <a>.
In this sense, that means <strong> is a descendant, but not a child, of <a>
. Keeping this in mind, let's change the CSS rules now, so that it looks like this:p > strong { color: #007BAD; }Adding in the extra > makes this a child selector. That is, the rule will only apply to <strong> tags that are directly children of <p> tags. Can you see what affect that has on selectors.html? The word "dot" in the last two paragraphs are still in our special shade of blue, #007BAD, but the "dot" in the first paragraph is a grandchild of <p>, not a child, so it doesn't count. Instead, it ends up being the same color as a regular link.
- Adjacent selectors
Let's say we to increase the spacing between the paragraphs. We could try to just modify the margin-top property like this:
p { font-family: Sans-Serif; margin-top: 3em; }However, this looks a little odd. We don't want all that extra space at the top. Somehow, we want to say, "put extra margin on the top for all the paragraphs except the first one." One possible solution is to give the first paragraph a special class like "firstParagraph", and then add in a CSS rule so that it has no top margin. However, that might be difficult to manage if you want to change around the order of your paragraphs.
One neat CSS trick we can do, instead, is to use an adjacent selector. Change the CSS rules in selectors.html to this, instead:
p { font-family: Sans-Serif; } p + p { margin-top: 3em; }Take a look at the result. Perfect! The first paragraph doesn't have a top margin, but all the subsequent ones do. What the + means is, "apply this rule only to paragraph tags that are after another paragraph tag." This will never apply to the first paragraph, because it doesn't have a paragraph in front of it to follow after. But, all the rest of the paragraphs do follow a previous paragraph, so the styling applies to them.
Block-level elements vs. inline elements
We've already seen what a <div> tag can do. But, there's a similar tag called <span>. <span> is sort of like <div>'s little brother. It acts exactly like a div, only you use spans around small amounts of text, rather than paragraphs or images.
We say <div> is a block-level element, while <span> is an inline element. Basically, we use spans around the same kinds of things you would put a <strong> or <em> tag around.
Other HTML elements can also be classified as either block-level or inline elements. Examples of inline elements include:
- <a> (anchor)
- <em> (emphasis)
- <strong> (strong emphasis)
- <sub> (subscript)
- <sup> (superscript)
Examples of block-level elements include:
- <h1> (heading 1)
- <p> (paragraph)
- <ol> (ordered list)
- <ul> (unordered list)
- <table> (table)
As you can see, inline elements generally have to do with text. Usually, you can put inline elements next to each other on the same line. Block-level elements, on the other hand, tend to be bigger, and take up multiple lines. Also, you can't really put block-level elements side-by-side. They tend to stack on top of each other, instead, although we'll see in just a moment how to change that with CSS. Finally, let's just reiterate this point: divs are like generic wrappers around block-level elements, while spans are their inline equivalent.
Floats
float is a common CSS property that we'll set for divs when we do layouts. What it does is specially position an element by moving it as far to the left or right as possible.
For example, open up quote.html. You can see that we have a long quote in a box, and then a single sentence from that quote that we want to feature. Usually, when you see a featured quotation like that in a newspaper or a magazine, it's off to the side a little bit, with the rest of the text wrapping around it. We'd like to do something like that. First, let's try making the featured box a little smaller:
.featured {
background-color: #DEF;
padding: 5px;
font-style: italic;
font-size: 1.25em;
line-height: 1.25em;
width: 200px;
}
This should be what you get:
No luck! Just making the featured box smaller won't make the paragraph text wrap around it. That's because the paragraphs are block-level elements, which, as we said earlier, tend to be laid out one on top of the other. What we really need is to bend the rules of the box model a little. That's where float comes in. Try adding this in:
.featured {
background-color: #DEF;
padding: 5px;
font-style: italic;
font-size: 1.25em;
line-height: 1.25em;
width: 200px;
float: left;
}
Bingo! That looks like it did it. Let's just add in a little bit of margin to the top and right of the featured box so that the spacing looks better:
.featured {
background-color: #DEF;
padding: 5px;
font-style: italic;
font-size: 1.25em;
line-height: 1.25em;
width: 200px;
float: left;
margin-top: 10px;
margin-right: 10px;
}
This should be your final result:
However, there's one little complication with floats that might be a little confusing. Let's illustrate this by continuing with our example. Currently, the author of that quote ("Richard Feynman, 1986") is in normal font and to the left. Let's make it so that his name is in italics, and on the right side of the box. Easy, let's just say:
.author {
font-style: italic;
float: right;
}
Oops! What just happened?
The problem here is that we made this span a floating element, by saying float: right; in the CSS. As we said earlier, floating elements bend the layout rules of the box model. What's actually going on is that the element is first "lifted out" of the normal layout, then moved as far to the left or right until it runs into the edge of its containing element, or into another floating element. After that, anything else just sort of wraps around it.
So, in our above example, the author citation was "lifted out" of the layout, and moved all the way to the right, until it reached the edge of its containing element, the quoteBox. Since it's been "lifted out," it's not really in the box anymore, so the bottom of the box is at the end of the last paragraph, which is not floating.
How can we fix this? We'll use another property of divs, called <overflow>, which tells the div what to do when its contents are bigger than the size of the div; that is, when its contents "overflow." Add in this code:
.quoteBox {
border: 4px solid #ABC;
width: 600px;
padding: 10px;
line-height: 2em;
overflow: auto;
}
Now we have what we wanted:
As complicated as this is, there are occasions when this behavior is useful, although we won't provide any examples of this yet. There's also a lot more to learn about <overflow> that we won't go into at this time. If this seems difficult, be assured that these tutorials will take you through many examples of CSS layout involving floats step by step, and anything new or unfamiliar will be explained.
CSS layout
Now, we're going to get into the fun part of web page design: CSS layout. We already have all the tools we need to do this, but knowing how to put it together can be a challenge. To see how all the pieces fit together, we'll work through a step-by-step example that might look a little familiar.
The Guardian 2: Under New Management
Last tutorial, we used tables to make this layout for a newspaper, The Daily Guardian:
However, as we pointed out at the time, table-based layouts are generally a bad idea, because tables can be very picky about how its rows and columns are structured, especially when rowspans and colspans get involved. Instead, we're going to lay out the page by putting every story in their own div, and then modifying the CSS rules to place those divs in the correct location. Are you ready?
Take a look at guardian2.html. We've already retooled it for you, so just spend a minute examining its structure. Every story is in a "story" div. They are also in classes based on the size of the story. Finally, the story divs are inside larger divs grouping the big stories together and the small stories together as follows:
- div - class: mainStories
- div - classes: main, story
- div - classes: medium, story
- div - class: smallStories
- div - classes: small, story
- div - classes: small, story
- div - classes: small, story
If you look at what guardian2.html looks like, that's not very impressive! All the stories are just laid out, one on top of the other without any apparent layout at all. But, it turns out, we're now going to harness the power of CSS to lay this out. The only thing we're going to be doing with guardian2.html from now on is to change the stylesheet that it uses. Let's start with the basic one:
<link rel="stylesheet" type="text/css" href="guardian-style.css" />
Now, open up guardian-style.css. As you can see, all we've done so far is to give all the divs a background color so that we can see where they are. We want to recreate the table-based layout we did in the last tutorial, so the main story should be 2/3s of the page, while all the other stories are 1/3 of the page wide. So, let's add in code to reflect that:
.mainStories {
width: 100%;
}
.main {
width: 67%;
}
.medium {
width: 33%;
}
.smallStories {
width: 100%;
}
.small {
width: 33%;
}
Everything's still stacked on top of each other! Do we remember why? <div>s are block-level elements, so they will be laid out vertically. Now, do we remember the solution? Floats! Let's tell all the stories to float to the left:
.mainStories {
width: 100%;
}
.main {
width: 67%;
float: left;
}
.medium {
width: 33%;
float: left;
}
.smallStories {
width: 100%;
}
.small {
width: 33%;
float: left;
}
We're getting closer, but we've run into a small problem (red lines drawn in for clarity):
What's happening is that pages are normally laid out from top to bottom, left to right. So, the browser first puts down the main and medium-sized stories. Since those are floating, the bottom of the mainStories div is non-existent! Since it consists only of floating elements, there isn't really anything inside the box, so its height is 0. That means that the topmost, leftmost position of the window happens to be that little nook to the right of the main story, and below the medium-sized story.
So, the browser places the first small story into that little nook. Then, it tries to float the first small story to the left until it can't anymore. If you remember, a float stops once you run into the edge of your containing element, or when you run into another floating element. Well, in this case, the small story is already up against a floating element on its left!
So, how do we fix this? We've seen it before: set overflow in the mainStories div. That way, the bottom of the mainStories div is the bottom at the bottom of the larger of the two stories inside of it. You can prove this by giving mainStories a border-bottom in addition to the code below. As a result of this fix, when the small stories get laid out, they start below the main stories:
.mainStories {
width: 100%;
overflow: auto;
}
Now, as we can see from the blue backgrounds, the stories are all pressed up right against each other. Now, we need to use our knowledge of the box model to put some spacing between the stories. Let's put 1% margin on the left and the right of every story. But remember, this also means we need to subtract 2% from the width of every story, since margins grow outwards:
.story {
background-color: #ABC;
margin: 0% 1%;
}
...
.main {
width: 65%;
float: left;
}
.medium {
width: 31%;
float: left;
}
...
.small {
width: 31%;
float: left;
}
That looks a lot better! This should be your final result (remove the background color if you like):
Anyway, here's the situation: The Daily Guardian has come under hard times, and is now under new management. The new bosses think people will be more interested in the paper if the main story were on the right instead of on the left. Let's see how hard this is to do. Modify guardian-style.css as follows, and see what happens:
...
.main {
width: 65%;
float: right;
}
...
The main story's now on the right! And it just happend with the change of a single word!
How about this: last tutorial, we proposed a nightmare situation with table-based layouts. What if management now wants the top two stories to stay the way they are, with the same proportions, but wants four small stories on the bottom, each taking up 1/4th the space? Can you imagine doing this if the the page were laid out with a table? Let's try doing this with CSS instead:
- Uncomment the 4th story from guardian2.html.
- Change the stylesheet for guardian2.html from guardian-style.css to guardian-style-4smalls.css (they are the same, we're just trying to keep our work in separate files).
- Change guardian-style-4smalls.css as follows:
.small { float: left; width: 23%; }
That was easy!
Let's try one more style from the beginning to see how easy this div-based layout makes things now. Here's the story. The Daily Guardian has tried those new layouts, without much improvement in business. They've made the following decision. First, people hate the movie review, so that should be removed, and there should only be three small stories on the front. Second, the main and medium stories should both be on the left side taking up 2/3s of the width, with the main story above the medium story. The three small stories should be stacked up on top of each other on the right side, taking the remaining 1/3 of width. Can we do it?
First, comment or delete the "Movie Review" story from guardian2.html.
Change the stylesheet to "guardian-style2.css"
Open up guardian-style2.css. Since the main stories are going to be on the left, taking 2/3s of the width, let's set the widths of the mainStories and smallStories divs as specified:
... .mainStories { width: 67%; } ... .smallStories { width: 33%; } ...The two divs are still stacked on top of each other, since they are block-level elements. What can we do now to fix this? We can make them floating divs. That way, the browser will float the main stories to the left. The mainStories div will have height 0, so the top of the page is still at the top of the browser window. Then, when the small stories are placed, they will start at the top, and float as far to the left as possible--to the right edge of the mainStories div.
... .mainStories { width: 67%; float: left; } ... .smallStories { width: 33%; float: left; } ...Now, all that's left to do is to add in some margin to the left and right sides of each story, so that they aren't all squashed together. Also remember to reduce the size of the stories accordingly:
... .story { background-color: #ABC; margin: 0% 1%; } .mainStories { width: 65%; float: left; } ... .smallStories { width: 31%; float: left; }
This should be your result:
In some cases, it might be that a table is just as much work as going through all the modifications to the CSS. But, we hope you're now convinced that CSS and div-based layout is far more flexible and powerful. However, we haven't even shown you the biggest advantage to a div-based layout yet! Remember that the whole point of CSS is that you can change the style and layout for an entire website just by changing the stylesheet the pages use. In all of our above examples, we've just been changing the layout for one page. If you're seriously interested in web development, divs and CSS layout are one topic you'll really want to master.
Today, you might be working for The Daily Guardian. Tomorrow, you might be working for The New York Times. Consider this fact: the New York Times' website hosts articles dating back to 1851. This means you can search as far back in their archives as the Civil War! If you click on some of those articles, you can build an appreciation for how the professional web developers at the New York Times have maintained an impeccably consistent styling and layout across their entire site, from the front page, to an old, archived Civil War-era article.
HTML vs. CSS: the philosophy
We'll end with a quick word about the philosophy behind HTML and CSS.
The creation of CSS is supposed to faciliate the fundamental process of separating content from style. Content, which goes in HTML files, consists just of the ideas we want to communicate. It's the reason why the website exists in the first place. Styling, which goes in CSS files, just tells us how to arrange the content in the web browser, what colors to use, and other things related to how the content looks.
We use divs and spans to put a little bit of information in our content about what kind of content it is. For example, are these paragraphs part of the main story, or part of a small story? It can be tempting to just put style information in our HTML files out of convenience, but it's better to avoid it as much as possible.
Think about the example of a newspaper website. It's the journalists' job to do reporting and to write stories. It's your job as the web developer to be creative, and decide how the website will look. Neither of you want to mix your jobs up. You'll find that HTML and CSS can work harmoniously in the same way to make your websites smart, pretty, and easy to maintain.