Last night, I was building a little thing in jQuery to slide a menu off to the left of the screen. What I wanted to do was queue the following effects so that the rest of the content on the page could take up it’s space once it has gone:
- Adjust the ‘left’ position of the menu <div> to slide it off the screen.
- Hide the menu <div> so that the content can move in.
The second step seems to be necessary as adjusting the left position of the <div> alone does not allow the content to move in (I‘m working on that bit still).
So lets take a second to look at what I had. Basically, this is my HTML:
1: <body>
2: <div id="wrapper">
3: <div id="menu">
4: <ul>
5: <li><a href="#">Menu Link 1</a></li>
6: <li><a href="#">Menu Link 2</a></li>
7: <li><a href="#">Menu Link 3</a></li>
8: <li><a href="#">Menu Link 4</a></li>
9: <li><a href="#">Menu Link 5</a></li>
10: </ul>
11: </div>
12: <div id="content">
13: <p><a id="menuToggle" href="#">This link</a> will toggle the menu.</p>
14: <p>Lorem ipsum dolor sit ... eget arcu erat.</p>
15: <p>Nullam a turpis eros, a ... et, auctor et nunc.</p>
16: <p>Cras tellus arcu, tincidunt ... tincidunt dolor sem ac odio. </p>
17: </div>
18: </div>
19: </body>
It’s a pretty simple and fairly standard kind of markup with unordered list to use as our menu. Next we need to style it up using some CSS, so here is my amazing effort:
1: *
2: {
3: margin:0;
4: padding:0;
5: }
6:
7: div#wrapper
8: {
9: margin-left:100px;
10: width:800px;
11: overflow: hidden;
12: }
13:
14: div#menu
15: {
16: background-color:#C0C0C0;
17: float:left;
18: position:relative;
19: width:220px;
20: overflow:hidden;
21: margin-right:10px;
22: }
23:
24: div#menu ul
25: {
26: list-style: none;
27: float:left;
28: overflow:hidden;
29: }
30:
31: div#menu ul li
32: {
33: overflow:hidden;
34: }
35:
36: div#content p
37: {
38: margin: 10px;
39: }
Genius, you pay a lot of money for a design like that. The basic point here is that I’m floating the div#menu left and allowing div#content to flow around the menu.
Looking back at my initial list of effects to apply to the menu, my first cut at the scrip was as follows:
1: var hidden = false;
2:
3: $(document).ready(function(){
4: $("div#content p a#menuToggle").click(function(){
5: if(hidden)
6: {
7: $("div#menu")
8: .show()
9: .animate({
10: "left": 0
11: }, {
12: queue: false, duration: "slow"
13: });
14: hidden = false;
15: } else {
16: $("div#menu")
17: .animate({
18: "left": $("div#menu").attr("clientWidth") * -1
19: }, {
20: queue: false, duration: "slow"
21: })
22: .hide();
23: hidden = true;
24: }
25: });
26: });
What i do here is assign a variable that will indicate the visibility of div#menu. When my link (a#menuToggle) is clicked, my intention was that the menu would slide out of view and then disappear, the content taking up its space once it was gone. Clicking again would make it appear nicely.
The Problem
In reality, what actually happened is the menu disappeared instantly. This had my flitting about on Google looking at queues and all sorts. I was slowly starting ot accept that I simply could not do what I wanted and was feeling a little dejected when I decided to have a look in the jQuery script file itself. What I found was interesting, the hide() function is defined as follows:
1: hide: function(speed,callback){
2: if ( speed ) {
3: return this.animate( genFx("hide", 3), speed, callback);
4: } else {
5: for ( var i = 0, l = this.length; i < l; i++ ){
6: var old = jQuery.data(this[i], "olddisplay");
7: if ( !old && old !== "none" )
8: jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
9: }
10:
11: // Set the display of the elements in a second loop
12: // to avoid the constant reflow
13: for ( var i = 0, l = this.length; i < l; i++ ){
14: this[i].style.display = "none";
15: }
16:
17: return this;
18: }
19: }
As you can see on line #2 we’re checking to see if the speed parameter is supplied. If it is, we perform some kind of effect on the selected object, otherwise, we run the code between lines 5 and 17. It’s clear to me that these lines ignore the effect queue completely. To test it, I added a speed to my script and it all worked fine.
It’s worth noting here, that I’ve changed the queue value, but the same result appears with true and false.
The Solution
In the end, I added a speed to the hide method and everything queues up nicely. So the final script looks as follows:
1: var hidden = false;
2:
3: $(document).ready(function(){
4: $("div#content p a#menuToggle").click(function(){
5: if(hidden)
6: {
7: $("div#menu")
8: .show()
9: .animate({
10: "left": 0
11: }, {
12: queue: false, duration: "slow"
13: });
14: hidden = false;
15: } else {
16: $("div#menu")
17: .animate({
18: "left": $("div#menu").attr("clientWidth") * -1
19: }, {
20: queue: false, duration: "slow"
21: })
22: .hide("slow");
23: hidden = true;
24: }
25: });
26: });
Hope that helps someone, and sorry it doesn’t look super-slick like so many other jQuery examples!