Lesson 26 - Home page panels

Course
Learn Eleventy From Scratch
Module
Front-End Build

We’ve got 3 different types of panel on our home page, so let’s style them all up in one lesson.


Let’s dive right in with our first panel: the call to action. If you remember from earlier in the course, this is a global call to action that appears on most of the pages in our site.

Thanks to the CUBE CSS methodology, most of this panel styling is done. All we need to do now is add some compositional CSS and a utility that provides us with a consistent heading style.

Call to action block permalink

Create a new file in your blocks folder called _cta.scss and add the following:

Code language
scss
.cta {
  // This is a dark panel, so we need to flip the selection styles
  ::selection {
    // We set this as an RGBA because that’s how you get a solid color, by using 0.99
    // alpha value. Browsers are wild.
    background: rgba(get-color('light'), 0.99);
    color: get-color('dark-shade');
  }

  @include media-query('md') {
    &__inner {
      display: grid;
      grid-gap: get-size('700') get-size('500');
      grid-template-columns: repeat(12, 1fr);

      @supports (display: grid) {
        > * {
          margin: 0;
        }
      }
    }

    &__heading {
      grid-column: 1/9;
    }

    &__summary {
      grid-row: 2;

      // Pull the content in from the right, by reversing columns
      grid-column: 12/5;
    }

    &__action {
      grid-row: 3;
      grid-column: 3/12;
    }
  }

  @include media-query('lg') {
    &__inner {
      grid-gap: get-size('500');
    }

    &__summary {
      grid-column: 12/7;
    }

    &__action {
      grid-column: 6/12;
    }
  }
}

The first thing we do is flip the ::selection styles. The global selection styles won’t work because this panel has a dark background. Notice how we use rgba to make a .99 opacity version of this colour? Yep, that’s some browser weirdness that we have to get over. Luckily, Sass allows us to pass a token into the rgba function.

At md and up, we introduce CSS Grid again. This time, we create a 12 column grid and use grid-column and grid-row to place content where we want it, just like we did with the intro. This enables us to create a pretty funky offset layout.

There’s also some progressive enhancement in action. By default, the call to action uses the .flow utility. This utility adds margin to each sibling element. This works fine for old browsers and smaller viewports where all we want is vertical space between items, but it does become a problem in our grid.

I wrote a post about the flow utility a couple of years ago. You should definitely check it out, because I use the utility all the time and it is everywhere on this site.

We also created The Stack in Every Layout which uses a very similar principle.

To fix this layout issue caused by .flow, we use @supports to detect grid support. If support exists, we remove the margin from the direct children of our .cta block, which allows grid-gap to take full control of the spacing.

Fancy a challenge? Go back to the .intro block and try to implement .flow and then progressively unset it using the same technique as above.

Right, let’s make the headline look good.

Headline utility permalink

Almost every heading on this site looks the same in terms of size, so it makes sense to create a global utility that responsively applies the correct design tokens, based on viewport.

Create a new file in your utilities folder called _headline.scss and add the following to it:

Code language
scss
$headline-highlights: ('dark', 'primary', 'secondary', 'quaternary', 'quinary');

.headline {
  font-size: get-size('700');
  max-width: 18ch;

  @include media-query('md') {
    font-size: get-size('800');
  }

  @include media-query('lg') {
    font-size: get-size('900');
  }

  &::after {
    content: '.';
  }

  // For each color, create an exception
  @each $headline-highlight in $headline-highlights {
    &[data-highlight='#{$headline-highlight}'] {
      &::after {
        color: get-color($headline-highlight);
      }
    }
  }
}

The first thing we do is apply font sizes for each breakpoint and then add a full stop at the end, using the &::after pseudo-element. So far, so simple.

To make things interesting, we generate the heading exceptions using a Sass map. The map is $headline-highlights and it's essentially an array of design tokens for colour. We then—using an @each loop—generate a [data-highlight] exception for each colour. This means that the full stop will have a design token applied to it to make it a different colour than our text. For example, this headline element has data-highlight="quaternary" in the HTML.

Adding our CSS to critical CSS permalink

The call to action is used everywhere on the site, so we’re going to add it to our global, critical CSS. Open up eleventy-from-scratch/src/scss/critical.scss and add the following, with the other block @import statements:

Code language
scss
@import 'blocks/cta';

Then, on line 92 add the following, with the other utility @import statements:

Code language
scss
@import 'utilities/headline';

When you load up your browser at http://localhost:8080 and scroll down to the call to action, it should now look like this:

The call to action now has a nice offset layout with a salmon coloured full stop at the end of the heading

Let’s make that feed of featured work look good. Create a new file in your blocks folder called _featured-work.scss and add the following to it:

Code language
scss
.featured-work {
  &__item {
    display: block;
  }

  &__action {
    text-align: center;
  }

  @include media-query('md') {
    &__inner {
      display: grid;
      grid-template-columns: repeat(12, 1fr);
      grid-gap: get-size('700') get-size('500');

      @supports (display: grid) {
        > * {
          margin: 0;
        }
      }
    }

    &__intro {
      grid-column: 1/13;
      align-self: end;
    }

    &__item {
      &:nth-child(odd) {
        grid-column: 1/8;
      }

      &:nth-child(even) {
        grid-column: 13/6;
      }
    }
  }

  @include media-query('lg') {
    grid-template-columns: repeat(2, 1fr);

    &__intro,
    &__item {
      &:nth-child(odd) {
        grid-column: 1/7;
      }

      &:nth-child(even) {
        grid-column: 13/7;
      }
    }
  }
}

Guess what? We’re using Grid again! This time, we use it to create a lovely staggered layout at medium viewports (the md breakpoint).

Using :nth-child(odd) and :nth-child(even), we place the items either out to the right or to the left. To place items to the right, we reverse our grid-column rule to be 13/6. This means we want it to start at grid line 13 and finish at grid line 6, which makes it align to the right. Cool, right?

Finally, at the largest breakpoint, we convert this to a standard two column grid and use :nth-child(odd) and :nth-child(even) to place the items each side. Since we used these in the previous breakpoint, it makes sense to use them again because we’re in a bit of a specificity pickle otherwise. It also makes the code a bit more predictable, which is always a good thing.

Let’s add that to our home critical CSS. Open up eleventy-from-scratch/src/scss/home.scss and right at the end, add the following:

Code language
scss
@import 'blocks/featured-work';

Now, when you load up http://localhost:8080 and scroll down to the work feed, it should look like this:

The featured work feed using a nice 2 column, 2 row layout, because we are at the highest breakpoint

Studio feed permalink

Last panel now. The remote data feed that loads in our “studio images” that we definitely didn’t just grab from Unsplash 👀

This is an overflow scrolling panel that a user can scroll using either a scrollbar, which appears automatically, or a swipe gesture, if available. We can do all of this with CSS, so we don’t need to bother kludging up the browser with JavaScript.

Create a new file called in your blocks folder called _studio-feed.scss and add the following to it:

Code language
scss
.studio-feed {
  &__list {
    display: flex;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;

    > * {
      width: 16rem;
      height: 13rem;
      flex-shrink: 0;
      padding: 0 0 get-size('400') 0;

      img {
        width: 100%;
        height: 100%;
        object-fit: cover;
      }
    }

    > * + * {
      margin-inline-start: get-size('500');
    }
  }

  @include media-query('md') {
    &__list {
      > * {
        width: 28rem;
        height: 17rem;
      }
    }
  }
}

What we’ve done here is make the &__list have overflow: auto and then add flexbox with no wrapping. This is the default behaviour, because flexbox will keep trying to fill space, even if it isn’t technically there. With this in place, we now have a (don’t make me say it) carousel.

We explicitly size each item to keep things nice and consistent because each image could rightly be a random size. We just don’t know at this point, so we should be writing our CSS with that in mind.
Because we’re explicitly sizing each item, we use object-fit: cover which prevents the image from looking squashed. This is because the browser will size the image within the bounds of the image so it’s cropped at the centre.

All we do then is increase the size of these images at larger breakpoints.

Let’s add that to our home critical CSS. Open up eleventy-from-scratch/src/scss/home.scss and at the end, on line 13 add the following:

Code language
scss
@import 'blocks/studio-feed';

Now, if you load up http://localhost:8080 and scroll down to the studio feed, it should look like this:

A carousel of very cringe images from some trendy design studio somewhere

Wrapping up permalink

That’s our home page styled up! We’ve also got most of our site’s styles written now, so all we have to do is visit some of the other sections, add some compositional styles and then we’re done.

Let’s tackle the blog next.


Comments

Next up: Lesson 27 - Styling the blog

Now it’s time to make our blog feeds and blog posts look exquisite.

Get started

Help! My version of this lesson isn’t working.

Don’t panic, you can download the working project here! Once they are downloaded: replace your project with these files and run npm install. You can read more information here.

Download project files

Hello, I’m Andy and I’ll help you build fast, accessible websites & design systems.

I’m a freelance CSS and design systems consultant, based in the UK. I specialise in design systems and creative web design, such as landing pages and campaign work.

I’m currently helping Google by refactoring the CSS and creating a design system for web.dev, but I have availability for projects such as small websites, landing pages and consultancy. I will have full availability for larger projects in January 2022.

Hire me