Mastering card design with Bootstrap 4

Mastering card design with Bootstrap 4

Table of Contents

Today’s post is about using the latest version of Bootstrap framework, made by team working for Twitter in the past, to create a simple layout card design. By the latest version I don’t mean version v3.3.5, but version 4 that is right know in alpha phase and under testing. Since Bootstrap 4 contains card component in its default package, most of styling will be done purely by Bootstrap with only couple enhancements from our side.

Necessary Assets for Card Design

The first thing you have to do is to get all the assets you will need to make the code for card design layout work. These assets will be focused only on CSS. All animations featured in the demo are done through CSS animations provided by animate.css created by Daniel Eden. There will be no JavaScript or jQuery libraries. Next, you will need a default CSS stylesheet from Bootstrap 4 framework. You can either download all the necessary files to your computer or use some of the available CDNs’.

You can see demo on Codepen and download the code from GitHub repository.

Creating the Structure

The first step is to create an HTML structure for our card design layout. In order to provide you with more examples I will create two rows with three cards in each of them. First row will feature “classic” cards with image title, sub-title, text and button or link. Second row will feature smaller cards where you will use overlay to show the text on the top of image.

The HTML will start with div with class of “container” in which we will nest the rows with cards. If you have never worked with Bootstrap 4 before or you are not familiar with its syntax, the “m-t-md” class I used on container div is a helper class adding top (-t-) margin (m-) to the element. The -md suffix stands for the amount of margin–1.5rem in this case. I used this class just to add some space between the top of the page and the cards. You don’t have to do include it if you don’t want.

In the “container” div are nested another two div elements with class “row”. Inside each rows will be three div boxes with classes “col-xs-12” and “col-md-4”. These classes are related to Bootstrap 4 grid system. To get better understanding of how Bootstrap’s grid system works take a look at one of the previous tutorials focused on this topic. Each of these boxes contains six article elements with class “card”.

Note: As you can see in the code below and in card design layout demo, I also used another classes such as “animate”, “fadeInLeft”, “fadeInUp”, “fadeInRight” and “fadeInDown”. These classes are from animate.css mentioned in assets part. If you don’t want to add any animations, just leave these classes out. If you want to know more available effects take a look at animate.css website.

Card Examples the First Row

The first thing in every “card” will be img element to hold the featured image you want to show on the card. This tag will have class ”card-img-top” and “img-responsive”. The first class is for the framework to recognize the image as a part of the card and, thanks to -top suffix, place it in the upper part of the card. The second class is just a helper used to resize the image to fit the card without overlapping it. Images I used in this tutorial are from stocksnap.io. All of them are free and you can use them as you wish. Don’t forget to include some alt text for better accessibility.

Subsequent to img elements will be a div with class of “card-block”. This block is used as a container for content of the card. In our case it will contain h4 for card title with the same class (“card-title”) and h6 for sub-title. I also added a class of “text-muted” to distinguish card sub-title from title a bit more.

The last thing included in the “card-block” div will be a paragraph with class “card-text”. Unlike the rest of cards, the first one will also have an anchor tag with class “btn” and “btn-primary” included in “card-block”.

Example of the first card:

<!-- Card -->
<article class="card animated fadeInLeft">
  <img class="card-img-top img-responsive" src="https://snap-photos.s3.amazonaws.com/img-thumbs/960w/1U2EGZ07GU.jpg" alt="Deer in nature" />

  <div class="card-block">
    <h4 class="card-title">Animal Farm</h4>

    <h6 class="text-muted">George Orwell</h6>

    <p class="card-text">Tired of their servitude to man, a group of farm animals revolt and establish their own society, only to be betrayed into worse servitude by their leaders, the pigs. This satire addresses the communist philosophy the Soviet Union.</p>

    <a href="#" class="btn btn-primary">Read more</a>
  </div>
</article><!-- .end Card ->

The second card will have similar structure except that the image will be placed under the title and sub-title. We will also remove the “card-img-top” class leaving only “img-responsive” for sizzing there or no class at all. In case of second card, I used two buttons and put them into another “card-block” div with helper class of “text-center”. The purpose is to center the button group. The button group divs also have role and aria-label tags for screen readers.

Note: you can also see that I actually used the button group twice. This is done due to better responsiveness of the button group. Under certain screen resolution, the button group will be broken to two lines. It looks pretty bad. So, to prevent that I created another button group with class “btn-group-vertical” that will show buttons stacked vertically. With use of responsive classes provided by Bootstrap, we will switch between them and show only one group at the time.

Example of the second card:

<!-- Card -->
<article class="card animated fadeInUp">
  <div class="card-block">
    <h4 class="card-title">Life After Life</h4>

    <h6 class="text-muted">Kate Atkinson</h6>
  </div>

  <img class="img-responsive" src="https://snap-photos.s3.amazonaws.com/img-thumbs/960w/SYC0YBA37V.jpg" alt="Leaf on the street" />

  <div class="card-block">
    <p class="card-text">On a cold and snowy night, Ursula Todd is born, the 3rd child of a wealthy banker and his wife. She dies before she can draw her first breath. On that same cold and snowy night, lets out a lusty wail.</p>
  </div>

  <div class="card-block text-center">
    <div class="btn-group hidden-sm-down hidden-md-down" role="group" aria-label="Card buttons">
      <a href="#" class="btn btn-primary">Read more</a>

      <a href="#" class="btn btn-primary">Save for later</a>
    </div>

    <div class="btn-group-vertical hidden-lg-up" role="group" aria-label="Card buttons">
      <a href="#" class="btn btn-primary">Read more</a>

      <a href="#" class="btn btn-primary">Save for later</a>
    </div>
  </div>
</article><!-- .end Card ->

The third card will feature two links instead of buttons and thumbnail will be placed in the bottom. I also used the same strategy for links as for buttons in the card number two. To place the image in the bottom of the card we will use class “card-img-bottom”. For the links, we will replace the anchor tags with class “btn” and “btn-primary” we used previously with anchor tags with one class “card-link”. That is all for this card and also the first row.

Example of the third card:

<!-- Card -->
<article class="card animated fadeInRight">
  <div class="card-block">
    <h4 class="card-title">Wind, Sand and Stars</h4>

    <h6 class="text-muted">Antoine de Saint-Exupéry</h6>

    <p class="card-text">Story that captures the grandeur, danger, and isolation of flight. Its exciting account of air adventure, combined with lyrical prose and the spirit of a philosopher, makes it one of the most popular works ever written.</p>
  </div>

  <div class="card-block text-center">
    <div class="btn-group hidden-sm-down hidden-md-down" role="group" aria-label="Card buttons">
      <a href="#" class="card-link">Read more</a>

      <a href="#" class="card-link">Save for later</a>
    </div>

    <div class="btn-group-vertical hidden-lg-up" role="group" aria-label="Card buttons">
      <a href="#" class="card-link">Read more</a>

      <br />

      <a href="#" class="card-link">Save for later</a>
    </div>
  </div>

  <img class="card-img-bottom img-responsive" src="https://snap-photos.s3.amazonaws.com/img-thumbs/960w/8SALDQRRZX.jpg" alt="White sand" />
</article><!-- .end Card ->

Card Examples of the Second Row

Since the cards in row number two are all the same (sorry) differing only in the thumbnail images, I’m going to show you the structure of the first one. Again, we will start with article element as a container to hold the content of cards. This element will also have class “card”, but this time we will add one more–“card-inverse”. This new class will make the text stand out more in darker background (overlay) by making it brighter.

First element nested in the article will be again img tag only with class “img-responsive” for better sizing. Following the image will be a div element with class “card-img-overlay”. This div will contain all the content you want to feature on the card. In our case, it will be h4 with class “card-title” for card title, h6 with class “text-muted” for sub-title and paragraph with class “card-text” for some short excerpt or description. You can also include a button or link if you want.

Example of the first card, second row:

<!-- Card -->
<article class="card card-inverse animated fadeInLeft">
  <img class="img-responsive" src="https://snap-photos.s3.amazonaws.com/img-thumbs/960w/1U2EGZ07GU.jpg" alt="Deer in nature" />

  <div class="card-img-overlay">
    <h4 class="card-title">Animal Farm</h4>

    <h6 class="text-muted">George Orwell</h6>

    <p class="card-text">Tired of their servitude to man, a group of farm animals revolt and establish their own society...</p>
  </div>
</article><!-- .end Card -->

When you put the pieces above together, the whole HTML code is following:

<div class="container m-t-md">
  <!-- First row -->
  <div class="row">
    <div class="col-xs-12 col-md-4">
      <!-- Card -->
      <article class="card animated fadeInLeft">
        <img class="card-img-top img-responsive" src="https://snap-photos.s3.amazonaws.com/img-thumbs/960w/1U2EGZ07GU.jpg" alt="Deer in nature" />

        <div class="card-block">
          <h4 class="card-title">Animal Farm</h4>

          <h6 class="text-muted">George Orwell</h6>

          <p class="card-text">Tired of their servitude to man, a group of farm animals revolt and establish their own society, only to be betrayed into worse servitude by their leaders, the pigs. This satire addresses the communist philosophy the Soviet Union.</p>

          <a href="#" class="btn btn-primary">Read more</a>
        </div>
      </article><!-- .end Card -->
    </div>

    <div class="col-xs-12 col-md-4">
      <!-- Card -->
      <article class="card animated fadeInUp">
        <div class="card-block">
          <h4 class="card-title">Life After Life</h4>

          <h6 class="text-muted">Kate Atkinson</h6>
        </div>

        <img class="img-responsive" src="https://snap-photos.s3.amazonaws.com/img-thumbs/960w/SYC0YBA37V.jpg" alt="Leaf on the street" />

        <div class="card-block">
          <p class="card-text">On a cold and snowy night, Ursula Todd is born, the 3rd child of a wealthy banker and his wife. She dies before she can draw her first breath. On that same cold and snowy night, lets out a lusty wail.</p>
        </div>

        <div class="card-block text-center">
          <div class="btn-group hidden-sm-down hidden-md-down" role="group" aria-label="Card buttons">
            <a href="#" class="btn btn-primary">Read more</a>

            <a href="#" class="btn btn-primary">Save for later</a>
          </div>

          <div class="btn-group-vertical hidden-lg-up" role="group" aria-label="Card buttons">
            <a href="#" class="btn btn-primary">Read more</a>

            <a href="#" class="btn btn-primary">Save for later</a>
          </div>
        </div>
      </article><!-- .end Card -->
    </div>

    <div class="col-xs-12 col-md-4">
      <!-- Card -->
      <article class="card animated fadeInRight">
        <div class="card-block">
          <h4 class="card-title">Wind, Sand and Stars</h4>

          <h6 class="text-muted">Antoine de Saint-Exupéry</h6>

          <p class="card-text">Story that captures the grandeur, danger, and isolation of flight. Its exciting account of air adventure, combined with lyrical prose and the spirit of a philosopher, makes it one of the most popular works ever written.</p>
        </div>

        <div class="card-block text-center">
          <div class="btn-group hidden-sm-down hidden-md-down" role="group" aria-label="Card buttons">
            <a href="#" class="card-link">Read more</a>

            <a href="#" class="card-link">Save for later</a>
          </div>

          <div class="btn-group-vertical hidden-lg-up" role="group" aria-label="Card buttons">
            <a href="#" class="card-link">Read more</a>

            <br />

            <a href="#" class="card-link">Save for later</a>
          </div>
        </div>

        <img class="card-img-bottom img-responsive" src="https://snap-photos.s3.amazonaws.com/img-thumbs/960w/8SALDQRRZX.jpg" alt="White sand" />
      </article><!-- .end Card -->
    </div>
  </div><!-- .end First row -->

  <!-- Second row -->
  <div class="row m-t-md">
    <div class="col-xs-12 col-md-4">
      <!-- Card -->
      <article class="card card-inverse animated fadeInLeft">
        <img class="img-responsive" src="https://snap-photos.s3.amazonaws.com/img-thumbs/960w/1U2EGZ07GU.jpg" alt="Deer in nature" />

        <div class="card-img-overlay">
          <h4 class="card-title">Animal Farm</h4>

          <h6 class="text-muted">George Orwell</h6>

          <p class="card-text">Tired of their servitude to man, a group of farm animals revolt and establish their own society...</p>
        </div>
      </article><!-- .end Card -->
    </div>

    <div class="col-xs-12 col-md-4">
      <!-- Card -->
      <article class="card card-inverse animated fadeInDown">
        <img class="img-responsive" src="https://snap-photos.s3.amazonaws.com/img-thumbs/960w/SYC0YBA37V.jpg" alt="Leaf on the street" />

        <div class="card-img-overlay">
          <h4 class="card-title">Life After Life</h4>

          <h6 class="text-muted">Kate Atkinson</h6>

          <p class="card-text">On a cold and snowy night, Ursula Todd is born, the 3rd child of a wealthy banker and his wife. She die...</p>
        </div>
      </article><!-- .end Card -->
    </div>

    <div class="col-xs-12 col-md-4">
      <!-- Card -->
      <article class="card card-inverse animated fadeInRight">
        <img class="img-responsive" src="https://snap-photos.s3.amazonaws.com/img-thumbs/960w/8SALDQRRZX.jpg" alt="White sand" />

        <div class="card-img-overlay">
          <h4 class="card-title">Wind, Sand and Stars</h4>

          <h6 class="text-muted">Antoine de Saint-Exupéry</h6>

          <p class="card-text">Story that captures the grandeur, danger, and isolation of flight. Its exciting account of air adventure...</p>
        </div>
      </article><!-- .end Card -->
    </div>
  </div><!-- .end Second row -->
</div>

Adding Style

Thanks to folks standing behind Bootstrap framework there is not so much additional work necessary to finish our card design. The only custom styles I had to create were for image overlays. Since the images I used for thumbnails are very bright, the text was hard to read. To fix this issue, I used background-color set to “rgba(#333, .85)” in Sass or “rgba(51, 51, 51, 0.85)” in plain CSS. This made layer on top of the images dark enough and the text readable.

There was also a little issue with bottom borders appearing on cards in the second row. The image borders were not rounded as the card and so I used overflow set to “hidden” to fix that. The rest of styles, such as box-shadow for cards and transition for anchor tags, are just to make the experience nicer and smoother.

Note: as you can see in Sass version of the code, I didn’t use any vendor prefixes. However, they are included in CSS. The reason is that I used autoprefixer plugin to take care about this.

Sass version:

// Box shadow helper
@mixin BoxShadowHelper($level: 1){
  @if $level == 1 {
    box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .16), 0 2px 10px 0 rgba(0, 0, 0, .12);
  }
  @if $level == 2 {
    box-shadow: 0 5px 11px 0 rgba(0, 0, 0, .18), 0 4px 15px 0 rgba(0, 0, 0, .15);
  }
}

a {
  transition: .25s all;
}

.card {
  @include BoxShadowHelper(1);
  
  overflow: hidden;
  transition: .25s box-shadow;
  
  &:focus,
  &:hover {
    @include BoxShadowHelper(2);
  }
}

.card-inverse .card-img-overlay {
  background-color: rgba(#333,.85);
  border-color: rgba(#333,.85);
}

CSS version:

a {
  -webkit-transition: .25s all;
  transition: .25s all;
}

.card {
  overflow: hidden;
  box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
  -webkit-transition: .25s box-shadow;
  transition: .25s box-shadow;
}

.card:focus,
.card:hover {
  box-shadow: 0 5px 11px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15);
}

.card-inverse .card-img-overlay {
  background-color: rgba(51, 51, 51, 0.85);
  border-color: rgba(51, 51, 51, 0.85);
}

Browser Support

The majority of modern browsers will render this layout based on card design without problems. However, since Bootstrap, with version 4, dropped IE8 and iOS 6 support there might be some issues with basic styling. Bootstrap 4 is fully compatible with IE9+ and iOS 7+. If you need to provide support for older browsers, you might have to either customize the code or use Bootstrap 3 as default and build this card design layout on it instead of 4.

Closing thoughts on mastering card design with Bootstrap 4

Who said that card design has to be hard? With use of available frameworks such as Bootstrap and few (dozens 🙂 ) line of code, you can create simple layout featuring card design for your website. I hope that this tutorial will come in handy and save you from unnecessary headaches. Let me know how you used this example of card design or how you improved it. Now it’s your turn. So go and create something great!

If you liked this article, please subscribe so you don't miss any future post.

If you'd like to support me and this blog, you can become a patron, or you can buy me a coffee 🙂

By Alex Devero

I'm Founder/CEO of DEVERO Corporation. Entrepreneur, designer, developer. My mission and MTP is to accelerate the development of humankind through technology.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.