Style a Blog Layout with CSS
Tags: tutorial, beginners, css, webdev
Published: 2020-03-13 03:24:15

In this post, we will learn about CSS properties and layout patterns useful for styling content such as for a blog, including 

- how to center website content
- about special selectors
- how margin collapsing works
- how to use Inspector to help create definitions for complex properties like `linear-gradient`
- how to make a circular image with one line of CSS

This is the thirteenth post and video in a series on learning web development. [Learn more about the series and see the post schedule >](https://thinkdobecreate.com/learnwebdev)

You may want to refer back to the first lesson that created our initial blog HTML, episode 5:

{% link https://dev.to/5t3ph/create-a-blog-layout-in-html-5hf1 %}

You may watch the following video or follow along with the expanded transcript that follows.

{% youtube e6nBu5aFK8M %}

[*Review the source code* >](https://github.com/5t3ph/howtowebdev/tree/master/ep13-blog-css)

To begin this lesson, open the [starter project](https://github.com/5t3ph/howtowebdev-starter) you began in episode 1, or [review the source files](https://github.com/5t3ph/howtowebdev/tree/master/ep12-accessibility-aboutpg) from episode 12.

To begin this lesson, open our project in VSCode.

In the Terminal, type the start command `npm run start` to run the project.

Open `blog-layout.html` in VSCode, and organize your screen to be split with the browser. Then update the browser url to include `/blog-layout.html`.

![initial blog layout appearance](https://dev-to-uploads.s3.amazonaws.com/i/c4x5wrmmrg9yr0nkk345.png)

Now, this page may seem a little shocking at this point since it is inheriting all of our styles due to linking to our single `style.css` file. We're no longer benefitting from that, so let's first create a new CSS file called `blog-layout.css`.

Then in our HTML file, update the stylesheet `link` in the `<head>` from `style.css` to `blog-layout.css` and save. Now we're back to default browser styles.

```html
<link rel="stylesheet" href="blog-layout.css" />
```

We'll first create a rule for `body`:

```css
    body {
    	font-family: sans-serif;
    	color: #222;
    }
```

I chose the `color` value of `#222` because an off-black is recommended as a little easier on the eyes when reading long-form content like a blog post.

Next, let's adjust our typographic scale, which means the size assigned to each typography element. 

Before that, let's temporarily comment out the image so we can focus on the type.

```html
    <!-- <img src="http://placecorgi.com/200x150" alt="Good corgi doggo" align="left"> -->
```

![layout with no image](https://dev-to-uploads.s3.amazonaws.com/i/isttjc6d2ie25llbbquu.png)

For the type, we'll do something similar to what we defined originally in `style.css`, including a rule to reset the margins. But we'll reduce our rules to cover h1-h3 for this demo.

```css
    h1, h2, h3 {
    	margin: 0 0 0.35em;
    }
    
    h1 {
      font-size: 40px;
    }
    
    h2 {
      font-size: 28px;
    }
    
    h3 {
      font-size: 20px;
    }
```

Looking at our page, it feels like the spacing is a little off around the paragraphs. Let's try adding a `margin` definition for `p`:

```css
    p {
    	margin: 0 0 1.15em;
    }
```

That feels a little better, but let's duplicate each paragraph, and then remove some words out of each paragraph to mimic real text a bit more. Then save and let's review.

![layout with updated type scale and spacing](https://dev-to-uploads.s3.amazonaws.com/i/r9u8lrq2l85h27fdunkl.png)

It looks nice between paragraphs, but it would be nice to use a bit more space to emphasize the sections created by use of the `h2`. For this, we could use a class, but that would require remembering to use the class each time we added an `h2`.

Instead, we can use the adjacent sibling selector which is `+` to select `h2` that follow `p` and create the following rule:

```css
    p + h2 {
    	margin-top: 1.5em;
    }
```

Save, then with Inspector we can see that there is only `margin-top` on the second `h2` because it is the only one following a `p`.

![margin-top on the h2](https://dev-to-uploads.s3.amazonaws.com/i/prn7dq7igfzvw2j4hrqa.png)

Inspector also helps us see a few other interesting things about how the `margin-top` was applied. First, since we used the relative `em` unit, the space is equal to 1.5 * 28px, since the `font-size` of the `h2` is set to `28px` which on the Computed tab we can see becomes `42px`. 

But wait - isn't there a `margin-bottom` on every `p`? If we inspect the paragraph prior to the `h2` we see there is a computed `margin-bottom` of `18.4px` and then if we hover the `h2` we see it's `margin-top` extends to the bottom of the paragraph, not to the bottom of the paragraph's margin.

![demo of collapsing margins between the p and h2](https://dev-to-uploads.s3.amazonaws.com/i/mvtylyfluds9gayu10rz.gif)

This is due to a particular behavior of margins which is called "collapsing". Competing margins collapse into each other with the smaller margin being collapsed into the larger margin. 

![demo of equal margins collapsing](https://dev-to-uploads.s3.amazonaws.com/i/i29ies4gjhl347qzbmy5.gif)

The takeaway here is that if you have set equal margins on two bordering elements, like `16px`, the space will not be double the value at `32px`, but rather collapse to be `16px` total. 

You can refresh the page to clear the `element.style`.

With our window half-width, we're missing the whole picture we have with our layout, so let's extend both VSCode and the browser back to full-width and then move beyond typography.

Open `blog-layout.html` in VSCode, and let's review our structure. Our primary containing elements are `header`, `main`, and `footer`. Let's go ahead and remove the `<hr>` we added in the HTML lesson since we'll replace it with CSS.

![full-width layout](https://dev-to-uploads.s3.amazonaws.com/i/jx5fqfdgyfcmlo1v5g4t.png)

With the browser window full-width, it's clear that our layout is aligned to the screen left, which make sense as all the containing elements are block elements and we learned previously that that's their default behavior. But you have likely noticed from viewing other websites that there is generally:

1. A max-width set for the main content area; and
2. The main content area is centered in the browser window

Switch back to our CSS file, and let's add a new rule:

```css
    header, main, footer {
    	max-width: 800px;
    	margin-left: auto;
    	margin-right: auto;
    }
```

Save, and you'll see our content now appears more centered. 

If we Inspect, you can see that's the result of adding the `auto` margins. The `auto` keyword is unique to `margin` and tells the browser to compute the value of extra space. We've used it on both sides, so it's effectively pushed our containers to the center. 

![auto margins highlighted](https://dev-to-uploads.s3.amazonaws.com/i/jjoxxh6zv2wszj3o4yoy.png)

Using Inspector, you can toggle off the `margin-right` definition and then see how the remaining `margin-left: auto` rule has caused the containers to slide all the way to the right side.

![margin-left highlighted](https://dev-to-uploads.s3.amazonaws.com/i/6gkpa1hn1a5w2qen2utj.png)

However, if we test toggling off the `max-width` rule, there is no extra space left around each element which eliminates the centering behavior.

This is looking good, but we want our header to stand out more, so let's add a rule:

```css
    header {
    	background-color: rebeccapurple;
    	color: #fff;
    	padding: 24px;
    }
```

![header background](https://dev-to-uploads.s3.amazonaws.com/i/7h2ex3wq01e6ig01elji.png)

Save, and you may agree that's not quite the effect we were going for. It would be nice if the `background-color` stretched across the window. But we placed our `max-width` rule on the header directly, so it's limiting the width of the background as well.

It's time to introduce a utility class to handle the width and centering, so let's change that rule to use the selector for a class: `.container` and save.

```css
    /* header, main, footer { */
    .container {
    	max-width: 800px;
    	margin-left: auto;
    	margin-right: auto;
        padding: 24px;
    }
```

Let's also move the padding rule from `header` into the `.container` class. Unlike `margin`, padding does not collapse since it's *inside* the element it's defined on. This will help create visual space between our elements.

Then in our HTML, we'll make 3 adjustments. First, wrap the content of `header` and `footer` with a `div` and include the `container` class.

```html
<!-- inside `header` and `footer` -->
<div class="container">
  <!-- content -->
</div>
```

Inside `main` we already have the child element of `article` so we can add the container class to that, then save and review.

```html
<main>
  <article class="container">
```

That's more like it! 

But there's still a bit of leftover space. Using Inspector to explore, we find that `margin` on `body` is the culprit, so on the `body` rule let's add the definition `margin: 0` and save.

![header background with children in .container](https://dev-to-uploads.s3.amazonaws.com/i/j5nmvyjs62wuta5kdszl.png)

Now let's add a new rule to the `footer`:

```
    footer {
    	border-top: 2px solid rebeccapurple;
    }
```

Save - and hold on, that did more than we wanted it to! 

![footer border doubled in blockquote](https://dev-to-uploads.s3.amazonaws.com/i/qvcd4acc3w49h2a9ftdc.png)

There's now also a border within our `blockquote` which also contains a `footer` element.

We could create a utility class to apply a border, but for purposes of this lesson, let's use the child combinator selector which is the `>` and means to select only elements that are a direct child of the qualifying selector. We'll modify our selector to `body > footer` and save. Now the footer that is nested within `blockquote` is unaffected by this rule.

Speaking of our `blockquote`, let's give him some styling love, too.

It can be helpful to use the `element.style` section to try out new styles before you commit to them in your stylesheet, and also to take advantage of the helpers provided by the browser, so let's select the `blockquote` and try it.

Add `background` and then if we begin to type `linear-gradient` the browser not only autocompletes but provides a default value. For things like gradients, developing in the browser is extra useful because the syntax is tricker than your average definition.

![browser's auto linear-gradient](https://dev-to-uploads.s3.amazonaws.com/i/9rf3r1mognw7q3a6p8ch.png)

Instead of the pure black the browser defaulted to, let's update to a softer value that's a tint of `rebeccapurple`. To figure out that value, let's Inspect `header` and open the color picker, and slide the picker icon at roughly a 45 degree angle toward the top left until it's on a really light purple. Click on the generated hex value and copy it. Don't worry about reverting the `header` value since we're focusing on the `blockquote` right now.

Return to the `blockquote` and update the value of `black` in the `linear-gradient` to the value you copied. The value I selected is `#eddbff`. 

![using Inspector to choose purple tint](https://dev-to-uploads.s3.amazonaws.com/i/dmxjszzeck1abn1dpg3d.png)

We can now copy the background definition, and move it to our stylesheet, where we'll add a few more properties to complete the rule:

```css
    blockquote {
    	background: linear-gradient(45deg, #eddbff, transparent);
    	color: rebeccapurple;
        margin-left: 0;
        margin-right: 0;
        padding: 1em;
        border-radius: 4px;
    }
```

![final blockquote appearance](https://dev-to-uploads.s3.amazonaws.com/i/opoyycr94epqcqo3mzn0.png)

We're almost done, but we need to deal with our image, so let's uncomment that to add it back in. Let's also update the `src` url to drop the `x150` which was added in error in the HTML lesson.

![default image placement](https://dev-to-uploads.s3.amazonaws.com/i/gf4yrg8e9n2zmkva1jcl.png)

The main issue here is the lack of space between the `img` and the surrounding content. Now, we want a rule that won't affect every `img` we may add to the site, just left-aligned images in our articles.

We also committed an error in our HTML lesson - which was done purely because we hadn't learned CSS yet! That error was using the `align` attribute which is actually what is called "deprecated". Deprecation means it used to be a valid attribute but is no longer recommended and support for it could be dropped in future browser versions, so we shouldn't rely on it.

Instead let's create a utility class:

```css
    .img--align-left {
      float: left; /* replaces the style previously inherited by the browser */
      margin: 0 16px 16px 0;
    }
```

Then on the `img` HTML, remove the `align` attribute and replace it with `class="img--align-left"`. 

```html
<img src="http://placecorgi.com/200" alt="Good corgi doggo" class="img--align-left" />
```

Save, and it's looking better with the `margin` added to give it some breathing room.

Let's add one more property for visual flair and use `border-radius: 50%` and save. You can see that the image now appears as a circle! `50%` is a special value that can produce a circle, but only on square elements. If the element is not square, it will begin to have a more oval appearance. 

![circular image with border-radius](https://dev-to-uploads.s3.amazonaws.com/i/b7hbicmdzbawfvh542ar.png)

Our use of the placecorgi service is returning a `200px` square image, which mimics an image that you may add into your blog from a CMS such as WordPress where you could also define precise dimensions, therefore ensuring a square base image. We'll explore a different method of ensuring visually consistent image sizes in our capstone project.

Finally, let's update our `margin` to actually use a negative value instead of `0` for the `margin-left`, so the definition becomes `0 16px 16px -20px` and save. This allows it to tuck into the space created by the `padding` defined by `.container` but not extend out beyond the boundary of the `article`.

![image with negative margin-left](https://dev-to-uploads.s3.amazonaws.com/i/smk27306ekb6p8r6nmcf.png)

Here's the final result on CodePen:

{% codepen https://codepen.io/5t3ph/pen/ExjENKv %}

> **Next up in Episode 14:** Styling a Card Layout