Thumbnail Grid Layout Instructions

The following exercise will walk you through creating a web page that uses CSS to create a thumbnail grid of products. When the exercise is complete, you will have a web page that looks something like what is shown in steps/final.html.

Through this exercise you will gain experience in the following techniques:

Start the exercise using the html file called start-here.html. The css you'll use is already linked at the top of the page.

If you get lost or need to restart the exercise at a specific point, you can refer to the HTML files in the steps folder. Each of these is named for the specific step in the exercise and linked to for reference.

Semantic Markup

Your starting point should look like step-1.html

The starting html contains a list of thumbnails and links. Each list item looks similar to this:

<li>
   <img src="images/clock_thumb.jpg" alt="alarm clock" />
   <p class="description">Analog Travel Alarm Clock Braun
      <span class="price">$40.00</span>
   </p>
</li>
  1. We can make this markup more meaningful by using the figure and figcaption elements. Review proper usage here: http://html5doctor.com/the-figure-figcaption-elements/

    Modify the first couple of list items to include figure and figcaption elements. You should not need to remove any markup.

    When finished, each thumbnail block should be marked up like the following:

    <li>
       <figure>
          <img src="images/clock_thumb.jpg" alt="alarm clock" />
          <figcaption>
             <p class="description">Analog Travel Alarm Clock Braun
               <span class="price">$40.00</span>
             </p>
          </figcaption>
       </figure>
    </li>
  2. The thumbnails should also be links to their respective product pages.

    For each thumbnail, wrap the entire figure in a link. As of HTML5, it’s ok to wrap a block level elements with a link.

    <li>
       <a href="#" title="View product details">
           <figure>
               <img src="images/clock_thumb.jpg" alt="alarm clock" />
               <figcaption>
                   <p class="description">Analog Travel Alarm Clock Braun
                       <span class="price">$40.00</span>
                   </p>
               </figcaption>
          </figure>
       </a>
    </li>
  3. Let’s also center our page and set a max-width of 1400px. We can use the container class on the outermost section for that.

    <body>
      <div class="container">
    
        <header>
          <h1>Thumbnail Grid Layout Demo</h1>
       </header>
    1. Create a CSS rule using the container class to set the max width of the page to 1400px and center it.
    2. See notes from Week 6 for help on centering a layout.
  4. Set the margin on the body to be 1em on the top and 3% on the left and right.

Create a grid

Your starting point should look like step-2.html

We're going to align our 8 thumbnails into a grid to make them display better. We'll start with aligning 4 thumbnails in each row.

This will create a 4x2 grid:

  1. We'll use the CSS Flexbox model to arrange our thumbnails into rows. Flexbox can arrange items into columns as well. CSS Tricks has an excellent reference page on flexbox:

    1. A Complete Guide to Flexbox

    Whenever we want elements to use flexbox as their layout module, the first step is to set the container of the elements to use flexbox. We do this by setting the display property to the value of flex.

    In this case, we want our thumbnails to use flexbox. Each thumbnail is in an li element. This means the container will be the ul.

    Illustration of list items and container
    1. Create a CSS selector that targets the ul that is the descendent of the thumbnail-grid class.

      Using the thumbnail-grid class as part of our CSS selector will ensure that the styles we add below will only affect our thumbnails and not the rest of the site.

    2. Add the following property to the selector you just created:

      display: flex;

    If done correctly, you should see your thumbnails arranged in a line, stretching off the page.

    Now that the ul has been set to display: flex;, it is referred to as the flex container. Each of the lis are the flex items.

  2. Flexbox allows you to arrange items in rows or columns, and also order items from left-to-right, right-to-left, top-to-bottom, or bottom-to-top. This stems from the desires to natively support languages that are written vertically or from right-to-left.

    Flexbox defaults to arranging items in a row and from a left-to-right order, much as you would expect in latin-based language.

    Use the Developer Tools or Web Inspector to modify the following propties to view their effects:

    1. Add the following property to the flex container:

      flex-direction: column;

      You should see the items stack in a column.

    2. Change flex-direction to row and add the following property to the flex container:

      flex-wrap: wrap-reverse;

      The flex items should now be arranged in a grid, with the last item first.

  3. In your CSS file, add flex properties to the flex container so that the flex items display in a row and wrap.

    .thumbnail-grid ul {
       display: flex;
       flex-direction: row;
       flex-wrap: wrap;
    }
  4. Our thumbnails are too large at their natural size to fit four across.

    1. To fit 4 thumbnails across the page, each thumbnail should have a width of 25% of its container: (100% รท 4).

    2. Create a new selector in your CSS for the flex items, which in this case are each li element. Make sure to use the thumbnail-grid class in your CSS to only target our li's in our thumbnail grid.

      .thumbnail-grid li {
      
      }
    3. Set the width of each thumbnail li to 25%.

  5. Our images are now too large to fit in their containers and are overflowing out of their thumbnails. This of course is also breaking our layout.

    Images are one of the few content elements that will not reflow to fit inside their containers to fit automatically.

    1. Fix this by setting the CSS max-width property on your images to 100%. This will cause the images to never exceed 100% of their containing box.

      This is a very important step to ensure our designs are responsive.

  6. Our thumbnail blocks should now fit into a 4x2 grid on our page.

    1. Looking closely we can see that our images are unusually small and have a lot of space around them.

    2. Use the web inspector to look at one of the figure elements. Notice that it has a lot of margin applied to it.

      This is a browser default that is not getting reset by the reset.css (because figure is an html5 element).

    3. Let’s reset it ourselves. Create a CSS rule for figure elements that sets both the margin and padding to 0.

      Once we’ve done this, our images will be larger, but there will no longer be a gutter between them.

    4. Add a gutter using the margin property on each of the li items. The margin should only be on the right and be 1.33%.

      This will cause our rows to only have three items, bumping the fourth one down because there isn't enough space in the row.

  7. We can fix our layout grid by adjusting the width and margins of our thumbnails to fit. The elements in each row must add up to less than 100% to fit. If they are over 100%, the last element will fall to the next row.

    1. Change the width of each li to 24%

    2. Our elements are still only lining up three across. This is because our width and margin together equals more than 100% of the container width, causing the last item to bump down a line.

      ( 24% * 4 ) + ( 1.33% * 4 ) = 101.32%

      Because we added a margin to the right of each item, we actually added an unnecessary margin to the right of the last item in each row.

      Removing just this last margin will make our rows fit across the page.

      ( 24% * 4 ) + ( 1.33% * 3 ) = 99.99%
    3. The right margin on the last item in each row needs to be removed. Since our grid will have four items in each row, we can say we need to remove the right margin from every 4th item.

      We can accomplish this using the CSS :nth-child pseudo-selector.

      :nth-child is best understood by example. See this CSS Tricks page:

      1. Useful :nth-child Recipes

      Going back to our grid, the following CSS rule will select every fourth li in our thumbnail grid and set the right margin to 0.

      .thumbnail-grid li:nth-child(4n) {
        margin-right: 0;
      }

      Add the rule above to your code.

    4. Read even more about the nth-child pseudo-selector in How nth-child Works by CSS Tricks.

  8. Flexbox actually allows us to do all of the things in the last step, but with less math!

    1. Comment out the margin-right properties added in the last step. Your thumbnails should revert to having no gutters (space between items).
    2. Change the width of the flex items to 21%.
    3. Using the Developer Tools or Web Inspector, add the justify-content property to the flex container. Experiment with each of the following values to see the effect:

      1. flex-start
      2. flex-end
      3. center
      4. space-between
      5. space-around
    4. Finish by setting the following properties in your CSS to allow for the best visual fit:

      1. width property of your flex items
      2. justify-content property of your flex container

Style the captions

Your starting point should look like step-3.html

While our thumbnails are now lining up nicely, our captions still leave something to be desired.

We want to style the captions and price so that the price is on the right side of the thumbnail. We’ll achieve this by careful use of CSS positioning.

  1. Start by styling the caption text to be .75em. Use the description class for this. Check your HTML to understand why we would use this class.
  2. Next we'll use the CSS position property to adjust where the prices appear.

    1. Using the price class, set the position property to absolute. This will cause our prices to be "absolutely positioned" on the screen.

      .thumbnail-grid .price {
         position: absolute;
      }
    2. Set the top and right properties to 0.

      .thumbnail-grid .price {
         position: absolute;
         right: 0;
         top: 0;
      }
    3. Save your files and refresh your browser.

    That made all of the prices go to the top right of the browser window!

    This is because we positioned them absolutely, relative to the browser window.

    That is the default behavior with absolute positioning.

    In this case, we want to position our prices relative to their container rather than the browser window. Review the HTML to discover what the containing element (or parent) of our prices are. Does that element have a class or id?

  3. The containing element of our prices are the paragraphs with the description class.

    1. Add a background color to the description class to better illustrate what’s happening. Any color is fine.

    2. Our goal is to make the prices fall into the top right corner of the background we just set.

  4. In order to absolutely position the prices relative to their containers we must first create a positioning context. To do this, set the position property on the element's container.

    The container is .description.

    To create a positioning context, change the position property of the container to relative.

    This by itself does not have any visual effect on the page, but when combined with the absolute positioning on the child element, it sets the positioning context.

    1. Add the following rule to your CSS:

      .thumbnail-grid .description {
         position: relative;
      }
    2. Save your files and refresh the browser. You should now see the prices have moved to the top right corner of the description backgrounds.
  5. At smaller browser widths you might have noticed that our prices now overlap our descriptions. Obviously we'll want to avoid this. We can use padding on the description to ensure the description text doesn't reach to the right side.

    1. Add a right padding of 25% to the description class.

    This helps with the layout quite a bit, but pay attention to the Black Porcelain Bowl. This item has a price of "From $24.00". At sizes below 1100px the text still overlaps. We can set the width of our price elements to cause this text to fall into two lines at smaller widths.

    1. Set the width of the price elements to 25%.

    2. Save your files and refresh your browser.

  6. Right align the price text to make it look better when it falls onto two lines.

  7. Remove the background color you added to the description element.

  8. These captions will work well on all but the smallest of screen sizes. For those sizes we would use an @media rule (or media query) to target the smaller sizes and style them differently. For now, we can be content with this.

Create an overlay on hover

Your starting point should look like step-4.html

To make our page a little bit more interesting, we want to add some interaction when we hover over our thumbnails with the mouse.

We're going to create styles that will display a colored overlay with some text when we hover over a thumbnail. Look at final.html for an example.

  1. In order to accomplish this, we need to add some markup that will contain our overlay text.

    We’ll use a span element with a class of overlay for this.

    The text inside the span should say “View”. (You would probably use better text for a real website)

  2. Add the HTML immediately before the first image on the first thumbnail.

    <a href="#" title="View product details">
       <figure>
          <span class="overlay">View</span>
          <img src="images/clock_thumb.jpg" alt="alarm clock" />
          <figcaption>
             <p class="description">Analog Travel Alarm Clock Braun
                <span class="price">$40.00</span>
             </p>
         </figcaption>
       </figure>
    </a>
  3. Create a new selector in your CSS using the overlay class.

  4. Add a rule to create a partially transparent background color. Pick any color you like and make it transparent by using using rgba colors.

  5. We want to style the overlay so that it is exactly the same size as the image and then overlaps it.

    1. In your CSS, set the width and height of the overlay to 100%.

    2. Set the top and left properties on the overlay to 0.

    3. Set the position of the overlay to absolute. What happens? Can you figure out why?

  6. Our overlay covered the entire screen. This again, is relative to the browser window by default.

    We need to create a position context by setting the container of our overlay to use position relative.

    1. Relatively position the containing element of the overlay (That’s the one that surrounds the overlay element).

      What happens?

  7. The overlay should now cover the entire figure element, including the caption.

    For purely aesthetic reasons, we only want the overlay to cover the photo, not the caption.

    To do this, we need to create a new container for the overlay which only contains the element with the photo.

    We’ll use a div since there is no semantic context for the container.

    1. Create a new div element in the first thumbnail li that contains both the overlay and the photo.

      <a href="#" title="View product details">
         <figure>
             <div>
                 <span class="overlay">View</span>
                 <img src="images/clock_thumb.jpg" alt="alarm clock" />
             </div>
      
             <figcaption>
                 <p class="description">Analog Travel Alarm Clock Braun
                     <span class="price">$40.00</span>
                 </p>
             </figcaption>
         </figure>
      </a>
    2. Add a class of thumbnail to the div.

      <a href="#" title="View product details">
         <figure>
             <div class="thumbnail">
                 <span class="overlay">View</span>
                 <img src="images/clock_thumb.jpg" alt="alarm clock" />
             </div>
    3. Relatively position the new container. What happens?

  8. Style the overlay text. You can use some variation of these styles:

    color: white;
    font-weight: bold;
    font-size: 200%;
    padding-top: 40%;
    text-align: center;
  9. You may have noticed there is a tiny gap below the images where the overlay extends past the images.

    This happens because they are inline by default and a small space is reserved below the element.

    We can set our thumbnails to display as block to fix this. Adding a little margin below each image adds needed space between the photos and description text.

    Add the following styles to get rid of the tiny gap below the images:

    .thumbnail-grid img {
        display: block; /* Get rid of tiny space below images */
        margin-bottom: .3em;
    }
    
  10. While our overlay is now covering our photos just like we want, we really only want it to show when we’re hovering over the thumbnail.

    1. Hide the overlay by setting the opacity property to 0.

    2. Use the hover pseudo-class selector on the overlay class to set the opacity of the overlay back to 1 when we hover over it.

      Add the following CSS:

      .overlay:hover {
         opacity: 1;
      }
  11. This effect can be enhanced even more by using CSS transitions to smooth the state change when we hover. This will have the effect of fading in our overlay background.

    To learn more about CSS transitions see:

    To create a simple 1 second long transition of all the properties that change on the overlay, add the following CSS:

    .thumbnail-grid .overlay {
        transition: 1s all;
    }
  12. Experiment with transitioning another property on your overlay.

    1. Try changing the background color on the hover state of the overlay.

    2. Read the CSS Tricks article to learn how to transition multiple states with different timing.

  13. Note: If you're using Chrome, you might have noticed that you overlay text likes to "drop in" when you reload the page. This is due to a weird bug in Chrome that causes transitions to fire when the page loads. See this Stack Overflow page for details if you're curious.

    Adding an empty script element to the top of your HTML page will fix this for this demo.

      <link rel="stylesheet" href="css/reset.css" />
      <link rel="stylesheet" href="css/styles.css" />
      <script> </script>
    </head>

Finished Demo

Your finished thumbnail grid should look like final.html