Reply to comment

jQuery FAQs: Scroll To and Highlight Tutorial

Yesterday I set out with the goal of creating some Frequently Asked Questions (FAQs), with the idea of using jQuery to provide some added functionality. That's when I stumbled across the Bit Repository. They provided a very nice way of accomplishing what I wanted, so I decided to follow their tutorial.

It gave me great inspiration and while implementing the idea, I decided to go ahead and improve upon what they had done. My solution had to be developed so it could easily be reused without having to touch any of the script's again. The following steps outline the approach I took and the accompanying results. Enjoy!

download source filesview demo

Step 1: Download the following jQuery and jQuery UI libraries. And while you're at it, pick up the jQuery scrollTo plug-in.

Step 2: Now that we have downloaded the necessary scripts, we have to structure our frequently asked questions. Using an unordered list, we'll add an ID to each list item (question) that corresponds to that questions number and wrap that question with an anchor tag.

<ul id="questions">
    <li id="q1"><a href="#a1">Question 1?</a></li>
    <li id="q2"><a href="#a2">Question 2?</li>
    <li id="q3"><a href="#a3">Question 3?</li>
    <li id="q4"><a href="#a4">Question 4?</a></li>
    <li id="q5"><a href="#a4">Question 5?</a></li>
</ul>

Now the only real surprise here might be the anchor tag linking to "#a1" or "#a2", etc. These href's will correspond with our answer's ID's. That way if for some reason JavaScript isn't enabled, the FAQ will still work and take your visitor to the appropriate answer. This is one aspect that wasn't accounted for in Bit Repository's tutorial that I needed to have.

Step 3: Followed by our question HTML will be the HTML for our answers. Each answer will be encompassed in a div that has an id which corresponds to it's above questions href. (i.e. <a href="#a1"> links to <div id="a1">)

<div id="a1">
    <h2>Question 1?</h2>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent ornare feugiat diam sit amet semper. </p>
</div>
 
<div id="a2">
    <h2>Question 2?</h2>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In interdum enim sem, in lacinia turpis. Ut dignissim posuere lectus et fermentum.</p>
</div>
 
<div id="a3">
    <h2>Question 3?</h2>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce porta, nunc a adipiscing scelerisque, leo ante iaculis nisl, eget molestie mi ipsum eget justo.</p>
</div>
 
<div id="a4">
    <h2>Question 4?</h2>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi vitae elit eros, a luctus nisl. </p>
</div>
 
<div id="a5">
    <h2>Question 5?</h2>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras nec magna tellus, nec tempor metus. </p>
</div>

Step 4: With our questions and answers structured, we need to begin adding functionality to them. For starters we'll need to reference our scripts, that we downloaded earlier, within the <head> section of our page.

<script src="/your-path/jquery.js"></script>
<script src="/your-path/jquery-ui.js"></script>
<script src="/your-path/jquery-scrollTo.js"></script>

NOTE: You do not have to host the jQuery or jQuery scripts on your server. Check out the Google AJAX Libraries for more info.

Step 5: Next we need to setup our script that will make all of this work. We'll start with some jQuery that will be used to let us know when the DOM is ready. This too, should go within your <head> section as well, if possible (after the above script declarations), or better yet, in a separate .js file altogether:

<script type="text/javascript">
$(function() {
    // code here
});
</script>

This syntax is shorthand for doing it the old $(document).ready(function(){ // code here }); way.

NOTE: If you use multiple libraries (Prototype, MooTools, etc.) it is usually a good idea to make sure jQuery will not interfere with them. If this is the case, consider using the following script instead of what was just provided. This will allow you to use the rest of the code snippets below, as-is, without issue.

<script type="text/javascript">
jQuery.noConflict();
 
jQuery(function($) {
    // code here
});
</script>

Step 6: The DOM is ready and now it's time to make the magic happen. We'll start by adding a click event to all of our questions.

<script type="text/javascript">
$(function() {
    // step 6
    $("#questions > li").click(function() {
        // click events
    });
});
</script>

Step 7: This step is an important one. I want to create a single function() that will serve ALL questions, instead of creating a function for each question, like in the Bit Repository tutorial.

<script type="text/javascript">
$(function() {
    $("#questions > li").click(function() {
        // step 7
        var qu = $(this).attr("id");
        var an = "#" + qu.replace("q","a");
    });
});
</script>

The variable "qu" gets the ID of the question that was clicked. For example, if I click on question 2, "qu" would equal "q2". With that ID, we can create another variable, "an", that will match our answer's id b/c we have replaced the "q" with an "a".

Step 8: Setting up our scrollTo() method is quite easy at this point. All we have to do is apply the method to our answer ID which is what the "an" variable is.

<script type="text/javascript">
$(function() {
    $("#questions > li").click(function() {
        var qu = $(this).attr("id");
        var an = "#" + qu.replace("q","a");
 
        // step 8
        $.scrollTo(an, {duration: 800, axis:"y"});
    });
});
</script>

The first thing we specified in the $.scrollTo(...) method is the answer ID we want the our clicked question to scroll to. Really that's all you need. However, I decided to set an allotted duration for how long I want the slide to take. I also specified that I wanted it to slide down via the y-axis. There are several more options you can specify here, simply refer to the scrollTo documenation.

Step 9: At this point we have a working prototype. However, the effect isn't complete. As the page scrolls from the question to the answer, it's quite likely your user gets lost along the way. To combat this, we need to add a highlight effect. This portion also differs than Bit Repository's in the sense that I didn't use a third-party plug-in for my highlighting. Instead, I just used the built-in one that comes bundled within jQuery UI. To add it, we need to add the "onAfter:" option to our $.scrollTo(...) declaration. The attached function will now execute AFTER the scroll.

<script type="text/javascript">
$(function() {
    $("#questions > li").click(function() {
        var qu = $(this).attr("id");
        var an = "#" + qu.replace("q","a");
 
        $.scrollTo(an, {duration: 800, axis:"y", onAfter:function(){
             // step 9
            $(an).effect("highlight", {color: "#99c0e1"}, 2000); }
        });
    });
});
</script>

The .effect("highlight", {...}) method accepts a color argument which can be any hex color you'd like. The integer 2000 determines how long it will take the highlighted region to completely fade.

Step 10: At this point, you might think our work is done. However, if you have a cumbersome and detailed FAQ, it could be quite lengthy. We need to add a button for returning to the top. This requires a few changes to our answers HTML and an additional function within our script.

First, we'll add an image within our <h2> tag and give it a class of "return-top". Below I show how this is done for answer 1, but it should be done for ALL answers.

UPDATE: Thanks to Justin for pointing this out in the comments section. To make this unobtrusive the <img> should be wrapped with an anchor tag.

<div id="a1">
    <h2><a href="#top" class="return-top" onclick="return false;"><img  src="/path/faq-return-to-top.gif" alt="return to top" class="return-top" /></a>Question 1?</h2>
    ...
</div>

NOTE: You can use text for this if you'd like. Just simply throw a <span> tag around it with a class of "return-top".

Step 11: Next we'll add the return to top functionality to our script. This requires adding a click event to "return-top" and giving it the ability to scroll back to the top.

<script type="text/javascript">
$(function() {
    $("#questions > li").click(function() {
        var qu = $(this).attr("id");
        var an = "#" + qu.replace("q","a");
 
        $.scrollTo(an, {duration: 800, axis:"y", onAfter:function(){
            $(an).effect("highlight", {color: "#99c0e1"}, 2000); }
        });
    });
 
    // step 11
    $(".return-top").click(function() {
        $.scrollTo("body", {duration: 800, axis:"y"});
    });
});
</script>

NOTE: I simply referenced the "body" attribute so the page returns all the way back to the top of the page. Substitute "#questions" if you want it to just return to the top of the questions.

Step 12: In all honesty, we could consider ourselves finished. However, I'm a perfectionist. You see, this next fix keeps your page from jumping down to the answer, then back to the question only to finally scroll back down to the question. This happens extremely fast, so it's not too bad, but it is noticeable.

The issue comes from having a "#" in an href. A click will cause the page to jump to up to the top. Having a "#id" inside an href causes it to jump to that id. This is something we don't want, since we will be scrolling to what we want displayed. This step is also something I've added to the Bit Repositories functionality. I don't like the way I have to accomplish it, because i don't like adding onClick to links, but it's the only way I know how to resolve the issue.

Without further ado, this is what you need to do. You must add an onClick="return false;" to your Quesiton <li> anchor tags. This will eliminate the jumping around.

<ul id="questions">
    <li id="q1"><a href="#" onClick="return false;">Question 1?</a></li>
    ...
    <li id="q5"><a href="#" onClick="return false;">Question 5?</a></li>
</ul>

Bonus Step: No one wants to use the default browser styles, so I have taken the liberty and provided you some CSS. This version is included with the source files, so you can decide which version you'd rather use.

<style type="text/css">
body {
	font-family: Verdana, Arial, Helvetica, sans-serif;
	font-size: 12px;
}
 
#container {
	margin: 0 auto;
	width: 700px;
}
 
h1 {
	font-size: 18px;
	font-weight: normal;
}
 
h2 {
	color: #666;
	font-size: 14px;
}
#questions {
	margin-bottom: 20px;
	padding-left: 0;
	margin-left: 20px;
}
 
#questions li {
	background: url(question-mark.png) no-repeat left center;
	line-height: 14px;
	list-style-type: none;
	margin-bottom: 10px;
	padding: 5px 0 5px 30px;
}
 
div.faq-a {
	border-bottom: dotted 2px #ddd;
	padding: 10px 0 7px;
}
 
.return-top {
	float: right;
	cursor: pointer;
	padding-left: 20px;
}
</style>

You're Done!

If you have any questions/comments about how something is done or how I can improve this further, I'd love to hear from you. Just post a comment below and I'll respond, if necessary.

download source filesview demo

Reply

The content of this field is kept private and will not be shown publicly. If you have a Gravatar account, used to display your avatar.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd><img>
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <css>, <drupal>, <java>, <javascript>, <mysql>, <php>, <ruby>. The supported tag styles are: <foo>, [foo]. PHP source code can also be enclosed in <?php ... ?> or <% ... %>.
  • Lines and paragraphs break automatically.

More information about formatting options

CAPTCHA

This question is for testing whether you are a human visitor and to prevent automated spam submissions.