CSS From the Ground Up

A few months ago, I signed up for Kevin Powell’s Responsive Design Bootcamp hosted on Scrimba. Scrimba is an online platform for learning software development via video lessons and live coding along with the teacher. In addition to the phenomenal teachers they have, Scrimba’s interactivity has made it my favorite platform for learning software.

Powell’s course has transformed the way I think about CSS and responsive design. There was a ton about CSS that I was never explicitly aware of before taking the course, and in this post I’ll be sharing some of those learnings. I find that a lot of developers are confused by CSS and find it to be a pain to deal with, but this course reminded me that like with any other human-designed system, there is always some explanation for the behavior you see.

The difference between block and inline

Have you ever created an element and wondered why it doesn’t seem to show up? Or wondered why an element is so wide even though there isn’t much content in it? Or why elements start on a new line even though you intended them to display next to each other?

Block elements have a width of 100% by default, while inline elements have a width proportional to their content.

If you were ever confused in such scenarios, it’s likely that the answer was in the distinction between block and inline display modes.

And you’ve probably noticed that some elements (like <span> and the anchor tag <a>) are inline by default, whereas others (like <div> and <p>) are block by default. Block-level elements can contain other block and inline elements, but inline elements can only contain other inlines. Powell has an additional video that does a great deep dive into block and inline and how margins, padding, and height work in each case.

Flexbox

In a flex container, if you don’t provide a flex basis, grow, or shrink to the children, they will grow and shrink proportional to the content inside them. The concept of items growing and shrinking to fit their content is a general pattern in CSS that I've come to notice as a result of this course. Previously, I had the intuition that flex children will all have the same width, unless we provide specific values to make them deviate—this is clearly wrong:

By default, flex children will grow according to the content inside them.

In the example above, the first paragraph grows to be much larger than the second, because it has more text. In particular, the paragraph keeps growing until the second div reaches its minimum width. How is minimum width determined? In this case, it’s just the length of the longest word in the div. Notice this in the layout below — the length of the word “thin” is what ultimately determines the layout:

The length of the longest word inside an element determines the “minimum” size that element.

Margins

#1. By default, adjacent margins collapse into each other.

Powell points out that this is one of the biggest sources of confusion when working with margins. You can see in the example below that the margins between the first and second element collapse into each other rather than stacking one next to the other.

The two divs each have a 1em margin, but that does not mean that the space between them is 2em.

Further, margins collapse not only between sibling elements, but also between parent and child elements. See below:

The margins collapse here, so you don’t see any space between the blue outline and the red outline.

Even though both the parent and the child element have a top margin, only the parent’s top margin appears (seen in the empty space above the red box), because the margins have collapsed. MDN has a great article on the specific conditions in which this collapse occurs. The margins only collapse when they’re touching and there is no content between them such as text, padding, or a border (this is why I used an outline instead of a border in this example).

#2. By default, text elements like <p> have a top and bottom margin of 1em.

The div with text inside has no margin, while the <p> does have margin.

If you’ve ever been confused about why there seems to be random extra space between some of your elements, this default behavior may have been the cause. In contrast to paragraph or heading tags, text inside a <div> does not have this margin. There’s a wide set of default styles like this that can even vary by browser/device, and libraries like Normalize CSS were created to standardize these properties.

Em units

For a given element, 1em actually means slightly different things depending on the CSS property you’re applying it to:

  • When setting margin and padding, 1em is equal to the font-size of the element. That means that if I set my padding to 2em and the font size is 16px, the padding will be 32px.
  • When setting font-size itself, 1em is actually equal to the font-size of the parent element. So if my parent's font size is 16px, and I set font-size: 2em, that will make my own font size 32px. Then if I set my margin to 2em, the margin will be 32px • 2= 64px.

The consequence of this that em units can cascade on top of each other — if a hierarchy of three nested elements all have a font-size of 2em, the grandchild's font will be 4 times the size of the grandparent.

The value of 1em is dependent on the parent’s font size.

To prevent this, we use the rem unit, which stands for root em. Wherever in the DOM tree you are and whatever CSS property you are setting, 1rem is always equal to the font size of the root element (which, by default, is 16px).

Grid, positioning, background-blend-mode

Moody red tint added to Hopper’s Nighthawks with CSS.

It was surprising to me that we can achieve a nice-looking image effect without having to use any fancy image editors!

CSS is itself a system that evolves over time

For example, when the flex display mode was introduced, collapsing margins were removed in that specific display mode. You may notice that once you set display: flex, margins no longer collapse. The CSS Working Group made this decision after seeing that collapsing margins were generally confusing for developers. This was an iterative improvement—it's better to drop collapsing margins in newly introduced display mode than changing existing behavior across the web for the block display mode.

Another change that took place in the CSS spec was the definition of the pixel unit. While 1px was originally equal to a single point on the screen, as more and more monitors with varying resolutions were built, the standard was redefined as being 1/196th of an inch.

Some closing thoughts