Implementing a smart drop down menu system (Reconfigured)

From Shopify Wiki

Revision as of 17:03, 20 December 2011 by Dennis (Talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Contents

Before reading further...

Before you add any drop down menus, take a look at these articles and see whether your layout adheres to proper web design standards:

What Shopify gives us out the box

With Shopify, we can create new lists of links and add them to our shop.

We create a menu (list of links) under the Navigation tab, then we add a bit of code to our theme to show that menu.

What Shopify does not give us

Shopify does not offer the possibility to nest a menu inside a menu under the Navigation tab. Link lists have 1 level only. There are no multiple-level menus in Shopify.

Using a naming convention to create sub-menus

So, there's no way to create sub-menus in Shopify under the Navigation tab. Should that stop us from creating a multi-level menu? Certainly not. With a bit of logic added to our theme, and a smart naming convention applied to the name of our link lists under the Navigation tab, we, as a designer, will be able to create a dynamic multi-level menu in Shopify — 'dynamic' as in not hard-coded in the theme.

How would that naming convention work?

For every link we wish to connect to a sub-menu, we'll create a link list that will have the same name as said (parent) link. Say what? Let's take an example. A typical Main Menu in Shopify contains the following links:

File:/upload/4/42/Default main menu.png

Say we wanted to include a link called Shop by Brand:

File:/upload/c/c7/Menu with shop by brand.png

And we wanted that link to become a drop-down sub-menu listing the brands in our shop, with links to vendor collections. Then what we'd do is create a link list called Shop by Brand:

File:/upload/e/e5/Add a link list.png

File:/upload/5/50/Brand name link list.png

And we'd fill up that link list with links to our vendor collections:

File:/upload/d/d5/Shop by brand menu full.png

To turn any link of our Main Menu into a 'parent' link, create a 'child' menu for it using the name of your parent link.

Now, time to make our theme smart.

Editing the HTML / Liquid that outputs our Main Menu

There are many solutions out there to create fancy drop-down menus.

The HTML markup these solutions rely on is always the same:

<ul id="nav">  
    <li><a href="#" >Link 1</a></li>  
    <li><a href="#" >Link 2</a>  
        <ul>  
            <li><a href="#" >Link3</a></li>  
            <li><a href="#" >Link4</a></li>  
        </ul>  
    </li>  
    <li><a href="#" >Link 5</a></li>  
</ul>  

Let's make it happen. In your shop admin, go to Theme → Template Editor. On the Template Editor page, locate the file theme.liquid under Layouts. (The .liquid extension is omitted in that view.) Click on 'theme' to open the file theme.liquid in the online code editor.

You will need to locate the Liquid / HTML that outputs your Main Menu. Look for the handle of the menu, it's main-menu. In the Reconfigured theme, the HTML / Liquid for the main menu is:

<ul class="navigation">{% for link in linklists.main-menu.links %}{% assign current = false %}{% if template == 'index' and link.url == '/' %}{% assign current = true %}{% elsif collection.url == link.url %}{% assign current = true %}{% elsif blog.url == link.url %}{% assign current = true %}{% elsif page.url == link.url %}{% assign current = true %}{% elsif page_title == link.title %}{% assign current = true %}{% elsif template == 'list-collections' and link.url == '/collections' %}{% assign current = true %}{% elsif page_title == 'Products' and link.url == '/collections/all' %}{% assign current = true %}{% elsif template == 'article' and link.url == article.url %}{% assign current = true %}{% endif %}
  <li{% if forloop.first %} class="first"{% endif %}><a{% if current %} class="active"{% endif %} href="{{ link.url }}">{{ link.title }}</a></li>{% endfor %}
</ul>

There is a longish segment of Liquid that determines if either of the menu items points to the current page, i.e. is an 'active link'. When it does, it adds an 'active' class to said item. Let's add a few line breaks to see the relevant code more clearly:

<ul class="navigation">

{% for link in linklists.main-menu.links %}

<!-- does this link in our iteration point to the current page? -->
{% assign current = false %}{% if template == 'index' and link.url == '/' %}{% assign current = true %}{% elsif collection.url == link.url %}{% assign current = true %}{% elsif blog.url == link.url %}{% assign current = true %}{% elsif page.url == link.url %}{% assign current = true %}{% elsif page_title == link.title %}{% assign current = true %}{% elsif template == 'list-collections' and link.url == '/collections' %}{% assign current = true %}{% elsif page_title == 'Products' and link.url == '/collections/all' %}{% assign current = true %}{% elsif template == 'article' and link.url == article.url %}{% assign current = true %}{% endif %}
<!-- end of soul-searching about active class -->

  <li{% if forloop.first %} class="first"{% endif %}><a{% if current %} class="active"{% endif %} href="{{ link.url }}">{{ link.title }}</a></li>

{% endfor %}

</ul>

For each link in our Main Menu, we need to check if there is a menu defined that bears the same name, and if that menu contains any link. Reformatted to be easy on the eye, we get this:

<ul class="navigation">

  {% for link in linklists.main-menu.links %}

<!-- does this link in our iteration point to the current page? -->
{% assign current = false %}{% if template == 'index' and link.url == '/' %}{% assign current = true %}{% elsif collection.url == link.url %}{% assign current = true %}{% elsif blog.url == link.url %}{% assign current = true %}{% elsif page.url == link.url %}{% assign current = true %}{% elsif page_title == link.title %}{% assign current = true %}{% elsif template == 'list-collections' and link.url == '/collections' %}{% assign current = true %}{% elsif page_title == 'Products' and link.url == '/collections/all' %}{% assign current = true %}{% elsif template == 'article' and link.url == article.url %}{% assign current = true %}{% endif %}
<!-- end of soul-searching about active class -->

  <li{% if forloop.first %} class="first"{% endif %}>
    <a{% if current %} class="active"{% endif %} href="{{ link.url }}">{{ link.title }}</a>
    {% capture child_list_handle %}{{ link.title | handle }}{% endcapture %}
    {% if linklists[child_list_handle] and linklists[child_list_handle].links.size > 0 %}
    <ul>
      {% for l in linklists[child_list_handle].links %}
      <li><a href="{{ l.url }}">{{ l.title }}</a></li>
      {% endfor %}
    </ul>
    {% endif %}
  </li>
 
  {% endfor %}

</ul>

Brace yourself as the results of this edit will disappoint.

File:/upload/2/25/Ugly results.png

Our menu needs CSS love.

Using the Superfish plugin (jQuery)

Downloading Superfish

We will download the Superfish massage therapist here: http://users.tpg.com.au/j_birch/plugins/superfish/#download

File:/upload/2/2d/Fish zip.png

Unzip.

Uploading the script files to our theme assets

On the Template Editor page, under Theme Assets, click on the Upload a new theme asset link. Browse to the following files and upload:

  • hoverIntent.js
  • jquery.bgiframe.min.js
  • superfish.js
  • supersubs.js

Including these script files

In the head element of our theme.liquid layout file, we will include the script files:

{{ 'hoverIntent.js' | asset_url | script_tag }}
{{ 'jquery.bgiframe.min.js' | asset_url | script_tag }}
{{ 'superfish.js' | asset_url | script_tag }}
{{ 'supersubs.js' | asset_url | script_tag }}

Note

Make sure to include the scripts after this code:

{{ 'jquery-1.3.2.min.js'       | asset_url | script_tag }}

Or whatever jQuery include your theme is using.

Adding the basic Superfish CSS to our theme stylesheet

Browse to the file css/superfish.css and look for the segment of CSS that has this heading:

/*** ESSENTIAL STYLES ***/

We will copy that CSS segment at the bottom of our theme stylesheet. For the Reconfigured theme, the stylesheet to amend is all.css.liquid.

Adding our CSS hook

We will add a sf-menu class to the parent ul of our Main Menu. In Reconfigured, that'll give us:

<ul class="navigation sf-menu">

Adding our JavaScript

Add the following JavaScript code to the head element of theme.liquid:

<script type="text/javascript" charset="utf-8">
//<![CDATA[
jQuery(function() {
  jQuery('ul.sf-menu').superfish({
    animation: { height: 'show' }, // slide-down animation
    speed: 'fast' // faster animation speed
  });
});
//]]>
</script>

The Superfish plugin has several options worth playing with: http://users.tpg.com.au/j_birch/plugins/superfish/#options

Tidying up our CSS in Reconfigured

If you look at our menu now, it does what it's supposed to do: when you place your cursor over a parent menu item, a sub-menu slides down to reveal child menu items.

But it looks downright ugly. We'll fix this.

File:/upload/3/31/Functional and ugly.png

Adding the following CSS makes the menu look 3/4 decent:

.sf-menu {
  line-height: 37px;
}

.sf-menu li.sfHover ul {
  top: 37px;
}

37 pixels is the exact height of our navigation bar.

File:/upload/e/ee/Functional and looks ok.png

Visiting the demo store

http://turcotte-koepp6126.myshopify.com/

Conclusion

Drop-down menus are about the hardest thing to style for a front-end designer: they are very hard to get 'just right'. Most drop-down menus we see out there are hideous. A drop-down menu is seen as fancy and cool and a must-have by many, unfortunately. A beautiful, professional theme can live without drop-down menus. Easy or not, they're not the holy grail of navigation. --Chill35 17:40, 1 April 2010 (UTC)

Tools

Shopify stores showcase