Making a Better FAQ Page

Design interactive websites to improve user experience by using the popular JavaScript library

(For more resources related to this topic, see here.)

Marking up the FAQ page

We'll get started by taking some extra care and attention with the way we mark up our FAQ list. As with most things that deal with web development, there's no right way of doing anything, so don't assume this approach is the only correct one. Any markup that makes sense semantically and makes it easy to enhance your list with CSS and JavaScript is perfectly acceptable.

Time for action – setting up the HTML file

Perform the following steps to get the HTML file set up for our FAQ page:

  1. We'll get started with our sample HTML file, the jQuery file, the scripts.js file, and the styles.css file. In this case, our HTML page will contain a definition list with the questions inside the <dt> tags and the answers wrapped in the <dd> tags. By default, most browsers will indent the <dd> tags, which means the questions hang into the left margin, making them easy to scan. Inside the <body> tag of your HTML document, add a heading and a definition list as shown in the following code:

    <h1>Frequently Asked Questions</h1> <dl> <dt>What is jQuery?</dt> <dd> <p>jQuery is an awesome JavaScript library</p> </dd> <dt>Why should I use jQuery?</dt> <dd> <p>Because it's awesome and it makes writing JavaScript faster and easier</p> </dd> <dt>Why would I want to hide the answers to my questions?</dt> <dd> <p>To make it easier to peruse the list of available questions - then you simply
    click to see the answer you're interested in reading.</p> </dd> <dt>What if my answers were a lot longer and more complicated than these
    examples?</dt> <dd> <p>The great thing about the &lt;dd&gt; element is that it's a block
    level element that can contain lots of other elements.</p> <p>That means your answer could contain:</p> <ul> <li>Unordered</li> <li>Lists</li> <li>with lots</li> <li>of items</li> <li>(or ordered lists or even another definition list)</li> </ul> <p>Or it might contain text with lots of <strong>special</strong>
    <em>formatting</em>.</p> <h2>Other things</h2> <p>It can even contain headings. Your answers could take up an entire screen or
    more all on their own - it doesn't matter since the answer will be hidden
    until the user wants to see it.</p> </dd> <dt>What if a user doesn't have JavaScript enabled?</dt> <dd> <p>You have two options for users with JavaScript disabled - which you choose
    might depend on the content of your page.</p> <p>You might just leave the page as it is - and make sure the &lt;dt&gt; tags
    are styled in a way that makes them stand out and easy to pick up when you're
    scanning down through the page.
    This would be a great solution if your answers are relatively short.</p> <p>If your FAQ page has long answers, it might be helpful to put a table of
    contents list of links to individual questions at the top of the page so users can
    click it to jump directly to the question and answer they're interested in.
    This is similar to what we did in the tabbed example, but in this case, we'd use
    jQuery to hide the table of contents when the page loaded since users with
    JavaScript wouldn't need to see the table of contents.</p> </dd> </dl>

  2. You can adjust the style of the page however you'd like by adding in some CSS styles. The following screenshot shows how the page is styled:

    For users with JavaScript disabled, this page works fine as is. The questions hang into the left margin and are bolder and larger than the rest of the text on the page, making them easy to scan.

What just happened?

We set up a basic definition list to hold our questions and answers. The default style of the definition list lends itself nicely to making the list of questions scannable for site visitors without JavaScript. We can enhance that further with our own custom CSS code to make the style of our list match our site.

As this simple collapse-and-show (or accordion) action is such a common one, two new elements have been proposed for HTML5: <summary> and <details> that will enable us to build accordions in HTML without the need for JavaScript interactivity. However, at the time of writing this, the new elements are only supported in Webkit browsers, which require some finagling to get them styled with CSS, and are also not accessible. Do keep an eye on these new elements to see if more widespread support for them develops. You can read about the elements in the HTML5 specs (http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html). If you'd like to understand the elements better, the HTML5 Doctor has a great tutorial that explains their use and styling at http://html5doctor.com/the-details-and-summary-elements/.

Time for action – moving around an HTML document

Perform the following steps to move from one element to another in JavaScript:

  1. We're going to keep working with the files we set up in the previously. Open up the scripts.js file that's inside your scripts folder. Add a document ready statement, then write a new empty function called dynamicFAQ, as follows:

    $(document).ready(function(){ }); function dynamicFAQ() { // Our function will go here }

  2. Let's think through how we'd like this page to behave. We'd like to have all the answers to our questions hidden when the page is loaded. Then, when a user finds the question they're looking for, we'd like to show the associated answer when they click on the question.

    This means the first thing we'll need to do is hide all the answers when the page loads. Get started by adding a class jsOff to the <body> tag, as follows:

    <body class="jsOff">

    Now, inside the document ready statement in scripts.js, add the line of code that removes the jsOff class and adds a class selector of jsOn:

    $(document).ready(function(){ $('body').removeClass('jsOff').addClass('jsOn'); });

    Finally, in the styles.css file, add this bit of CSS to hide the answers for the site visitors who have JavaScript enabled:

    .jsOn dd { display: none; }

    Now if you refresh the page in the browser, you'll see that the <dd> elements and the content they contain are no longer visible (see the following screenshot):

  3. Now, we need to show the answer when the site visitor clicks on a question. To do that, we need to tell jQuery to do something whenever someone clicks on one of the questions or the <dt> tags. Inside the dynamicFAQ function, add a line of code to add a click event handler to the <dt> elements, as shown in the following code:

    function dynamicFAQ() { $('dt').on('click', function(){ //Show function will go here }); }

    When the site visitor clicks on a question, we want to get the answer to that question and show it because our FAQ list is set up as follows:

    <dl> <dt>Question 1</dt> <dd>Answer to Question 1</dd> <dt>Question 2</dt> <dd>Answer to Question 2</dd> ... </dl>

    We know that the answer is the next node or element in the DOM after our question. We'll start from the question. When a site visitor clicks on a question, we can get the current question by using jQuery's $(this) selector. The user has just clicked on a question, and we say $(this) to mean the question they just clicked on. Inside the new click function, add $(this) so that we can refer to the clicked question, as follows:

    $('dt').on('click', function(){ $(this); });

  4. Now that we have the question that was just clicked, we need to get the next thing, or the answer to that question so that we can show it. This is called traversing the DOM in JavaScript. It just means that we're moving to a different element in the document.

    jQuery gives us the next method to move to the next node in the DOM. We'll select our answer by inserting the following code:

    $('dt').on('click', function(){ $(this).next(); });

  5. Now, we've moved from the question to the answer. Now all that's left to do is show the answer. To do so, add a line of code as follows:

    $('dt').on('click', function(){ $(this).next().show(); });

  6. If you refresh the page in the browser, you might be disappointed to see that nothing happens when we click the questions. Don't worry—that's easy to fix. We wrote a dynamicFAQ() function, but we didn't call it. Functions don't work until they're called. Inside the document ready statement, call the function as follows:

    $(document).ready(function(){ $('body').removeClass('jsOff').addClass('jsOn'); dynamicFAQ(); });

  7. Now, if we load the page in the browser, you can see that all of our answers are hidden until we click on the question. This is nice and useful, but it would be even nicer if the site visitor could hide the answer again when they're done reading it to get it out of their way. Luckily, this is such a common task, jQuery makes this very easy for us. All we have to do is replace our call to the show method with a call to the toggle method as follows:

    $('dt').on('click', function(){ $(this).next().toggle(); });

    Now when you refresh the page in the browser, you'll see that clicking on the question once shows the answer and clicking on the question a second time hides the answer again.

What just happened?

We learned how to traverse the DOM—how to get from one element to another. Toggling the display of elements on a page is a common JavaScript task, so jQuery already has built-in methods to handle it and make it simple and straightforward to get this up and running on our page. That was pretty easy—just a few lines of code.

Sprucing up our FAQ page

That was so easy, in fact, that we have plenty of time left over to enhance our FAQ page to make it even better. This is where the power of jQuery becomes apparent—you can not only create a show/hide FAQ page, but you can make it a fancy one and still meet your deadline. How's that for impressing a client or your boss?

Time for action – making it fancy

Perform the following steps to add some fancy new features to the FAQ page:

  1. Let's start with a lit le CSS code to change the cursor to a pointer and add a little hover effect to our questions to make it obvious to site visitors that the questions are clickable. Open up the styles.css file that's inside the styles folder and add the following bit of CSS code:

    .jsOn dt { cursor: pointer; } .jsOn dt:hover { color: #ac92ec; }

    We're only applying these styles for those site visitors that have JavaScript enabled. These styles definitely help to communicate to the site visitor that the questions are clickable. You might also choose to change something other than the font color for the hover effect. Feel free to style your FAQ list however you'd like. Have a look at the following screenshot:

  2. Now that we've made it clear that our <dt> elements can be interacted with, let's take a look at how to show the answers in a nicer way. When we click on a question to see the answer, the change isn't communicated to the site visitor very well; the jump in the page is a little disconcerting and it takes a moment to realize what just happened. It would be nicer and easier to understand if the questions were to slide into view. The site visitor could literally see the question appearing and would understand immediately what change just happened on the screen.

    jQuery makes that easy for us. We just have to replace our call to the toggle method with a call to the slideToggle method:

    $('dt').on('click', function(){ $(this).next().slideToggle(); });

    Now if you view the page in your browser, you can see that the questions slide smoothly in and out of view when the question is clicked. It's easy to understand what's happening when the page changes, and the animation is a nice touch.

  3. Now, there's just one lit le detail we've still got to take care of. Depending on how you've styled your FAQ list, you might see a lit le jump in the answer at the end of the animation. This is caused by some extra margins around the <p> tags inside the <dd> element. They don't normally cause any issues in HTML, and browsers can figure how to display them correctly. However, when we start working with animation, sometimes this becomes a problem. It's easy to fix. Just remove the top margin from the <p> tags inside the FAQ list as follows:

    .content dd p { margin-top: 0; }

    If you refresh the page in the browser, you'll see that the little jump is now gone and our animation smoothly shows and hides the answers to our questions.

What just happened?

We replaced our toggle method with the slideToggle method to animate the showing and hiding of the answers. This makes it easier for the site visitor to understand the change that's taking place on the page. We also added some CSS to make the questions appear to be clickable to communicate the abilities of our page to our site visitors.

We're almost there!

jQuery made animating that show and hide so easy that we've still got time left over to enhance our FAQ page even more. It would be nice to add some sort of indicator to our questions to show that they're collapsed and can be expanded, and to add some sort of special style to our questions once they're opened to show that they can be collapsed again.

Time for action – adding some final touches

Perform the following steps to add some finishing touches to our FAQ list:

  1. Let's start with some simple CSS code to add a small arrow icon to the left side of our questions. Head back into style.css and modify the styles a bit to add an arrow as follows:

    .jsOn dt:before { border: 0.5em solid; border-color: transparent transparent transparent #f2eeef; content: ''; display: inline-block; height: 0; margin-right: 0.5em; vertical-align: middle; width: 0; } .jsOn dt:hover:before { border-left-color: #ac92ec; }

    You might be wondering about this sort of odd bit of CSS. This is a technique to create triangles in pure CSS without having to use any images. If you're not familiar with this technique, I recommend checking out appendTo's blog post that explains pure CSS triangles at http://appendto.com/2013/03/pure-css-triangles-explained/.

    We've also included a hover style so that the triangle will match the text color when the site visitor hovers his/her mouse over the question. Note that we're using the jsOn class so that arrows don't get added to the page unless the site visitors have JavaScript enabled. See the triangles created in the following screenshot:

  2. Next, we'll change the arrow to a different orientation when the question is opened. We'll create a new CSS class open and use it to de fine some new styles for our CSS arrow using the following code:

    .jsOn dt.open:before { border-color: #f2eeef transparent transparent transparent; border-bottom-width: 0; } .jsOn dt.open:hover:before { border-left-color: transparent; border-top-color: #ac92ec; }

    Just make sure you add these new classes after the other CSS we're using to style our <dt> tags. This will ensure that the CSS cascades the way we intended.

  3. So we have our CSS code to change the arrows and show our questions are open, but how do we actually use that new class? We'll use jQuery to add the class to our question when it is opened and to remove the class when it's closed.

    jQuery provides some nice methods to work with CSS classes.

    The addClass method will add a class to a jQuery object and the removeClass method will remove a class. However, we want to toggle our class just like we're toggling the show and hide phenomenon of our questions. jQuery's got us covered for that too. We want the class to change when we click on the question, so we'll add a line of code inside our dynamicFAQ function that we're calling each time a <dt> tag is clicked as follows:

    $('dt').on('click', function(){ $(this).toggleClass('open'); $(this).next().slideToggle(); });

    Now when you view the page, you'll see your open styles being applied to the <dt> tags when they're open and removed again when they're closed. To see this, have a look at the following screenshot:

  4. However, we can actually crunch our code to be a little bit smaller. Remember how we chain methods in jQuery? We can take advantage of chaining again. We have a bit of redundancy in our code because we're starting two different lines with $(this). We can remove this extra $(this) and just add our toggleClass method to the chain we've already started as follows:

    $(this).toggleClass('open').next().slideToggle();

    This helps keep our code short and concise, and just look at what we're accomplishing in one line of code!

What just happened?

We created the CSS styles to style the open and closed states of our questions, and then we added a bit of code to our JavaScript to change the CSS class of the question to use our new styles. jQuery provides a few different methods to update CSS classes, which is o t en a quick and easy way to update the display of our document in response to input from the site visitor. In this case, since we wanted to add and remove a class, we used the toggleClass method. It saved us from having to figure out on our own whether we needed to add or remove the open class.

We also took advantage of chaining to simply add this new functionality to our existing line of code, making the animated show and hide phenomenon of the answer and the change of CSS class of our question happen all in just one line of code. How's that for impressive power in a small amount of code?

Summary

You learned how to set up a basic FAQ page that hides the answers to the questions until the site visitor needs to see them. Because jQuery made this so simple, we had plenty of time left over to enhance our FAQ page even more, adding animations to our show and hide phenomenon for the answers, and taking advantage of CSS to style our questions with special open and closed classes to communicate to our site visitors how our page works. And we did all of that with just a few lines of code!

Resources for Article:


Further resources on this subject:


Books to Consider

comments powered by Disqus
X

An Introduction to 3D Printing

Explore the future of manufacturing and design  - read our guide to 3d printing for free