YUI Library Home

YUI Library Examples: Menu Family: Website Top Nav Using Animation With Submenus Built From Markup

Menu Family: Website Top Nav Using Animation With Submenus Built From Markup

This example demonstrates how to create a traditional, two-column page layout (using Grids) with top navigation featuring animated drop-down menus. The top navigation is created using a MenuBar instance that is constructed using existing markup and enables the user to navigate to different landing pages for each Yahoo! product category.

Begin by placing the markup for the two-column Grid on the page (this example uses the Grids Preset Template 1, 160px left). Add the markup for the MenuBar instance to the right column of the grid, appending the class of "yuimenubarnav" to the root element. The application of the "yuimenubarnav" class will render each item in the MenuBar instance with arrows to the right of each text label, providing a visual cue that the item contains a submenu.

1<div id="productsandservices" class="yuimenubar yuimenubarnav"
2    <!-- Additional Menubar markup here --> 
3</div> 
view plain | print | ?

Use the onContentReady method of the Event utility to instantiate the MenuBar as soon as its markup is available for scripting.

1// Initialize and render the MenuBar when it is available in the page 
2 
3YAHOO.util.Event.onContentReady("productsandservices"function () { 
4 
5    /*
6         Instantiate a MenuBar.  The first argument passed to the 
7         constructor is the id of the element in the page that 
8         represents the MenuBar; the second is an object literal 
9         representing a set of configuration properties.
10    */ 
11 
12    var oMenuBar = new YAHOO.widget.MenuBar("productsandservices", {  
13                                                autosubmenudisplay: true,  
14                                                hidedelay: 750,  
15                                                lazyload: true }); 
16                                                 
17 
18    /*
19         Call the "render" method with no arguments since the 
20         markup for this MenuBar already exists in the page.
21    */ 
22 
23    oMenuBar.render(); 
24 
25}); 
view plain | print | ?

This MenuBar instance makes use of several configuration properties. Setting the "autosubmenudisplay" configuration property to "true" modifies its default behavior so that mousing over any item in the MenuBar automatically triggers the display of its submenu. The "hidedelay" configuration property is set to "750" so each submenu automatically hides 750ms after the user's mouse has left the menu. Lastly, the "lazyload" property is set to "true" to help speed up the initial load time of the MenuBar instance by deferring the initialization and rendering of each submenu until just before it is initially made visible.

Setup the animation for the submenus by subscribing to their "beforeShow" and "show" events. The "beforeShow" event handler will be used to collapse the height of the Menu instance before it is made visible. The "show" event handler will kick off an animation that increments the "marginTop" style property of each submenu's <ul> element from a negative value equal to its height to 0, causing the submenu to slowly expand to its original height as it is displayed.

1var ua = YAHOO.env.ua, 
2    oAnim;  // Animation instance 
3 
4 
5/*
6     "beforeshow" event handler for each submenu of the MenuBar
7     instance, used to setup certain style properties before
8     the menu is animated.
9*/ 
10 
11function onSubmenuBeforeShow(p_sType, p_sArgs) { 
12 
13    var oBody, 
14        oElement, 
15        oShadow, 
16        oUL; 
17 
18 
19    if (this.parent) { 
20 
21        oElement = this.element; 
22 
23        /*
24             Get a reference to the Menu's shadow element and 
25             set its "height" property to "0px" to syncronize 
26             it with the height of the Menu instance.
27        */ 
28 
29        oShadow = oElement.lastChild; 
30        oShadow.style.height = "0px"
31 
32         
33        /*
34            Stop the Animation instance if it is currently 
35            animating a Menu.
36        */  
37     
38        if (oAnim && oAnim.isAnimated()) { 
39         
40            oAnim.stop(); 
41            oAnim = null
42         
43        } 
44 
45 
46        /*
47            Set the body element's "overflow" property to 
48            "hidden" to clip the display of its negatively 
49            positioned <ul> element.
50        */  
51 
52        oBody = this.body; 
53 
54 
55        //  Check if the menu is a submenu of a submenu. 
56 
57        if (this.parent &&  
58            !(this.parent instanceof YAHOO.widget.MenuBarItem)) { 
59         
60 
61            /*
62                There is a bug in gecko-based browsers where 
63                an element whose "position" property is set to 
64                "absolute" and "overflow" property is set to 
65                "hidden" will not render at the correct width when
66                its offsetParent's "position" property is also 
67                set to "absolute."  It is possible to work around 
68                this bug by specifying a value for the width 
69                property in addition to overflow.
70            */ 
71 
72            if (ua.gecko) { 
73             
74                oBody.style.width = oBody.clientWidth + "px"
75             
76            } 
77             
78             
79            /*
80                Set a width on the submenu to prevent its 
81                width from growing when the animation 
82                is complete.
83            */ 
84             
85            if (ua.ie == 7) { 
86 
87                oElement.style.width = oElement.clientWidth + "px"
88 
89            } 
90         
91        } 
92 
93 
94        oBody.style.overflow = "hidden"
95 
96 
97        /*
98            Set the <ul> element's "marginTop" property 
99            to a negative value so that the Menu's height
100            collapses.
101        */  
102 
103        oUL = oBody.getElementsByTagName("ul")[0]; 
104 
105        oUL.style.marginTop = ("-" + oUL.offsetHeight + "px"); 
106     
107    } 
108 
109
110 
111 
112/*
113    "tween" event handler for the Anim instance, used to 
114    syncronize the size and position of the Menu instance's 
115    shadow and iframe shim (if it exists) with its 
116    changing height.
117*/ 
118 
119function onTween(p_sType, p_aArgs, p_oShadow) { 
120 
121    if (this.cfg.getProperty("iframe")) { 
122     
123        this.syncIframe(); 
124 
125    } 
126 
127    if (p_oShadow) { 
128 
129        p_oShadow.style.height = this.element.offsetHeight + "px"
130     
131    } 
132 
133
134 
135 
136/*
137    "complete" event handler for the Anim instance, used to 
138    remove style properties that were animated so that the 
139    Menu instance can be displayed at its final height.
140*/ 
141 
142function onAnimationComplete(p_sType, p_aArgs, p_oShadow) { 
143 
144    var oBody = this.body, 
145        oUL = oBody.getElementsByTagName("ul")[0]; 
146 
147    if (p_oShadow) { 
148     
149        p_oShadow.style.height = this.element.offsetHeight + "px"
150     
151    } 
152 
153 
154    oUL.style.marginTop = ""
155    oBody.style.overflow = ""
156     
157 
158    //  Check if the menu is a submenu of a submenu. 
159 
160    if (this.parent &&  
161        !(this.parent instanceof YAHOO.widget.MenuBarItem)) { 
162 
163 
164        // Clear widths set by the "beforeshow" event handler 
165 
166        if (ua.gecko) { 
167         
168            oBody.style.width = ""
169         
170        } 
171         
172        if (ua.ie == 7) { 
173 
174            this.element.style.width = ""
175 
176        } 
177     
178    } 
179     
180
181 
182 
183/*
184     "show" event handler for each submenu of the MenuBar 
185     instance - used to kick off the animation of the 
186     <ul> element.
187*/ 
188 
189function onSubmenuShow(p_sType, p_sArgs) { 
190 
191    var oElement, 
192        oShadow, 
193        oUL; 
194 
195    if (this.parent) { 
196 
197        oElement = this.element; 
198        oShadow = oElement.lastChild; 
199        oUL = this.body.getElementsByTagName("ul")[0]; 
200     
201 
202        /*
203             Animate the <ul> element's "marginTop" style 
204             property to a value of 0.
205        */ 
206 
207        oAnim = new YAHOO.util.Anim(oUL,  
208            { marginTop: { to: 0 } }, 
209            .5, YAHOO.util.Easing.easeOut); 
210 
211 
212        oAnim.onStart.subscribe(function () { 
213 
214            oShadow.style.height = "100%"
215         
216        }); 
217 
218 
219        oAnim.animate(); 
220 
221 
222        /*
223            Subscribe to the Anim instance's "tween" event for 
224            IE to syncronize the size and position of a 
225            submenu's shadow and iframe shim (if it exists)  
226            with its changing height.
227        */ 
228 
229        if (YAHOO.env.ua.ie) { 
230             
231            oShadow.style.height = oElement.offsetHeight + "px"
232 
233 
234            /*
235                Subscribe to the Anim instance's "tween"
236                event, passing a reference Menu's shadow 
237                element and making the scope of the event 
238                listener the Menu instance.
239            */ 
240 
241            oAnim.onTween.subscribe(onTween, oShadow, this); 
242 
243        } 
244 
245 
246        /*
247            Subscribe to the Anim instance's "complete" event,
248            passing a reference Menu's shadow element and making 
249            the scope of the event listener the Menu instance.
250        */ 
251 
252        oAnim.onComplete.subscribe(onAnimationComplete, oShadow, this); 
253     
254    } 
255 
256
257 
258 
259/*
260     Subscribe to the "beforeShow" and "show" events for 
261     each submenu of the MenuBar instance.
262*/ 
263 
264oMenuBar.subscribe("beforeShow", onSubmenuBeforeShow); 
265oMenuBar.subscribe("show", onSubmenuShow); 
view plain | print | ?

Configuration for This Example

You can load the necessary JavaScript and CSS for this example from Yahoo's servers. Click here to load the YUI Dependency Configurator with all of this example's dependencies preconfigured.

Menu Family Examples:

More Menu Family Resources:

Copyright © 2009 Yahoo! Inc. All rights reserved.

Privacy Policy - Terms of Service - Copyright Policy - Job Openings