The HTML: the Structure
<section class="clearfix" id="lessonBuilder">
<span id="lessonsTabTarget"><a href="#">Show Lessons</a></span>
<nav id="lessonsTab" style="display: none;">
<h1>Lessons</h1>
<ul class="clearfix">
<li class="tab"><a href="#"><img src="thumbnail.jpg" /></a></li>
<li class="tab"><a href="#"><img src="thumbnail.jpg" /></a></li>
<li class="tab"><a href="#"><img src="thumbnail.jpg" /></a></li>
<li class="tab"><a href="#"><img src="thumbnail.jpg" /></a></li>
</ul>
</nav>
</section>
If you’re unfamiliar with HTML5, you’ll see I’ve used a few tags that will be new to you. The section
is used to describe sections of your site, and the nav
tag is used to contain navigation elements. The HTML5 tags help to reduce “div-itis”; for example, where you may have <div id="section"></div>
and <div id="nav"></div>
.
Apart from the new tags, it’s basically standard HTML. The unordered list would contain the linked thumbnails.
The JavaScript: the Magic
var LEARNABLE = {};
/**
* Initialises the Lesson Drawer
*/
LEARNABLE.lessonDrawer = (function () {
var init = function () {
$("#lessonsTab").hide();
$('#lessonsTabTarget').toggle(function() {
$(this).addClass("shown").children('a').html("Hide Lesson Navigator");
$("nav#lessonsTab").show("slow");
return false;
}, function() {
$("nav#lessonsTab").hide("slow");
$(this).removeClass("shown").children('a').html("Show Lesson Navigator");
return false;
});
};
// Public API
return {
init: init
};
})();
$(document).ready(function() {
LEARNABLE.lessonDrawer.init();
});
The JavaScript is where it becomes interesting. I’m going to proceed through this step by step, building it the way I would write it while explaining along the way.
var LEARNABLE = {};
This creates an object that will contain the functions for your page. We’ve named it LEARNABLE
, as it “namespaces” your functions. This form of writing JavaScript is called the module pattern. It’s a great way to structure your JavaScript for a number of reasons:
- It reduces the number of global variables, as they are evil.
- You can easily have lots of functions working together without affecting other scripts you may have running.
- It’s relatively straightforward to maintain and work on.
- Other developers involved in the project will be able to see what’s going on easily.
var LEARNABLE = {};
/**
* Initialises the Lesson Drawer
*/
LEARNABLE.lessonDrawer = (function () {
var init = function () {
...
};
// Public API
return {
init: init
};
})();
Now we create our functions. I’ve named it lessonDrawer
, and as it’s a part of the LEARNABLE
codebase, it becomes LEARNABLE.lessonDrawer
.
LEARNABLE.lessonDrawer
is a function, so it is written as = (function (){
, then the code, and is closed with })();
.
Here are the outside bits of the function:
LEARNABLE.lessonDrawer = (function () {
...
})();
Count the parentheses, and you’ll see that there’s an extra set of ()
at the end. This means it is self-executing; when your browser has downloaded this script, it will run it, allowing it to be accessed by any other JavaScript function in your script. Well, sort of.
var init = function () {
...
};
// Public API
return {
init: init
};
This little bit of trickery means that within the lessonDrawer
function there are further functions, in this case called init
. The tricky part is that at the end of the lessonDrawer
function, it will return to your script a way to gain access to the init
function. You may ask, what’s the big deal? Let’s say we changed it a little:
var LEARNABLE = {};
/**
* Initialises the Lesson Drawer
*/
LEARNABLE.lessonDrawer = (function () {
var init = function () {
...
};
var otherThing = function () {
...
};
// Public API
return {
init: init
};
})();
Because we’ve specifically said that we only want the init
function available, no function outside of lessonDrawer
can touch the function named otherThing
. It’s safe inside its parent function. You can’t accidentally run it and, more importantly, when you give it to other developers, they can only use it the way you’ve specified.
Now to the insides of the init
function:
$("#lessonsTab").hide();
First, we hide the #lessonsTab
, which is our nav
container. We do that in this function so that JavaScript-less users can still see the lesson drawer:
$('#lessonsTabTarget').toggle(function() {
....
}, function() {
....
});
The jQuery Toggle method displays or hides elements that it’s told about. The first half between the $('#lessonsTabTarget').toggle(function() {
and });
means that when it’s clicked, it will show the lesson drawer.
Its counterpart, between the function() {
and closing });
, will hide the lesson drawer if it’s open:
$(this).addClass("shown").children('a').html("Hide Lesson Navigator");
$("nav#lessonsTab").show("slow");
return false;
This is the code for showing the lesson drawer. I’ll now explain it line by line for you:
$(this).addClass("shown").children('a').html("Hide Lesson Navigator");
$(this)
means whatever its parent is talking about (in this case, it’s the $('#lessonsTabTarget')
. I’ve been assuming you know what $('#lessonsTabTarget')
means, but for those who’ve been playing at home, it asks jQuery (represented by the $
) for any elements that have an ID of lessonsTabTarget
.
We add a class called “shown"
to $(this)
, and then look through its children for an anchor. Looking back at the HTML structure we’re using, this is <span id="lessonsTabTarget"><a href="#">Show Lessons</a></span>
, and on the child anchor we change the text (or its HTML) to the next text (“Hide Lesson Navigator”) as an instruction to the user that if they click the button, they will hide it).
$("nav#lessonsTab").show("slow");
Now we tell it to find the nav#lessonsTab
and make it appear slowly. The jQuery Show method accepts a few arguments, the first being how long you want it to take to show an element. Instead of "slow"
, you can use "fast"
or the number of milliseconds, where 1,000 means one second (as this is typed as an integer, no quotation marks are necessary, unlike "fast"
and "slow"
).
return false;
We return false
to stop the browser from following the link. (As it is, it doesn’t go anywhere, but the <a href="#"
would make the page jump to the top without returning false).
To summarize:
- Set up an unobstructive JavaScript function any time the page contains a
#lessonsTabTarget
element. - Add a class (telling the CSS that it’s “
shown
“). - Change the button text.
- Open the lesson tab drawer.
- Stop the page from following the link.
shown
” class name, and changes the text back. It also stops the browser from following the link. On a side note, the return false
always needs to be the last thing in your function.
Lastly, we need to run the code. Our final task is to tell the document that when it’s downloaded all its resources (JavaScript and CSS, as well as images), or when it’s ready, to run the init()
function. To access the init()
function, you have to use its full name: LEARNABLE.lessonDrawer.init();
.
$(document).ready(function() {
LEARNABLE.lessonDrawer.init();
});
The CSS: the Polish
Adding the CSS is the last bit needed to make this a really great component./* HTML5 tags */
header, section, footer, aside, nav, article, figure {
display: block;
}
#lessonBuilder {
min-height: 200px;
width: 940px;
margin: 0 auto;
position: relative;
}
nav#lessonsTab {
background-color: #26414A;
width: 940px !important;
margin: 0 auto;
opacity: 1 !important;
padding: 30px 0;
z-index: 1;
display: none;
}
nav#lessonsTab h1 {
color: white;
font-size: 18px;
margin: 0 0 0 45px;
}
nav#lessonsTab ul {
list-style: none;
padding: 20px 0 0 45px;
margin: 0;
}
nav#lessonsTab ul li {
float: left;
margin: 0 15px 40px 0;
padding: 4px;
height: 70px;
}
nav#lessonsTab ul li:hover {
background-color: #C9EFFB;
}
nav#lessonsTab ul li a {
width: 100px;
display: block;
text-decoration: none;
}
nav#lessonsTab ul li a img {
border: none;
}
#lessonsTabTarget {
border-top: 2px solid #3F6D7B;
width: 940px;
display: block;
z-index: 2;
margin-top: -2px;
text-decoration: none;
}
#lessonsTabTarget a {
background: #283D44 url('lessonnav.png') top left repeat-x;
display: block;
padding: 7px 20px;
position: absolute;
right: 0;
top: 0;
color: white;
width: 170px;
text-align: center;
-moz-border-radius: 0 0 5px 5px;
-webkit-border-radius: 0 0 5px 5px;
border-radius: 0 0 5px 5px;
font-weight: bold;
font-size: 15px;
text-decoration: none;
text-shadow: 0 1px 1px #333;
}
#lessonsTabTarget.shown a,
#lessonsTabTarget a:hover {
background: #283D44 url('lessonnav.png') 0 -35px repeat-x;
}
/* http://perishablepress.com/press/2008/02/05/lessons-learned-concerning-the-clearfix-css-hack */
.clearfix:after {
clear: both;
content: ' ';
display: block;
font-size: 0;
line-height: 0;
visibility: hidden;
width: 0;
height: 0;
}
.clearfix {
display: inline-block;
}
* html .clearfix {
height: 1%;
}
.clearfix {
display: block;
}
In Conclusion
This nice modular component is a real-world example of effectively using JavaScript (in this case, jQuery), HTML (with some HTML5 stuff), and CSS together. As I mentioned, it’s in use in Learnable, the place where you can take or create a course online on any subject.Frequently Asked Questions (FAQs) about Building a Lesson Drawer in jQuery, HTML, and CSS
How can I add more content to the drawer?
Adding more content to the drawer is quite simple. You just need to add more HTML elements within the drawer’s div. You can add text, images, links, or even other HTML elements like lists or tables. Remember to use appropriate HTML tags for each type of content. Also, ensure that the content fits within the drawer’s width and height. If the content exceeds the drawer’s dimensions, you may need to add a scrollbar using CSS.
Can I use this drawer on a mobile device?
Yes, you can use this drawer on a mobile device. The drawer is responsive, which means it adjusts its size and layout based on the screen size. However, you may need to adjust the drawer’s dimensions and the size of the content within it to ensure it displays correctly on smaller screens. You can use CSS media queries to apply different styles for different screen sizes.
How can I change the direction of the drawer?
The direction of the drawer can be changed by modifying the CSS. By default, the drawer slides in from the left. If you want it to slide in from the right, you can change the ‘left’ property to ‘right’ in the CSS. Similarly, you can make the drawer slide in from the top or bottom by using the ‘top’ or ‘bottom’ property instead.
Can I add multiple drawers to a page?
Yes, you can add multiple drawers to a page. Each drawer should have a unique id so that it can be controlled independently. You can use the same jQuery function to control all the drawers, but you need to pass the id of the drawer as a parameter to the function.
How can I change the speed of the drawer?
The speed of the drawer can be changed by modifying the jQuery function. The ‘animate’ function has a duration parameter that determines the speed of the animation. By default, the duration is 200 milliseconds. You can increase or decrease this value to change the speed of the drawer.
Can I add a close button to the drawer?
Yes, you can add a close button to the drawer. You need to add a button element within the drawer’s div and use jQuery to add a click event to the button. When the button is clicked, the drawer should be hidden. You can use the ‘hide’ function in jQuery to hide the drawer.
How can I make the drawer always visible?
To make the drawer always visible, you can remove the jQuery function that hides the drawer. Alternatively, you can set the ‘display’ property of the drawer’s div to ‘block’ in the CSS. This will make the drawer always visible, regardless of any jQuery functions.
Can I use this drawer with other JavaScript libraries?
Yes, you can use this drawer with other JavaScript libraries. However, you need to ensure that there are no conflicts between jQuery and the other libraries. You can use the ‘noConflict’ method in jQuery to avoid conflicts.
How can I add a scrollbar to the drawer?
You can add a scrollbar to the drawer by using CSS. If the content within the drawer exceeds the drawer’s dimensions, a scrollbar will automatically appear. You can use the ‘overflow’ property in CSS to control the scrollbar. If you set ‘overflow’ to ‘auto’, a scrollbar will appear only when necessary.
Can I use this drawer without jQuery?
While this drawer is built using jQuery for simplicity and ease of use, it is possible to build a similar drawer using pure JavaScript. However, this would require more complex code and a deeper understanding of JavaScript. If you are comfortable with JavaScript, you can use the ‘document.getElementById’ method to select the drawer and the ‘style’ property to control its visibility and position.
Mark Cipolla is a web guy at heart; front-end design and coding (with xhtml/html5/css with a touch of javascript) meets programming (Ruby on Rails and a touch of PHP).