Coding a Toggle-Based FAQ Page with CSS3 and jQuery

by Jake Rocheleau

on April 23, 2014

in Tutorials

Get the FlatPix UI Kit for only $7 - Learn More or Buy Now

Company websites often have Frequently Asked Questions for people who don’t know much about the corporation or their services. Larger pages with Q&A listed together will often have a table of contents at the top. I don’t like this method because the pages end up long and sometimes confusing to navigate.

This tutorial is based around a similar idea, but using toggle effects for each question. As the user clicks on a question the answer will slide down and toggle into view. Users can also click already-opened questions which toggles them closed again. This technique is perfect for saving room on the page while cramming together an assortment of helpful information.

css3 jquery faq toggle tutorial preview screen

Getting Started

To create the page I’m setting an HTML5 doctype along with an external CSS stylesheet. Also I’ve linked to an external copy of jQuery for the scripting. Inside the page body itself I’ve created a small heading section centered within a wrapper.

You’ll notice that each of the question/answer boxes are split into two columns. When we have them floating next to each other the expandable height values tend to push questions onto new rows. This looks awful and the quickest solution is to break them up into left and right columns.

<div id="questions" class="clearfix">
  <div class="qaleft">
    <div class="toggle">
      <h3>Is this a typical question from customers?</h3>
      <div class="toggle-info">
        <p>Yes! No strings attached.</p>
      </div>
    </div>
  </div> <!-- @end .qaleft -->

  <div class="qaright">
    <div class="toggle">
      <h3>Lorem ipsum dolor sit amet?</h3>
      <div class="toggle-info">
        <p>Cras id ullamcorper nunc. Morbi tempor risus venenatis risus pretium, ac mattis metus aliquet. Donec vestibulum congue ligula, eu malesuada nisi ultricies eget.</p>
        
        <p>Morbi at suscipit neque, porttitor feugiat mauris. Etiam auctor libero dolor, nec consequat felis convallis in.</p>
      </div>
    </div>

This code doesn’t include every question box, it simply demonstrates how to setup each of the columns. Everything in the left side will appear in a vertical row so it’s best to stagger questions from left to right making horizontal rows. Also you might consider breaking up questions into larger sections with sub-headings, divided by a horizontal rule or anther similar element.

Each of the containers .qaleft and .qaright are floated using a fixed width. The container uses a 100% width spanning the entirety of the page. So each internal .toggle element has the same formatted code. First we see an H3 which appears to the user as a clickable link.

Then as a sibling element I’ve created another div with the class .toggle-info. This allows us to branch out beyond simple paragraphs to answer a question. You might embed a video, image thumbnail, external links, or anything else convenient to visitors.

Page Styles

Most of my CSS resets are based on the source by Eric Meyer with a number of customizations. For this tutorial I’m using the Google Webfont Hammersmith One along with a custom tiled background.

/** page structure **/
#w {
  display: block;
  width: 800px;
  margin: 0 auto;
  padding: 15px;
  background: #fff;
  -webkit-border-radius: 4px;
  -moz-border-radius: 4px;
  border-radius: 4px;
  -webkit-box-shadow: 1px 3px 2px rgba(0,0,0,0.3);
  -moz-box-shadow: 1px 3px 2px rgba(0,0,0,0.3);
  box-shadow: 1px 2px 3px rgba(0,0,0,0.3);
}

#title { text-align: center; }

#headline {
  display: block;
  position: relative;
  width: 100%;
  height: 220px;
  background: url('../img/featured-headline-bg.jpg') no-repeat;
  background-size: 100%;
}

#headline h2 {
  display: block;
  position: absolute;
  right: 50%;
  bottom: 0;
  padding: 10px 5px;
  margin-bottom: 10px;
  font-size: 2.2em;
  font-weight: bold;
  color: #616161;
  background: rgba(255,255,255,0.6);
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
}

#questions {
  display: block;
  width: 100%;
}

I’ve created a centered page container with the #w wrapper ID. Also the larger headline container uses a background image fitted with background-size: 100%. The internal H2 element is fitted perfectly into the container with a white background using adjusted opacity. Large background headers are great for companies to showcase their office photo(s) so that visitors can build a deeper connection online.

/** toggle boxes **/
.qaleft {
  display: block;
  float: left;
  width: 370px;
}

.qaright {
  display: block;
  float: right;
  width: 370px;
}

.toggle {
  display: block;
  width: 100%;
  height: auto;
  margin-right: 10px;
  margin-bottom: 15px;
  -webkit-transition: all .15s ease-out;
  -moz-transition: all .15s ease-out;
  -o-transition: all .15s ease-out;
  transition: all .15s ease-out;
}

.toggle h3 {
  color: #576c7d;
  background: #e5eaee;
  display: block;
  font-size: 1.4em;
  line-height: 22px;
  text-align: center;
  padding: 10px 0;
  position: relative;
  cursor: pointer;
  font-weight: bold;
  text-shadow: 1px 1px 0 #fff;
  -moz-border-radius: 6px;
  -webkit-border-radius: 6px;
  border-radius: 6px;
  -webkit-transition: all .15s ease-out;
  -moz-transition: all .15s ease-out;
  -o-transition: all .15s ease-out;
  transition: all .15s ease-out;
}

All of the toggle containers should be self-explanatory. The H3 element for each toggle is made to appear like a hyperlink without a needless HREF. Using a bit of CSS I’ve forced the cursor to always appear as the hand pointer, and I’ve attached CSS3 transitions onto each toggle header.

.toggle p:last-of-type {
  margin-bottom: 0;
}

.toggle h3:hover, .toggle.open h3 { 
  background: #d2dbe2;
}

.toggle.open h3 {
  color: #46525c;
}

.toggle .toggle-info {
  display: none;
  padding: 7px 11px;
}

The rest is very simple but adds some extra value to the page. Since each toggle box uses a margin at the bottom, it’s unnecessary for the last paragraph to push down an extra 15px margin. This can be fixed using the :last-of-type pseudo selector on every internal paragraph. The last paragraph in the toggle container has no margin so each box is spaced properly.

Also whenever a user clicks to display an answer, the toggle box gets an extra class of .open. The heading background is darkened along with the text color. It’s just a minor effect but when quickly skimming over the page you tend to notice which questions are opened vs. which are not.

Toggling with jQuery

If you’re new to JavaScript or jQuery development this should be new and unique stuff. Any intermediate-to-advanced developer is likely familiar with toggling animation. But it doesn’t hurt to go over the process again in the context of this article.

$(function(){
  $('.toggle h3').on('click', function(e){
    var answer = $(this).next('.toggle-info');
    
    if(!$(answer).is(":visible")) {
      $(this).parent().addClass('open');
    } else {
      $(this).parent().removeClass('open');
    }
    $(answer).slideToggle(300);
  });
});

The jQuery selector is targeting every H3 element contained inside a .toggle div. Whenever one of these headings gets clicked we call a new function. The internal variable answer will change based on which question was clicked. We can use next() to pinpoint the sibling element with a class of .toggle-info.

A brief if/else logic block is used to determine the .open class. If the related .toggle-info div is not visible then we know the user clicked to display it. So for this case we need to add the class .open onto the toggle container using addClass(). Otherwise the class is removed and the heading goes back to its default state.

Finally at the end of this function I’m using the jQuery method .slideToggle() to display the answer. The 300 parameter sets the number of milliseconds for the animation to take place. This is known as duration and may be adjusted to whatever you need. There is an optional secondary parameter named complete which can be used for a callback function once the animation is complete. It doesn’t provide much use for this tutorial but you can see how this works in the code sample below:

$(answer).slideToggle(300, function() {
  // callback function code
});

css3 jquery faq toggle tutorial preview screen

Closing

This is a really simple yet optimal effect for any large-scale website. Q&A sections can be used with startups, ecommerce shops, media companies, anything that might be somewhat ambiguous to the general public. Since most visitors understand toggle-based interfaces this design style is perfect for any modern layout. Feel free to download a copy of my source code and try building this into your own website.

Powered by Shutterstock

About Jake Rocheleau

Jake is a digital researcher and writer on many popular design magazines. He frequently writes on topics including web design, user experience, mobile apps, and project management. You can find him all throughout Google and tweeting @jakerocheleau. Connect with Jake on google+