Boxes Within Boxes #
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.
-
Introduction to CSS Layout – MDN
As usual. -
Layout – web.dev
This gets intogrid
andflex
; we’ll talk about those next unit. -
Learn CSS Layout
An old-but-still-good run-through.
By default, all browsers’ user-agent styles have an unfortunate box-sizing: content-box;
—which means that the padding (and border) exists outside the content width or height—so padding (and border) is then an outset.
But this is often unintuitive for designers and doesn’t fit with most web design patterns—so it is very, very common (nearly universal) to instead override this to box-sizing: border-box;
—which makes padding and border exist inside the content dimensions. Then padding (and border) is easier to think of as an inset. W3C probably got this default wrong. Good ol’ CSS!
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.)
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):
Padding – MDN
There is no P
Train.
A Sidebar About Shorthand #
Padding—and many other properties, like border and
Shorthand Properties – MDN
There are some S
shuttles though.
1 value | All Directions / Sides |
2 values | top/bottom left/right |
3 values | top left/right bottom |
4 values | top right bottom left |
section { padding: 20px; }
section { padding: 20px 40px; }
section { padding: 20px 40px 80px; }
section { padding: 20px 40px 80px 40px; }
These three- and four-value rules are often harder to read and quickly understand though, so we tend to avoid them. You can always write the individual directions out, for clarity!
section {
padding-top: 20px;
padding-bottom: 80px;
padding-right: 40px;
padding-left: 40px;
}
Border #
Then we have border. Border is… the border around an element. It has its own border-width
, border-color
, and also border-style
:
Border – MDN
Our first non-text design element! You are allowed.
Margin #
The last part of our box is margin—the space around an element, empty/white-space 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:
Margin – MDN
The space between things.
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 closer together:
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:
Logical Properties #
You can also now define all your box model properties using logical directions—meaning instead of physical (top
/bottom
, left
/right
) orientations, you can map your rules to the flow of the text (block-start
/block-end
, inline-start
/inline-end
).
CSS Logical Properties
Adrian Roselli has a very thorough explanation.
In left-to-right, horizontal writing modes (as in English):
/* These horizontal physical directions: */
padding-left: 10px;
padding-right: 10px;
/* Map to these logical directions: */
padding-inline-start: 10px;
padding-inline-end: 10px;
/* And this combined property: */
padding-inline: 10px;
/* Same for the vertical directions: */
margin-top: 20px;
margin-bottom: 20px;
/* Mapping to these: */
margin-block-start: 20px;
margin-block-end: 20px;
/* And this shorthand for both: */
margin-block: 20px;
This start
/ end
terminology will come up later with flexbox
and grid
, so it isn’t a bad habit / mindset to get into!
This allows your design/styles to behave in a logically (if not physically) consistent way across languages with varied writing modes and different text directions. You can write styles that work even when your site is translated! (And the shorthand is nice, here.)
And Their 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
. (Picas, anyone?) We’ll look at some common ones.
<length>
– MDN
Length is used by many properties!
Absolute Units #
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 Units #
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;
}
Combine Them With a calc
#
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);
}
Limit/Constrain Them #
You’ll often want to set limits/constraints on values—particularly with flexible, relative units (and responsive design, which we’ll talk about soon.) You can usually set minimums and maximums by using the prefixes 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! 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.
Position – MDN
Interesting web work often uses position
.
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!
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:
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 positioned ancestor as the origin.
So absolute elements will go “up the tree” of parents and wrapper elements until they find one set to anything other than default/static
—
Importantly, position: absolute;
also removes the element from the normal document
This is often used for exacting, specific design elements.
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.
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.
“Depth” #
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, and z-index
is how we can decide the front-to-back ordering (think
By default, items that are lower in the HTML (coming after each other) are in front of higher, earlier elements:
A whole lot of things make a new stacking context (including most position
changes) which is kind of like a group (or a Figma frame) 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 always adjust the z-index of the group, as we do here!
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.
Display – MDN
Our block
and inline
elements (and later, grid
and flex
).
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:
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
(or any -top
/-bottom
) properties:
But Also 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:
And Sometimes 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 HTML:
…vs. 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:
…vs. 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:
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!
What About Floats? #
Oh right, 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 (and sometimes still the trickiest) is a float.
Floats – MDN
You don’t see these used as much, anymore!
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:
Don’t Forget to 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:
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. Almost never what you want.
You can solve this broken look with a clearfix hack, which uses a pseudo-element as an ersatz last-child
to clear the container.
Generally, folks 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/
… flex
and grid
? #
We’ll cover these next unit! They’ll make your (layout) life easier.
E.g.: ____________ H1 has a 1 character margin So does H2 P starts here and could go on forever. Wow, a 5 character left margin sure looks great! _____ | + + | Wow, you can do | @ | images as well? | --- | Then you'll |_____| want a 1 character margin on the left side. Until, you're below the image that is. This is where we [find] the simple stacked box model is a bit too simple.