Prefatory

We’re behind where I wanted to be right now, but that is easily fixed. Review this material, and ensure that you understand how CSS and the box-model work. There’s another short tutorial that I’m proof-reading now, and then I’ll post it. It deals with styling images and introduces the <div> into the mix. I’ve shortened the Second Project to be an opportunity to apply different CSS templates to the Frankenstein text we’d already put into HTML. It shouldn’t take very long to do, but it will give us a chance to talk about specific styling choices and why they work (or not). The Third Project will focus on implementing a responsive flex-grid; the additional stuff (about static-sites, Hugo, WordPress, and so on) will still be available, but it will become totally optional. Mastering the HTML and CSS principles here is what matters most.

I’ll post the Project Two material and the brief tutorial on some last-minute CSS stuff in a few hours. Meanwhile, do make sure that you understand how the box-model works (below).

Box model

Skilling-Up in CSS

To CSS, everything is a box. A rectangle.

CSS is appealing because we can use a few selectors to make a lot of HTML more legible – and more interesting to look at! – without having to place every line on the screen ourselves.

The CSS Box Model approximates the way newspaper editors, layout specialists, and typesetting professionals used to organize material to be printed to paper. It was time-consuming, laborious, and highly-specialized work.

Today, the rate at which we create new information on a daily basis far exceeds the rate at which human beings could be expected physically to lay things out on a page for print. CSS' box model approach helps automate this process. It isn’t perfect. (It is far from perfect). But – especially when you keep it simple – it can be surprisingly effective.

How-To

Again, CSS excels not at “laying out” a single page – although it can do that: Instead, it is best for laying-out hundreds, even thousands of pages automatically, customizing each for the particular needs of each reader: The size of the images, the color of the screen, the need for a table of contents, and so on.

Let’s look at this excerpt from Paine’s pamphlet, Common Sense. I’ve applied very basic HTML tags to it, creating a document that is fully marked-up: There is no longer any raw text, just HTML elements.

NB: In the CSS document, I’ve added some default CSS selectors. These attempt to make up for some of CSS' flaws. I’m going to skip any explanation for now, just know that they make our job much, much easier.

The Rules

I said CSS sees the world as rectangles – there are no arcs, waves, noodley-lines, scribbles, triangles, or circles. Just rectangles.

Those rectangles “flow” across the browser window, one after another. By default, every rectangle follows a couple of rules. Let me explain those, and show you a couple of examples.

  1. Rectangles are horizontally greedy. Unless instructed otherwise, they want to occupy as much space across the X-axis as they can. They want to stretch from the left-hand side of the browser to the right-hand side of the browser. It’s as though the sides of every rectangle were spring-loaded.

In other words, by default, the <p> in your default CSS is set to the following:

p {
	width: 100%;
}

We can see that in the codepen above. Let’s add our own declaration to the <p> selector to make this clearer.

Add this:

p {
	background: gainsboro;
}

See? Every paragraph rectangle now has a light grey background. You can see that each of those <p>...</p> elements stretches all the way across the screen – even if the text doesn’t require it! Shrink, enlarge the window: They still reach the edge. Horizontal greediness is the box-model default.

A few things more:

  1. We can see that when there is more text than fits on that horizontal line, then the rectangle expands downward, adding another line to its total height. The rectangle was greedy horizontally, taking up all possible space, but it is more practical vertically: It only absorbs the space it needs. It doesn’t automatically fill the space all the way to the bottom of the page! (That would make it very hard for any other paragraphs to find room, after all.)

  2. As the paragraphs “flow” down the page, they text inside them seems to end up aligning to the far left-hand side. That will be important in a moment.

  3. Those paragraphs don’t seem to want to touch one another. There is space between them – space we didn’t specify. Why is that?

  4. Similarly, lots of other details also seem to have been pre-set: The typeface, its size, its color, the line-height, the letter-spacing, and so on. Is that a good thing, or not?

So this is one of the tricky things about CSS: Often you’ll find that there are hidden pre-sets sneaking around in the background that seem to undermine all of your careful design! Designers use complex CSS sheets to “reset” or “normalize” their pages online. (Thankfully, codepen does some of that for us.)

But for the moment, let’s see if we can’t learn more about the rectangles that comprise each of these paragraphs. One way to do this is to add this one weird trick to our CSS:

Add:

* {
	border: 1px solid red;
}

Go ahead and add that to the top of the CSS. Excellent! It makes a lot of invisible data suddenly become visible. Rectangles, rectangles, everywhere.

With that in mind, a few points to observe:

  1. The <h1>...</h1> element is just as horizontally greedy and vertically practical as the <p>...</p> elements are.

  2. There are at least two boxes that we didn’t put there – boxes that seem to contain all of our stuff, from top to bottom.

  3. The phrase “Common Sense”, on the second line of text, also seems to be in its own rectangle! But this rectangle doesn’t appear to be horizontally greedy: Instead, that rectangle sits really tight against those two words.

  4. The <p>...</p> elements are now outlined by red borders. But that space between each paragraph still seems unaccounted for.

Let’s exaggerate things further in order to learn what is going on (this kind of playful experimentation with your CSS is a VITAL TECHNIQUE to understanding how things work – do it all the time).

So let’s replace our first border property declaration with this one:

* {
	border: 10px solid red;
}

See what happened? Two things:

  1. When the border got thicker, it did not overlap other borders, or the text itself – instead, it seems like those spring-loaded left- and right-sides, still squeezed up against our window’s edges, held tight. But because the border became thicker, there was less space for the contents: left border + right border = 20 pixels less space. Which means that, in order to fit everything in, each paragraph became a little bigger vertically. We can change it further to to see an even more exaggerated version:
* {
	border: 20px solid linen;
}

If you switch back and forth, adding and removing that selector, you’ll see that the new 20 pixel wide border never overlaps anything. That’s useful. Instead, each rectangle just needs more space (since there is now a 20-pixel-wide border on its top, bottom, left, and right). And things push downward. That even is true (again) with the phrase “Common Sense” on text line two: See how that <em>...</em> element got pushed to the right, away from the the author’s name? Remove that border declaration (as before), and it’ll go right back to where it was.

So let’s do that. Let’s eliminate the “all” selector (the asterisk, *), and instead change our paragraph selector a bit.

Try this:

p {
	background: gainsboro;
	border: 1px solid red;
}

Ah-ha! The external box borders have disappeared. So have the borders around the <h1> and the <em>. Notice that when we change width of window, the rectangles STILL have a red border on every side (they are changing width with us, not just running off the screen, which is really important). And notice that the white space beneath each paragraph remains… unchanged. Is it permanent? It doesn’t change, no matter how tall the paragraph is. That space remains uniform. And mysterious!

So let’s do this:

p {
	background: gainsboro;
	border: 1px solid red;
	width: 50%;
}

And let’s add two selectors, h1 and body.

body {
	background: skyblue;
}

h1 {
	background: linen;
}

More observations about what has just happened:

  1. <h1> is still 100% wide, even though we reduced the width of our <p> to 50%;
  2. Even though the <p> is now set to 50% width, it is still lined up against the left-hand side of the screen;
  3. That mysterious rectangle we saw in the background before – containing every <p>...</p> – must have been <body>! Codepen seems to render it even if we don’t include it in our HTML.
  4. All of these rectangles seem to preserve their own properties. When we changed the background of <h1>, it didn’t change the color of our <p>.
  5. But! Now the color of <body> is completely visible between those paragraphs! There are just blue spaces between all the grey ones now! And, come to think of it, there is a blue space between <h1>...</h1> and that first <p>...</p>, as well as to the top and bottom of that single <hr />. Hmmmm…

One more change to try before we sum up:

body {
	width: 50%;
	border: 1px solid red;
}

So, this is important.

  1. The <body> now extends only halfway across the screen (jammed up against the left side of the screen, still);
  2. The rectangles that sit inside <body>...</body> – that is, our <h1>...</h1> and <p>...</p> elements – are now half their former width, and flow commensurately further down the page!

So the children of a parent end up being sized relative to the parent!

The <body>...</body> element (which contained basically the whole page) was 100% by default, and when we set our <p>...</p> elements to be just 50% wide, they reached half-way across the screen. But when we set the <body>...</body> itself to 50% wide, then the <p>...</p> elements became even narrower. They became 25% of the total width of the screen, since 50% of 50% is… 25%. In the box-model, children are situated relative to the parent.

Cool, cool. All of that is starting to make sense. So let’s confuse things a bit.

I Heart CSS

So here is a peek at the part of CSS that makes less sense than what we’ve just seen. It’s vital to know about it, even though it is a bit confusing.

To see it, start by removing those mysterious selectors from the top of the CSS document: The html selector and the omni selector that begins *, *:before, *:after.

Now crank up the settings on your paragraph selector, thus:

p {
	background: gainsboro;
	border: 45px solid red;
	width: 50%;
}

See that? By removing those selectors, 50% width is no longer the same 50% width we saw before. Ugh. This box-model thing is a great way to put stuff on the screen, but it turns out they’ve changed the way it works over time. It used to be that the border width (the red line around our paragraphs) wasn’t factored in to the total width or total height of a rectangle. You can see that in the above example. In that example, the grey part of the paragraph itself is probably 50% of the width, but when you factor in the width of that red outline, which we have been doing in the past, the total is now maybe, what, 75%? How can I even calculate that, since one value is relative (50% width) while the other is absolute (45px border width). What a headache.

It can get much worse… but let’s leave it there for now. The lesson: Always (for now at least) include the code for those two selectors (<html>, and *, *:before, *:after) at the top of every CSS document you build. They make life easier. (We’ll eventually come to a few others, too).

Mysterious margins

We still have at least one unresolved question: What’s the deal with the spaces between our <p>...</p>?

So open up this new codepen page and let’s have an even more detailed look at the box-model. (The pen is different from our earlier one just to make things a tiny bit more interesting. The principles, however, are all the same.)

Take a look at the paragraph selector in particular. I’ve added some of the most common properties associated with the box-model that we’ve not yet discussed at length: margin and padding.

Take a look:

p {
	background: lightblue;
	color: black;
	font-family: Helvetica;
	padding: 2px;
	margin: 5px;
}

As we’d seen before, our rectangles aren’t just rectangles: They are rectangles that contain rectangles! This is the box-model, then.

Box model

Content

The stuff inside this part of the box is what sets the dimensions of the “content” rectangle. In other words, unlike all the other parts, you don’t really have much direct control over the part in the very center. If I make my font really huge, then the content part of my box – the very center of it, the part that is lightblue in our current demo – the content part of the box will also be very big: As big as it needs to be in order to fulfill those rules we discussed:

  1. Be as wide as you possibly can (horizontally greedy)!
  2. Only be as high as is necessary (vertically practical)!

(Again, it is important to point out that by default, the margin and the padding are NOT zero – you have to force them to zero if that is what your layout requires. That is sometimes easy to forget, and messes up beginners all the time.)

Padding

Moving outside of the content area, and heading away from it, we come to the padding. The padding is the soft gooey space that sits between the content area and the crunchy border (all those red lines we’ve drawn). You can’t put any content into the space reserved for the padding, but the padding does absorb the color of the content’s background. So if I set my p selector to background: firebrick;, any padding that is larger than 0 will also be colored firebrick. If the box is set to background: none, then both the content area and the padding area will become transparent, letting the background of the body or some other parent element shine through.

Border

After we’re through the padding, we come to the border. It doesn’t have a background property. Instead, we can set its thickness, its line type, and its foreground color: Its just an outline, in effect. But this is a good place to talk more about how these properties can get set – and how complex they can be. Here’s one way to set the border for a paragraph selector:

p {
	border-color: blue;
	border-style: solid;
	border-width: 1em;
}

Three lines may seem like a good bit for one feature, but that’s actually a shortened version! If we want, we can specify the properties of each side of the box individually. (Design hint: You will never, ever want to set each of these properties to different colors, thicknesses, and line-types. This is just an example).

(Feel free to add this to a codepen and see what happens).

p {
	border-color: blue;
	border-style: solid;
	border-width: 1em;
	border-left-width: 5px;
	border-left-color: red;
	border-left-style: dotted;
	border-right-width: 3px;
	border-right-color: orange;
	border-right-style: dashed;
	border-top-width: 10px;
	border-top-style: double;
	border-top-color: yellow;
	border-bottom-width: 20px;
	border-bottom-style: solid;
	border-bottom-color: green;
}

Now all of those declarations are necessary because we’ve got so many different things happening. If we’re willing to keep everything uniform, then we can radically shorten everything to just one line:

p {
	border: 1px solid black;
}

It’s worth saying: There are lots of combinations you can explore here, and CSS is full of short-hand versions. For more information, consider, for example this site’s overview.

Margin

We’re about to escape the box altogether, but we’ve one last area of influence: The margin. The margin is the soft outermost layer that sits outside the border. It is a kind of dead zone: You cannot color it; you cannot put content into it; it is always transparent.

So why does it exist, and how can we use it? It is actually really useful, as it works like a force-field, pushing the box itself away from the edges of all the other boxes and boundaries it touches.

Indeed, the margin is what has been creating the mysterious distance between our <p>...</p> elements all this time. Try this, for example, in one of the pens we’ve been experimenting upon:

p {
	margin-bottom: 0px;
	margin-top: 0px;
}

The paragraphs should all have collapsed so that they are sitting directly on top of one another. They’re all still stretched all the way across the page, but they touch one another from the topmost to the bottommost <p>...</p>.

But wait! There’s more to see here! Try by setting your paragraphs like this:

p {
	margin-bottom: 10px;
	margin-top: 10px;
}

Now… switch it up. Set them like this:

p {
	margin-bottom: 0px;
	margin-top: 10px;
}

Wait what? Those are very different settings, and yet the result is almost exactly the same! How is this possible? (Answer: Because CSS.) Aaargh.

Margins, it turns out, conspire together in the background, outside of your influence. When my box bumps up against your box, you might expect that the distance between our borders would be calculated thus: my margin PLUS your margin. But you’d be a fool for thinking thus, and CSS wins again. Why? Because someone decided that all of that margin space was Too Much Margin. So when it is being rendered to my browser, CSS looks at my margin, and then it looks at your margin, and then… it deletes the smaller of the two.

So if my margin-bottom is set to 20px, and your margin-top is set to 21px, and my box comes to rest on top of yours, then the borders of our boxes will only be 21px apart – not 41px!

Sigh. That’s one of the things that makes CSS something of a challenge. There are a lot of weird little exceptions like that.

Exercise

OK. Wow. Before all of that learning evaporates, let’s take a few minutes and play around with some of those ideas. None of this is for publication, obviously: The outcomes can be ugly. The point is to see how things work.

Load up this codepen, which has been HTML-itified for you.

I’ve also included a bit of default CSS.

Now use CSS to create a few different outcomes. Try these, for example:

  • Make the whole page white. There should be a large margin of empty space on the left and right of our paragraphs. The text should be black, but the space behind the text should be bright yellow, as though you’ve drawn over the text with a highlighter.
  • Change the width of your <p>...</p> to 50%. Can you make it appear as though the highlighter extends from the left-most edge of the page, but ends at the 50% point exactly? That is, the highlighting will extend beyond the text on the left-hand side, but will end (roughly) at the same place the text ends on the right-hand side.
  • Using only the body selector, imagine page that has three columns of equal width. Put your paragraphs into the center column.
  • Eliminate your body selector, and add a p selector. Using only that selector, and imagining the same layout, put your single column of paragraphs in the rightmost of those three imaginary columns.
  • Now push the <h1>...</h1> and the <h2>...</h2> over to the right-hand edge, but give it a background color of firebrick and ensure that the background color extends from the far left to the far right window edges. The color should not be visible once you move past the <h1>...</h1> and <h2>...</h2>.

Don’t hesitate to look above for hints, or ask online. Or text me. Or if you’d like to look at more comprehensive information about how things work in the box model, take a look at some of the resources below.

Resources

An insightful (if ambivalent) box-sizing article

The margin property of CSS

A reasonably good little video tutorial on the box-margin