No Time Dad

A blog about web development written by a busy dad

Building a Responsive Footer with CSS Grid

Here is a demo of the responsive footer described in this post. Be sure to check it out on different size viewports.

Intro

Every good product page needs a footer. So, here is a walkthrough of building a simple responsive footer with CSS grid and a little bit of flexbox. I haven’t done much with css grid up until this point, so I thought a footer section might be a good candidate for using it since footers are often multiple columns of links and what not.

This actually brings up a good point. I am still a little grey on when to use flexbox and when to use grid. I’ve read in a few places that grid should be used for larger scale layouts (like header, sidenav, content, footer, etc) and flexbox should be used more for alignment purposes. I’ve definitely used flexbox for larger scale layouts and it seemed to work fine and wasn’t too complicated, so I guess the jury is still out for me on which to use and when. Using grid is fine for the most part but I find the syntax a little more confusing. But confusing syntax might mean that it is more flexible? I guess I’m still deciding.

Building the Footer

The plan is to have our footer be responsive. The basic template for our footer on larger viewports will be a 4 column grid with a “row” underneath the columns. I put “row” in quotes here because the row is really a column that will span the entire width of the 4 columns above it. The reason I did it this way is because I didn’t know how to implement a row inside of the grid containter that I have already defined to have columns. I’m certain there is a way, but I didn’t want to spend a ton of time on it and this version seems to work just fine. Also, grid allows you to define how many columns you want another column to span, so it sort of lends itself to using the column this way.

The smaller viewport version of the footer will still contain 4 columns but they will only be 2 columns wide. I initially went with 1 column but I felt like there was a lot of unused space on the right, so I went with the 2 column layout for mobile which seems to fit a little better. If you have a longer link or content text in your columns then you might consider a single column as a better option.

For the content itself, each grid column will contain a set of links for your product that are probably similar to what you’d have in a header or navigation menu. The “row” at the bottom will contain some company info and links to social media accounts.

Here is a template of how the footer will look on larger viewports (sorry mobile readers):

Link Col
Link Col
Link Col
Link Col
Company Info Col

Here is a template of how the footer will look on smaller viewports:

Link Col
Link Col
Link Col
Link Col
Company Info Col

The html and css for both of these is pretty straightforward for the most part. For the html we basically just have a grid container that has 5 child elements that are each grid columns. The child elements are all the same, with the exception of the 5th element which we want to span the length of the elements above it.

The Grid Container

The Grid__Container selector is where we declare that we will be using grid via display: grid;. All children of the Grid__Container element automatically become grid items (columns or rows).

Adding the display: grid; property will have no effect until we define how many columns or rows we want and what size they should be.

Once we have the container defined as grid layout via display: grid;, we can define how many columns we want to use for each screen size. For small viewports we want two columns, so we’ll use grid-template-columns: repeat(2, 1fr);, which is equivalent to grid-template-columns: 1fr 1fr;.

The fr stands for “fractal unit”, which means that it will take up the available space in the container. You could also use px or % for your columns, but using fr helps with consistent spacing.

For larger viewports we’ll want 4 columns, so we’ll use grid-template-columns: repeat(4, 1fr);. Keeping mobile first in mind, we’ll need a media query to toggle our selectors based on the min-width of the screen.

Below is a psuedo-code example of how the core structure our html and css will look.

.Grid__Container {
  display: grid;
  /* 2 columns for smaller screens */
  grid-template-columns: repeat(2, 1fr);
}

.Bottom_Column {
  /* The bottom "row" should span the 2 columns on smaller screens */
  grid-column: span 2 / span 2;
}

@media (min-width: 768px) {
  .Grid__Container {
    /* 4 columns for larger screens */
    grid-template-columns: repeat(4, 1fr);
  }
  .Bottom_Column {
    /* The bottom "row" should span the 4 columns on larger screens */
    grid-column: span 4;
  }
}
<div class="Grid__Container">
  <div>Link Col</div>
  <div>Link Col</div>
  <div>Link Col</div>
  <div>Link Col</div>
  <div class="Bottom_Column">Company Info Col</div>
</div>

For the most part, I think laying out the grid is the hardest part of building this footer and it really wasn’t that bad. The next thing we want to do is add the content, adjust spacing, and adjust the colors and styles.

Column Content

The columns themselves will all use flexbox for alignment. This probably could be done just using grid again, but I find it way easier to align things with flexbox so that is what I chose to use here. Each column that contains links will have an uppercase header whose text is less prominant (via reduced opacity) than the link text.

Here is an example of how our css and html are starting to shape-up. Some of the style properties have been omitted for brevity.

.Grid__Container {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
}

.Column {
  /* Use flexbox to handle alignment in the column */
  display: flex;
  flex-direction: column;
  font-size: 14px;
  padding: 1rem;
}

.Column__Header {
  opacity: 0.8;
  text-transform: uppercase;
}

.Column__Link {
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}

.Bottom_Column {
  grid-column: span 2 / span 2;
  padding: 1rem;
  opacity: 0.8;
}

@media (min-width: 768px) {
  .Grid__Container {
    grid-template-columns: repeat(4, 1fr);
  }
  .Bottom_Column {
    grid-column: span 4;
  }
}
...
<div class="Grid__Container">
  <div class="Column">
    <div class="Column__Header">...</div>
    <div class="Column__Link">...</div>
  </div>
  <div class="Column">
    <div class="Column__Header">...</div>
    <div class="Column__Link">...</div>
  </div>
  <div class="Column">
    <div class="Column__Header">...</div>
    <div class="Column__Link">...</div>
  </div>
  <div class="Column">
    <div class="Column__Header">...</div>
    <div class="Column__Link">...</div>
  </div>
  <div class="Bottom_Column">
    <div class="Bottom_Column__Content_Container">...</div>
  </div>
</div>
Bottom Column

The last piece of the puzzle for this footer is to determine how the bottom “column” content will behave on small and large viewports. On small viewports I think it looks best if the content is stacked instead of trying to stretch it all across a row. On larger viewports we do want to spread the content out across the column since we have the space. To accomplish this we’ll use flexbox and toggle between flex-direction: column; on smaller viewports and flex-direction: row; on larger viewports.

...
<div class="Bottom_Column">
  <div class="Bottom_Column__Content_Container">...</div>
</div>
...
...
.Bottom_Column__Content_Container {
  /* Stack the content and center it in the container on smaller viewports */
  display: flex;
  flex-direction: column;
  align-items: center;
}

@media (min-width: 768px) {
  ...
  .Bottom_Column__Content_Container {
    /* Spread the content out evenly in a row on larger viewports */
    flex-direction: row;
    justify-content: space-between;
  }
  ...
}

Conclusion & Full Code

Overall, building this was a fun foray into using css grid. I’m sure there are better ways to utilize grid than what is shown here but I think it works really well for being a fairly easy implementation of a responsive footer using just css and html. If you wanted some additional reading, MDN has a really great article on all things css grid that goes way more in-depth on the subject than I did here. Below is the full code for the footer.

NOTE: Consider using some css resets and setting your box-sizing as follows or something similar for the page: *, *:before, *:after { box-sizing: border-box;}.

/* Placeholder for content that would normally push footer to the bottom */
.Content__Container {
  display: flex;
  min-height: 100vh;
  flex-direction: column;
  justify-content: space-between;
  background-color: whitesmoke;
}


/* Start Footer container */
.Grid__Container {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  background-color: #14213d;
  color: white;
  padding: 1rem;
}


/* Single column container */
.Column {
  display: flex;
  flex-direction: column;
  font-size: 14px;
  padding: 1rem;
}


/* Colum specific styles */
.Column__Header {
  opacity: 0.8;
  text-transform: uppercase;
}

.Column__Link {
  text-decoration: none;
  color: white;
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}

.Column__Link:hover {
  opacity: 0.8;
}


/* Bottom column of the footer  */
.Bottom_Column {
  grid-column: span 2 / span 2;
  padding: 1rem;
  opacity: 0.8;
}

.Bottom_Column__Content_Container {
  display: flex;
  flex-direction: column;
  align-items: center;
}


/* Social icons */
.Social__Icon {
  width: 1.5rem;
  height: 1.5rem;
  fill: white;
}

.Column__Social_Link {
  padding-right: 0.5rem;
  padding-left: 0.5rem;
}

.Column__Social_Link:hover {
  opacity: 0.8;
}


/* Media queries */
@media (min-width: 768px) {
  .Grid__Container {
    grid-template-columns: repeat(4, 1fr);
  }
  .Bottom_Column {
    grid-column: span 4;
  }
  .Bottom_Column__Content_Container {
    flex-direction: row;
    justify-content: space-between;
  }
}
<div class="Content__Container">
  <main class="Content"></main>

  <footer class="Grid__Container">

    <div class="Column">
      <div class="Column__Header">Solutions</div>
      <a href="#analytics" class="Column__Link">Analytics</a>
      <a href="#marketing" class="Column__Link">Marketing</a>
      <a href="#innotivation" class="Column__Link">Innovation</a>
      <a href="#onboarding" class="Column__Link">On Boarding</a>
      <a href="#development" class="Column__Link">Development</a>
    </div>

    <div class="Column">
      <div class="Column__Header">Support</div>
      <a href="#pricing" class="Column__Link">Pricing</a>
      <a href="#apidocs" class="Column__Link">API Docs</a>
      <a href="#examples" class="Column__Link">Examples</a>
    </div>

    <div class="Column">
      <div class="Column__Header">Company</div>
      <a href="#about" class="Column__Link">About</a>
      <a href="#blog" class="Column__Link">Blog</a>
      <a href="#careers" class="Column__Link">Careers</a>
      <a href="#news" class="Column__Link">News</a>
    </div>

    <div class="Column">
      <div class="Column__Header">Legal</div>
      <a href="#claim" class="Column__Link">Claim</a>
      <a href="#blog" class="Column__Link">Privacy</a>
      <a href="#careers" class="Column__Link">Careers</a>
    </div>

    <div class="Bottom_Column">
      <div class="Bottom_Column__Content_Container">
        <div class="Column__Link">
          Awesome Company LLC.
        </div>

        <div class="Column__Social_Icons_Container">
          <a href="#twitter" class="Column__Social_Link">
            <svg class="Social__Icon" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>Twitter icon</title><path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z" /></svg>
          </a>
          <a href="#facebook" class="Column__Social_Link">
            <svg class="Social__Icon" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>Facebook icon</title><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" /></svg>
          </a>
          <a href="#youtube" class="Column__Social_Link">
            <svg class="Social__Icon" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>YouTube icon</title><path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z" /></svg>
          </a>
        </div>

      </div>
    </div>
  </footer>
</div>