Mind Diary

CSS Box Model

The "CSS box model" is a set of rules that define how every web page on the Internet is rendered. CSS treats each element in our HTML document as a box with a bunch of different properties that determine where it appears on the page.

The "default" layout scheme of web pages is a bunch of elements rendered one after another. The box model is our toolkit for customizing this.

Using the CSS box model to make the layout of web pages

A big part of your job as a web developer will be to apply rules from the CSS box model to turn a design mockup into a web page.

Block Elements and Inline Elements:

Each HTML element rendered on the screen is a box, and they come in two flavors: block boxes and inline boxes.

Block boxes versus inline boxes

Important behaviours associated with block and inline boxes:

  • A block box always appear below the previous block element. This is the "natural" or "static" flow of an HTML document when it gets rendered by a web browser.
  • The "width" of block boxes is set automatically based on the width of their parent container. In this case, our block boxes always have the same width of the browser window.
  • The default height of block boxes is based on their content. When you narrow the browser window, a long <h1> element, for example, gets split over two lines, and its height adjusts accordingly.
  • Inline boxes do not affect vertical spacing. They are not meant for determining layout — they are for styling stuff inside of a block.
  • The "width" of inline boxes is based on their content, not on the width of their parent element.

Changing Box Behaviour:

We can override the "default" box type of HTML elements with the CSS display property.

Thus, for example, if we want to make an <em> or a <strong> element as "blocks" instead of "inline" elements, we could do it like this:

em {
   display: block;
}

Turning "inline" elements into "block" elements will make them act like headings and paragraphs: they start on their own line, and they fill the entire width of the browser.

This comes in handy when we are trying to turn <a> elements into buttons or when formatting <img> elements (both of them are inline boxes by default).

Content, Padding, Border, and Margin:

The "CSS box model" is a set of rules that determine the dimensions of every element in a web page. It gives each box (both inline and block) four properties:

  • Content – The text, image, or other media content in the element.
  • Padding – The space between the box's content and its border.
  • Border – The line between the box's padding and margin.
  • Margin – The space between the box and surrounding boxes.
CSS box model

Together, this is everything a browser needs to render an element's box.

The content is what you author in an HTML document, and it is the only one that has any semantic value (which is why it is in the HTML). The rest of them are purely presentational, so they are defined by CSS rules.

Padding:

The padding is inside the border. Everything inside the border gets a background.

We can also style one side of an element, like this:

p {
   padding–top: 20px;
   padding–bottom: 20px;
   padding–left: 10px;
   padding–right: 10px;
}

We can use any unit for the padding of an element, not just pixels. Again, em units are particularly useful for making your paddings "scale" with the base font size.

Shorthand Formats:

CSS provides a "shorthand" form of the padding property so that we set the padding with only "one line".

Two values for the padding shortform

When we provide two values for the padding property, the web browser interprets them as the vertical and horizontal padding values, respectively.
This means that our previous rule can be rewritten as follow:

p {
   padding: 20px 10px; /* Vertical Horizontal */
}
Two values for the padding shortform

Alternatively, if we provide "four values", we can set the padding for each side of an element "individually". The values are interpreted clockwise, starting at the top:

Four values for the padding shortform

So, if we would remove the 10px right padding from the previous CSS rule, this should give us 20 pixels on the top and bottom of each paragraph, 10 pixels on the left, but "none" on the right:

p {
   padding: 20px 0 20px 10px; /* Top Right Bottom Left */
}
Four values for the padding shortform

Borders:

The border is a line drawn around the content and padding of an element. The syntax of the border property requires that first, we define the stroke width of the border, then its style, followed by its colour, like this:

h2 {
   border: 6px groove #5fe;
}

Like padding, there are –top, –bottom, –left, and –right variants for the border property. Thus, if we would limit our border to only the bottom of our heading, it will be defined as follows:

h2 {
   border–bottom: 6px groove #5fe;
}

Borders are common design elements, but they are also invaluable for "debugging": When you are not sure how a box is being rendered, add a border: 1px solid red; CSS rule to it. This will clearly show the box's padding, margin, and the overall dimensions with just a single line of CSS. After you have figured out why your stuff is broken, simply delete the rule.

Please, refer to the Mozilla Developer Network for more information about border styles.

Margins:

Margins define the space outside of an element's border, i.e. the space between a box and its surrounding boxes.

The margin property also accepts the same shorthand formats as padding.

Margins and padding can accomplish the same thing in a lot of situations, making it difficult to determine which one is the “right” choice.

The most common reasons to help you decide whether to use padding over margin are:

  • The padding of a box has a background, while margins are always "transparent".
  • Padding is included in the click area of an element, while margins are not.
  • Margins "collapse" vertically, while padding does not !

If none of these help you decide whether to use padding over margin, then do not fret about it — just pick one !
In CSS, there is often more than one way to solve your problem.

Margins On Inline Elements:

One of the annoying contrasts between block–level elements and inline ones is their handling of margins. Inline boxes completely "ignore" the top and bottom margins of an element.

Thus, if we would try to add a big margin to an inline element, e.g. a <strong> element, like this:

strong {
   margin: 50px;
}

Then, we would find out that the "horizontal" margins display just like we would expect, while the "vertical" space around our <strong> element will not change one bit.

The strange behaviour of margins on inline elements

If we would change margin to padding, we will discover that this is not exactly the case for a box's padding. It will display the colour set for the background; however, it will not affect the "vertical layout" of the surrounding boxes.

Padding of inline elements Padding of inline elements with a transparent background-colour

The reason behind this is that inline boxes format runs of text inside of a block, and thus have limited impact on the overall layout of a page.

Before you start banging your head against the wall trying to figure out why your "top" or "bottom" margin is not working for a certain element, remember to check its display property.

Vertical Margin Collapse:

Another peculiarity of the CSS box model is the vertical margin collapse. When we have two boxes with vertical margins sitting right on top of each other, they will "collapse". Instead of adding the margins together like we might expect, only "the biggest one" is displayed.

For example, if we would add a top margin of 25 pixels and a bottom margin of 50 pixels to a <p> element, like this:

p {
   margin–top: 25px;
   margin–bottom: 50px;
}

We would expect that each paragraph should have 50 pixels on the bottom, and 25 pixels on the top. That is 75 pixels between our <p> elements, right ?
Wrong ! There is still only going to be 50px between them because the smaller top margin "collapses" into the bigger bottom one.

The smaller margin collapses into the bigger one

Preventing Margin Collapse:

If we do want to prevent the margins from "collapsing", all we need to do is put another invisible element in between them"

<p>I was very busy yesterday so that I could not go back home earlier.</p>

<div style="padding–top: 1px;"></div>

<p>When I came back home I felt so tired that I went directly to bed.</p>

The important part here is that only consecutive elements can "collapse" into each other. Putting an element with non–zero height (hence the padding–top) between our paragraphs forces them to display both the 25px top margin and the 50px bottom margin.

Inserting a non-zero height element like a div element between two paragraph elements prevents their margins from collapsing

Remember that padding never collapses, so an alternative solution to using margin would be to use padding to space out our paragraphs instead of the margin property.

A third option to avoid "margin collapse" is to stick to a bottom–only or top–only margin convention. For instance, if all your elements only define a bottom margin, there is no potential for them to collapse.

Finally, the flexbox layout scheme doesn’t have collapsing margins

Generic Boxes:

Every HTML element lends additional meaning to the content it contains. However, there are many times when we need a generic box purely for the sake of “styling” a web page. This is what <div> and <span> are for.

Both <div> and <span> are “container” elements that can be used for adding CSS styles to some certain sections of a web page. For example, sometimes we need to add an invisible box to prevent a margin collapse, or maybe we want to group the first few paragraphs of an article in order to style them with a different text formatting.

The only real difference between a <div> and <span> is that the former is for block–level content while the latter is meant for inline content.

Explicit Dimensions:

HTML elements define their dimensions automatically.

However, sometimes our desired layout calls for an "explicit" dimension, like a sidebar that is exactly 250 pixels wide. For this purpose, CSS provides the width and height properties, which take precedence over the "default" size of a box's content.

Content Boxes and Border Boxes:

The width and height properties only define the size of a box's content. Its padding and border are both "added" on top of whatever explicit dimensions we set.

The actual size of the CSS box - Content Box

This can be a little counter–intuitive when you are trying to lay out a page. Imagine trying to fill a 600px container with three boxes, where each one of these three boxes has a width of 200px and a border of 1px, they are not going to fit, because all of them have a 1px border (making the actual width of each one of these boxes 202px).

Fortunately, CSS lets you change how the width of a box is calculated via the box–sizing property, whose default value is content–box.

Thus, if we want to force the actual width of each of our three boxes to be 200px including padding and borders, we need to use the following CSS rule:

div {
   box–sizing: border–box;
}

This is much more intuitive. Using border–box for all your boxes is considered a best practice among modern web developers.

If you would like to set border–box for all your CSS selectors at once, add the following CSS declaration at the top of your CSS sheet:

* {
   box–sizing: border–box;
}

Aligning Boxes:

block–boxes alignment is totally unrelated to the text–align property.

There are three methods for horizontally aligning block–level elements:

  • “auto–margins” for center alignment.
  • “floats” for left/right alignment.
  • “flexbox” for complete control over alignment.

Centering With Auto–Margins:

When we set the left and right margin of a block–level element to auto, it will center the block in its parent element.

Note that this only works on blocks that have an "explicit width" defined on them.

Resetting Styles:

Different browsers have different default styles for all of their HTML elements, making it difficult to create consistent stylesheets.

It is usually a good idea to "override" those default styles to a predictable value using the “universal” CSS selector (*)

Try adding this to the top of your CSS stylesheets:

* {
   margin: 0;
   padding: 0;
   box–sizing: border–box;
}

This selector matches every HTML element, effectively resetting the margin and padding properties for our web page. It also converts all our boxes to border–box, which, again, is a best practice.