Core 1 Interaction

Boxes!

The Box model

The first thing we need to understand is how CSS sizes elements. This is called the the box model, as everything on the web begins as a rectangle:

With box-sizing: content-box; per the spec.

By default, browsers are set to box-sizing: content-box; which means that the padding (and border) exists outside the content width or height—so padding is then an outset.

But this is often unintuitive and doesn’t fit with most web design patterns, so it is very common (nearly universal) to instead set this to box-sizing: border-box; which makes padding and border exist inside the content dimensions. Then padding is easier to think of as an inset. (W3C probably got this default wrong. Good ol’ CSS!)

With box-sizing: border-box; the defacto standard. Most CSS resets will do this for you.

Let’s take a look at this box, going inside-to-outside.

Content

The content area is the guts of the element, usually text or an image. Its dimensions are defined by that content, but also can be specified directly via width or height. (More on those soon.)

body {
	font-family: cursive;
	padding: 20px;
}

div { background-color: lightgrey; }
<!DOCTYPE html>
<html>
	<head>
		<title>Content</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
		</section>
	</body>
</html>

I’ve pulled our CSS reset into the <head> all of these examples, so we are only seeing the styles that are expressly written out here.

Padding

Next comes padding, which extends the element’s area around the content. It’s easiest to think of this as an inset (if we’ve made our box-sizing the logical border-box, above).


body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	padding: 10px;
}
<!DOCTYPE html>
<html>
	<head>
		<title>Padding</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
		</section>
	</body>
</html>

Shorthand

Padding—and many other properties, like border and margin—can be specified with a shorthand property to make it easier to use the same spacing all around, or shared top/bottom and left/right. (We’ll talk about units below, promise.)

p { padding: 20px; }
p { padding: 20px 40px; }
p { padding: 20px 40px 80px; }
		      /* T    R    B    L */
p { padding: 20px 20px 40px 80px; }

You can always write the individual directions out, though (like padding-top). Three- and four-value rules are harder to read, so I tend to avoid them. My way of remembering the 4 values: They spell terrible abbreviated.

Border

Then we have border. Border is… the border around an element. It has its own border-width, border-color, and also border-style:

body {
	font-family: cursive;
	padding: 20px;
}


div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div {
	border-color: black; /* Non-shorthand. */
	border-style: solid;
	border-width: 1px;
}
<!DOCTYPE html>
<html>
	<head>
		<title>Border</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">

	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
		</section>
	</body>
</html>

The shorthand border-top property value order here doesn’t matter! Isn’t CSS logical.

div:nth-child(1) { border-style: none; }
div:nth-child(2) { border-style: hidden; }
div:nth-child(3) { border-style: dotted; }
div:nth-child(4) { border-style: dashed; }
div:nth-child(5) { border-style: solid; }
div:nth-child(6) { border-style: double; }
div:nth-child(7) { border-style: groove; }
div:nth-child(8) { border-style: ridge; }
div:nth-child(9) { border-style: inset; }
div:nth-child(10) { border-style: outset; }

/* Same as before. */
body {
	font-family: cursive;
	padding: 20px;
}

div { padding: 10px; }

/* Every one but the first one. */
div:not(:first-child) { margin-top: 10px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Border-style</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">

	</head>
	<body>
		<section>
			<div>
				<p>none</p>
			</div>
			<div>
				<p>hidden</p>
			</div>
			<div>
				<p>dotted</p>
			</div>
			<div>
				<p>dashed</p>
			</div>
			<div>
				<p>solid</p>
			</div>
			<div>
				<p>double</p>
			</div>
			<div>
				<p>groove</p>
			</div>
			<div>
				<p>ridge</p>
			</div>
			<div>
				<p>inset</p>
			</div>
			<div>
				<p>outset</p>
			</div>
		</section>
	</body>
</html>

Look at all those borders.

.one {
	border-radius: 50%; /* Relative to size. */
	border-style: solid;
}

.two {
	background-color: lightgrey;
	border-radius: 10px; /* Absolute amount. */
}

.three {
	background-color: palegoldenrod;
	border-bottom-right-radius: 25px;
	border-top-left-radius: 25px;
}

/* Same as before. */
body {
	font-family: cursive;
	padding: 20px;
}

div { padding: 20px; }

/* Every one but the first one. */
div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Border radius</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
		<link href="style.css" rel="stylesheet" type="text/css">
	</head>
	<body>
		<div class="one">
			<p>Unlike margin and padding, borders can be rounded.</p>
		</div>
		<div class="two">
			<p>This is often used in combination with a background.</p>
		</div>
		<div class="three">
			<p>It can also only adjust specific corners!</p>
		</div>
	</body>
</html>

Margin

The last part of our box is margin—the space around an element, empty/whitespace area that is used to separate an element from its siblings. Like padding and border, you can specify it all around or on individual sides.

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

/* Every one but the first one. */
div:not(:first-child) { margin-top: 40px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Margin</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">

	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
		</section>
	</body>
</html>

Margin has a couple tricks up its sleeve. First, it can have negative values—which will eat up/remove space between elements. (Padding and border only take up space.) Just add a minus before the value and watch it bring things together.

/* This applies to both. */
div:not(:first-child) { margin-top: 40px; }

/* But this negates some of it. */
div:first-child { margin-bottom: -30px; }

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}
<!DOCTYPE html>
<html>
	<head>
		<title>Margin negative</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">

	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
		</section>
	</body>
</html>

The first element pulls the second element closer with a negative margin.

Also margins collapse, meaning that they are sometimes combined into a single value (the largest) between two elements. This happens most often on adjacent siblings, and is both useful and an absolute pain.

div:not(:first-child) { margin-top: 40px; }

div:first-child { margin-bottom: 40px; }

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}
<!DOCTYPE html>
<html>
	<head>
		<title>Margin collapse</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
		

	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
		</section>
	</body>
</html>

You might expect the margin between the first two div to be 80px, but it is only 40px. They have collapsed.

Units

Okay, so we have all these box properties—but how do we specify the dimensions? CSS has many length units, used for width, height, and also padding, border, margin, and even font-size. We’ll look at some common ones.

Absolute

Maybe the easiest ones to understand, fixed to physical (well, sort of) sizes.

With the many vagaries of screen size and density, the physical/ruler lengths will only be correct when you print. And maybe not even then.

.pixels {
	height: 360px;
	width: 720px;
}

.inches {
	height: 5in;
	width: 10in;
}

.mm {
	height: 84mm;
	width: 400mm;
}

Relative

Otherwise you can use relative units, which depend on and respond to their context.

These are distinctly and intrinsically web measurements.

/* Relative to nearest sized ancestor. */
.percentage {
	height: 90%;
	width: 85%;
}

/* Relative to viewport height/width. */
.viewport {
	height: 75vh;
	width: 80vw;
}

/* Relative to element font-size. */
.em {
	height: 14em; /* 1em is one line. */
	width: 4.8em;
}

/* Also relative to font size */
.ch {
	width: 1ch; /* 1ch is one letter. */
}

/* Relative to :root font-size. */
.rem {
	height: 12rem;
	width: 2.4rem;
}

Calc Combos

Sometimes you might want to use these together! Or otherwise do some math. For this we have the calc function.

.absolute-and-relative {
	width: calc(50% - 20px);
}

.computer-do-the-math {
	width: calc(100% / 12);
}

Min-/Max-

You’ll often want to set limits/constraints on these values—particularly with flexible, relative units (and responsive design, which we’ll talk about soon.) You can set minimums and maximums using the prefix min- and max-.

.constrained-width {
	min-width: 200px;
	width: 50%;
	max-width: 400px;
}

.constrained-height {
	min-height: 100px;
	height: 100%;
	max-height: 200px;
}

/* Handy to watch your line lengths! */
p {
	max-width: 65ch; /* 65ish letters. */
}

CSS is big and massive and overwhelming and sometimes indefensibly nonsensical—but remember that you can do a surprising amount with just these basic properties! And no matter how complex it gets, it always comes back to these basics.

Position

With an idea of how elements take up space, now we’ll look at how they exist and move together in the document flow. The CSS property position sets this relationship.

Static

By default, every element is static—just meaning its normal, stacked position in the document.

You’ll rarely, if ever, actually set this yourself. It’s the default you change.

div:nth-child(3) {
	background-color: palegoldenrod;
	position: static;
	width: 66%;
}

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Position static</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
			<div>
				<p>Let’s add a fourth.</p>
			</div>
			<div>
				<p>Even a fifth.</p>
			</div>
			<div>
				<p>This should let it scroll.</p>
			</div>
			<div>
				<p>It was the best of times; it was the worst of times.</p>
			</div>
			<div>
				<p>Scrolling is always fun.</p>
			</div>
			<div>
				<p>I guess that isn’t true.</p>
			</div>
			<div>
				<p>Sometimes it goes on and on, you know.</p>
			</div>
			<div>
				<p>Okay, this is enough.</p>
			</div>
			<div>
				<p>One more, for good measure.</p>
			</div>
		</section>
	</body>
</html>

Nothing changes here—static is the default.

Relative

The first thing we might want to do is adjust an element from that normal static position, which we can do with relative positioning.

Once you have set position: relative; you can use the top, right, bottom, and left values (with any of the units, above) to move the element away from its default, normal position in the flow.

div:nth-child(3) {
	background-color: palegoldenrod;
	left: 30px;
	position: relative;
	top: 30px;
	width: 66%;
}


body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Position relative</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
		

	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
			<div>
				<p>Let’s add a fourth.</p>
			</div>
			<div>
				<p>Even a fifth.</p>
			</div>
			<div>
				<p>This should let it scroll.</p>
			</div>
			<div>
				<p>It was the best of times; it was the worst of times.</p>
			</div>
			<div>
				<p>Scrolling is always fun.</p>
			</div>
			<div>
				<p>I guess that isn’t true.</p>
			</div>
			<div>
				<p>Sometimes it goes on and on, you know.</p>
			</div>
			<div>
				<p>Okay, this is enough.</p>
			</div>
			<div>
				<p>One more, for good measure.</p>
			</div>
		</section>
	</body>
</html>

The element still exists/takes up space in the flow.

Absolute

Absolute positioning is somewhat similar to relative—but instead of placing an element in relation to its own default position, it uses the position of its nearest relatively-positioned ancestor. So it will “go up the chain” of parents and wrapper elements until it finds one set to position: relative;, then uses the same offset properties to move the element around.

Importantly, position: absolute; also removes the element from the normal document flow—meaning it takes up no space in the page layout.

This is often used for exacting, specific design elements.

/* The closest relative ancestor. */
section { position: relative; }

div:nth-child(3) {
	background-color: palegoldenrod;
	left: 30px;
	position: absolute;
	top: 30px;
	width: 66%;
}

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Position absolute</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
		

	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
			<div>
				<p>Let’s add a fourth.</p>
			</div>
			<div>
				<p>Even a fifth.</p>
			</div>
			<div>
				<p>This should let it scroll.</p>
			</div>
			<div>
				<p>It was the best of times; it was the worst of times.</p>
			</div>
			<div>
				<p>Scrolling is always fun.</p>
			</div>
			<div>
				<p>I guess that isn’t true.</p>
			</div>
			<div>
				<p>Sometimes it goes on and on, you know.</p>
			</div>
			<div>
				<p>Okay, this is enough.</p>
			</div>
			<div>
				<p>One more, for good measure.</p>
			</div>
		</section>
	</body>
</html>

The element is out of the flow, and placed according to the relative parent.

Fixed

Fixed positioning also removes the element from the document flow, but it places elements with relation to the browser viewport—the boundaries of the window or device.

So position: fixed; brings the element completely out of the page’s normal flow, like it is sitting on its own separate layer.

This is often used for things like navigation elements.

div:nth-child(3) {
	background-color: palegoldenrod;
	left: 30px;
	position: fixed;
	top: 30px;
	width: 66%;
}

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Position fixed</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
			<div>
				<p>Let’s add a fourth.</p>
			</div>
			<div>
				<p>Even a fifth.</p>
			</div>
			<div>
				<p>This should let it scroll.</p>
			</div>
			<div>
				<p>It was the best of times; it was the worst of times.</p>
			</div>
			<div>
				<p>Scrolling is always fun.</p>
			</div>
			<div>
				<p>I guess that isn’t true.</p>
			</div>
			<div>
				<p>Sometimes it goes on and on, you know.</p>
			</div>
			<div>
				<p>Okay, this is enough.</p>
			</div>
			<div>
				<p>One more, for good measure.</p>
			</div>
		</section>
	</body>
</html>

Sticky

The most recent addition to the position party, position: sticky; elements are placed according to the normal flow of the document, like static, until their nearest scrolling ancestor (usually the viewport) moves past them. The element is then stuck in relation to this element.

This is often used for headers on tables and lists.

div:nth-child(3) {
	background-color: palegoldenrod;
	left: 30px;
	position: sticky;
	top: 30px;
	width: 66%;
}

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Position sticky</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
			<div>
				<p>Let’s add a fourth.</p>
			</div>
			<div>
				<p>Even a fifth.</p>
			</div>
			<div>
				<p>This should let it scroll.</p>
			</div>
			<div>
				<p>It was the best of times; it was the worst of times.</p>
			</div>
			<div>
				<p>Scrolling is always fun.</p>
			</div>
			<div>
				<p>I guess that isn’t true.</p>
			</div>
			<div>
				<p>Sometimes it goes on and on, you know.</p>
			</div>
			<div>
				<p>Okay, this is enough.</p>
			</div>
			<div>
				<p>One more, for good measure.</p>
			</div>
		</section>
	</body>
</html>

This always feels very web-y.

Z-Index

Okay, z-index is not strictly positioning—it is a separate property. You can see that all these position properties have given us ways to make things overlap. z-index is how we can decide the front-to-back ordering (think z-axis).

By default, items that are lower in the DOM (coming after each other) are in front of higher, earlier elements.

div:nth-child(3) {
	background-color: palegoldenrod;
	left: 30px;
	position: sticky;
	top: 30px;
	width: 66%;
}

div:nth-child(even) {
	position: relative;
	z-index: 1;
}

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Z-index</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
			<div>
				<p>Let’s add a fourth.</p>
			</div>
			<div>
				<p>Even a fifth.</p>
			</div>
			<div>
				<p>This should let it scroll.</p>
			</div>
			<div>
				<p>It was the best of times; it was the worst of times.</p>
			</div>
			<div>
				<p>Scrolling is always fun.</p>
			</div>
			<div>
				<p>I guess that isn’t true.</p>
			</div>
			<div>
				<p>Sometimes it goes on and on, you know.</p>
			</div>
			<div>
				<p>Okay, this is enough.</p>
			</div>
			<div>
				<p>Let’s make a longer scroll on this one.</p>
			</div>
			<div>
				<p>To really show off the stacking.</p>
			</div>
			<div>
				<p>One more, for good measure.</p>
			</div>
		</section>
	</body>
</html>

The two position properties both create new stacking contexts, z-index: 1; moves even elements in front.

A whole lot of things make a new stacking context (including most position changes) which is kind of like a group that has its own internal depth/overlap order. No amount of internal z-index adjustments can break something out of that group—which is one of the reasons why z can be really difficult to understand and tricky to use. But you can adjust the z-index of the group, as we do here.

Floats

Sometimes you’ll want to have an image or block flow within a block of text. There are a lot of ways to do this now, but the oldest (yet sometimes still trickiest) is a float.

Left and right

The declarations float: left; and float: right; take an element out of the normal flow and place it on the left or right side of its parent container. Any text siblings will then flow around the element—like a text wrap—filling up any available space to its side. They will go as far up as the top of the floated element.

aside {
	background-color: palegoldenrod;
	float: left;
	margin-right: 10px;
	padding: 10px;
	width: 100px;
}

div:nth-child(2) aside {
	float: right;
	margin-left: 10px;
	margin-right: initial;
}

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Float</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
	</head>
	<body>
		<section>
			<div>
				<aside>
					<p>This is an aside element.</p>
				</aside>
				<p>This is some text in the first element. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Arcu risus quis varius quam. Egestas fringilla phasellus faucibus scelerisque eleifend donec. </p>
			</div>
			<div>
				<aside>
						<p>And another aside here too, with a lot more text in it.</p>
				</aside>
				<p>And some more in the second element. Ut etiam sit amet nisl. Sed libero enim sed faucibus turpis in eu. Congue nisi vitae suscipit tellus mauris. Nisi est sit amet facilisis magna etiam tempor orci. Leo urna molestie at elementum. Morbi tristique senectus et netus et malesuada.</p>
			</div>
			<div>
				<p>And a third one, too.</p>
			</div>
		</section>
	</body>
</html>

Clear

Since this takes the floated element out of the flow, if we want the following element (often another text block, like a <p>) to not move up it needs to be cleared with clear: left; , clear: right;, or clear: both;. Applied on the following element, it will make it stay entirely below (clear of) the floated element.

aside {
	background-color: palegoldenrod;
	float: left;
	margin-right: 10px;
	padding: 10px;
	width: 100px;
}

div:nth-child(2) aside {
	float: right;
	margin-left: 10px;
	margin-right: initial;
}

p:last-child {
	clear: left;
}

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Float clear</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
	</head>
	<body>
		<section>
			<div>
				<aside>
					<p>This is an aside element.</p>
				</aside>
				<p>This is some text.</p>
				<p>And a second pargraph set to clear left, so it goes across the float.</p>
			</div>
			<div>
				<aside>
					<p>And another aside here too, with a lot more text in it.</p>
				</aside>
				<p>And some more.</p>
				<p>This one clears left, but the aside is to the right.</p>
			</div>
			<div>
				<p>And a third one, too.</p>
			</div>
		</section>
	</body>
</html>

Uh oh, classic float problem on the second one.

If you have a parent wrapper and no following element, there won’t be anything there to clear the float—meaning the parent will collapse down to the size of the text content. You can solve this broken look with a clearfix hack, which uses a pseudo-element as an ersatz last-child to clear the container.

aside {
	background-color: palegoldenrod;
	float: left;
	margin-right: 10px;
	padding: 10px;
	width: 100px;
}

div:nth-child(2) aside {
	float: right;
	margin-left: 10px;
	margin-right: initial;
}

div:after { /* This is the “clearfix”. */
	clear: both;
	content: '';
	display: block;
}

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Float clearfix</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
	</head>
	<body>
		<section>
			<div>
				<aside>
					<p>This is an aside element.</p>
				</aside>
				<p>This is some text.</p>
			</div>
			<div>
				<aside>
					<p>And another aside here too, with a lot more text in it.</p>
				</aside>
				<p>And some more.</p>
			</div>
			<div>
				<p>And a third one, too.</p>
			</div>
		</section>
	</body>
</html>

Much better. :after is a pseudo-element—which acts here as a last child that clears the div.

Generally, I try and avoid floats—they aren’t common in modern design patterns and have been giving people headaches for… decades now. They require you to know how long your content is and also how big your viewport/page will be—both things that you don’t always have control over in responsive/mobile 2022.

Sometimes they are still the only thing that can do what you need!

Display

In our HTML introduction we briefly talked about block and inline elements, as set by the user-agent styles. These are the first two examples of the display property.

Block

So as we discussed, most HTML elements are block-level by default. But you can also set display: block; manually on an inline element, too. This would mean that it starts on a new line, takes up the full width available, and you can specify a height, width, and use margin above and below.

a {
	background-color: palegoldenrod;
	text-decoration: underline;
}

div:nth-child(2) a {
	display: block;
	margin-bottom: 10px;
	padding: 10px;
	text-decoration: none;
}

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Display block</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
	</head>
	<body>
		<section>
			<div>
				<p><a href="#">Links are usually inline.</a> This is some text in the first element.</p>
			</div>
			<div>
				<p><a href="#">But you’ll often want them block →</a> And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
		</section>
	</body>
</html>

Whenever you are linking a whole area (like an image and text together), safe bet that you want block.

Inline

And going the other way, you can make block elements switch to inline with display: inline;. They will no longer start on their own lines, will only take up as much space as their content/children, and don’t accept height and width properties.

p:not(:first-child) {
	background-color: palegoldenrod;
	margin-top: 10px;
}

div:nth-child(2) p:not(:first-child) {
	display: inline;
	white-space: pre;
}

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Display inline</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
				<p>Paragraphs are normally block-level.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
				<p> But you </p>
				<p> might want </p>
				<p> inline </p>
				<p> for tags </p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
		</section>
	</body>
</html>

The white-space property pre-vents the spaces in the paragraphs from collapsing.

Inline-block

You can also combine the qualities of block and inline with display: inline-block;. These elements take height and width (and vertical margin) like block-level elements, but do not start on their own line.

p:not(:first-child) {
	background-color: palegoldenrod;
	margin-top: 10px;
}

div:nth-child(2) p:not(:first-child) {
	display: inline-block;
	margin-top: 10px;
	padding: 5px;
	text-align: center;
	white-space: pre;
	width: 100px;
}

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Display inline-block</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
		

	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
				<p>Paragraphs are normally block-level.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
				<p> Inline-block </p>
				<p> will give </p>
				<p> you more </p>
				<p> control </p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
		</section>
	</body>
</html>

None

Setting display: none; hides an element visually from the document—as well as taking it out of the flow. (Keep in mind the HTML is still there, if someone opens up the source code.)

This is a common way to hide/show (by setting another display property) elements on the page, but it will reflow the document when applied—as if the element is actually added/removed from the DOM.

div:nth-child(2) { display: none; }

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Display none</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
		</section>
	</body>
</html>

Poof. Like it wasn’t even there.

Visibility

You can also hide something visually without taking it out of the document flow, which is useful when you don’t want the page to jump/reflow when something appears/disappears. Setting visibility: hidden; keeps the space an element had before, but makes it invisible and unable to be interacted with. The value visible is the default.

div:nth-child(2) { visibility: hidden; }

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Visibility</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
		</section>
	</body>
</html>

Opacity

Another way to hide an element visually is to adjust its opacity, which uses values on a scale from 0–1. This differs from visibility because elements with no (or partial) opacity can still be interacted with.

div:nth-child(2) { opacity: 0; }

div:nth-child(3) { opacity: 0.5; }

body {
	font-family: cursive;
	padding: 20px;
}

div {
	background-color: lightgrey;
	border: solid black 1px;
	padding: 10px;
}

div:not(:first-child) { margin-top: 20px; }
<!DOCTYPE html>
<html>
	<head>
		<title>Opacity</title>
		<link href="../reset.css" rel="stylesheet" type="text/css">
	</head>
	<body>
		<section>
			<div>
				<p>This is some text in the first element.</p>
			</div>
			<div>
				<p>And some more in the second element.</p>
			</div>
			<div>
				<p>Then a third one, too.</p>
			</div>
		</section>
	</body>
</html>

You can still select the text (or click links) of not-fully-opaque elements.

Keep in mind that display: none;, visibility: hidden;, and opacity: 0; only hide things in the rendered browser view. The HTML is still visible in the source code!

Flex and Grid

We’ll cover these separately! But they’ll make your (layout) life easier.


This page was adapted (ever so slightly) from Michael Fehrenbach's page on The Box Model.