Full Bleed Sections

This demo is already complete. Finished files at the bottom of the page.

The problem: You want areas with backgrounds that cover the full viewport, but text and other content still need to be contained.

To achieve this we need to deal with both the width and the height in some way. Both factors are pretty simple on their own, but combining them effectively can be tricky.

Width

Normally to contain the width of some content, we'd slap a max-width and some auto margins on the element and call it a day. Unfortunately in this case that's not enough, because the background stops at the edges of the element.

Text contained to a readable width, but so is the background.

What we effectively need is to leave the element with the background alone, so it still spans full width, and contain just the content inside it.

Background spans full width (within this page's constraints) while text is nicely contained.

Height

The height setting is a little easier, with one (big) consideration. Setting explicit height values in web design is generally a bad idea. The height should almost always adapt to the length of the content, and we rarely know exactly how tall that will be.

Luckily, min-height + viewport units take care of this very elegantly. Using min-height, we can ensure the element is at least as tall as the viewport, and if the content is longer it's no problem... the container just keeps growing.

One Solution - Nested Containers

<div class="outer-container">
    <section class="inner-container">
        <h2>...</h2>
        <p>...</p>
        <p>...</p>
        <img>
        <figure>...</figure>
        <table>...</table>
        <p>...</p>
    </section>
</div>
.outer-container {
    background-color: DarkRed;
}

.inner-container {
    min-height: 100vh;
    padding: 1rem;
    max-width: 36rem;
    margin-left: auto;
    margin-right: auto;
}

In this method, the outer container gets the background color, and the inner container gets the height and width settings. The outer container will span the full width, and it's height will grow as needed along with the inner container.

This is very similar to the div.wrapper we've been using all semester. The body tag spans full width, and div.wrapper is contained and centered.

This method is very simple and reliable. The main drawback is that it requires additional HTML markup which is kind of ugly. With several of these full bleed sections, we end up with a lot of redundant HTML containers just for the background color.

Another Solution - Creative CSS Selectors

<section class="outer-container">
    <h2>...</h2>
    <p>...</p>
    <p>...</p>
    <img>
    <figure>...</figure>
    <table>...</table>
    <p>...</p>
</section>
.outer-container {
    min-height: 100vh;
    padding: 1rem;
}

.outer-container > * {
    display: block;
    max-width: 36rem;
    margin-left: auto;
    margin-right: auto;
}

We can eliminate the inner container by targeting the inner content directly using a CSS Selector.

This method uses one container for the full bleed area, and directly targets all of the child elements to set their max-width. The HTML is cleaner, but we have to account for the fact that the child elements could be anything at all. Setting display: block allows everything to be centered using margins, but this can be a problem for certain kinds of elements like tables, which will lose their special properties if their display mode is changed.

It's also important to note with this method that the max-width is set in rems, not ems. Pixels or percentages would work too, but if ems are used, the effective max-width would vary based on each element's font size. In other words, headers with larger text would end up with a wider max-width... definitely not the consistent contained width that we want.

OK, How About Grid?

<div class="outer-container">
    <p>...</p>
    <p>...</p>
    <img>
    <figure>...</figure>
    <table>...</table>
    <p>...</p>
</div>
.outer-container {
    min-height: 100vh;
    padding: 1rem;
    display: grid;
    grid-template-columns:
      [full-start] 1fr [main-start] minmax(auto, 36rem) [main-end] 1fr [full-end];
    align-content: start;
}

.outer-container > * {
    grid-column: main-start / main-end;
}

This final method uses CSS Grid. Each full bleed section becomes a grid container. Here I'm naming the grid lines, and each element inside the container gets placed in the middle column, leaving the left and right sides empty.

Since we're changing the normal height settings, we also need an align-content setting. This keeps the grid from vertically stretching the content to fill our min-height. align-content: center or align-content: start work well.

OK, yeah, let's go with that!