This commit makes Pure Menu smaller, more responsive, and easier to customize. This change does break back-compatibility, as I have removed some classnames and some functionality.
What's in this PR
- Remove the close relationship with YUI's
Y.Menu
. This helps to get rid of a lot of CSS which wasn't needed 80% of the time.
- Remove
.pure-menu-open
: This also helps to get rid of adjoining class selectors, which makes it easier to customize menus.
- Add
.pure-menu-responsive
and .pure-menu-responsive-toggle
to make responsive horizontal menus: Yay!
- CSS-only dropdown support: This only supports one level of nesting but I think that should be fine for most use cases.
- Make pure menus really easy to customize: More on this below
Responsive Horizontal Menu
This is something that I've been wanting for a while. You can now make responsive menus that can show and hide their links on small screens. Doing this is really easy, and the site will have JS snippets that you can copy/paste in to achieve the necessary behavior.
This is done by adding two new classnames, .pure-menu-responsive
and .pure-menu-responsive-toggle
. Since you may not want every horizontal menu to be responsive, you have to add the .pure-menu-responsive
class name. Responsive menus also need an <a>
element with the .pure-menu-responsive-toggle
class name so that it can show/hide menu items on small screens.
HTML
Here's the HTML for a responsive menu:
<div class="pure-menu pure-menu-horizontal pure-menu-responsive">
<a href="#" class="pure-menu-link pure-menu-heading">Title</a>
<a href="#" class="pure-menu-responsive-toggle">Toggle</a>
<ul class="pure-menu-list">
<li class="pure-menu-item"><a href="#" class="pure-menu-link">Home</a></li>
<li class="pure-menu-item"><a href="#" class="pure-menu-link">About</a></li>
<li class="pure-menu-item"><a href="#" class="pure-menu-link">Blog</a></li>
<li class="pure-menu-item"><a href="#" class="pure-menu-link">Contact</a></li>
<li class="pure-menu-item"><a href="#" class="pure-menu-link">GitHub</a></li>
<li class="pure-menu-item"><a href="#" class="pure-menu-link">Twitter</a></li>
</ul>
</div>
That'll give you something that looks like this on small screens:

Open State:

Dropdown Menu
Here's the HTML for a dropdown menu:
<div class="pure-menu pure-menu-horizontal pure-menu-responsive">
<a href="#" class="pure-menu-link pure-menu-heading">Title</a>
<a href="#" class="pure-menu-responsive-toggle">Toggle</a>
<ul class="pure-menu-list">
<li class="pure-menu-item"><a href="#" class="pure-menu-link">Home</a></li>
<li class="pure-menu-item"><a href="#" class="pure-menu-link">About</a></li>
<li class="pure-menu-item pure-menu-has-children">
<a href="#" class="pure-menu-link">Blog</a>
<ul class="pure-menu-children">
<li class="pure-menu-item"><a class="pure-menu-link" href="/handlebars">Handlebars Helpers</a></li>
<li class="pure-menu-item"><a class="pure-menu-link" href="/dust">Dust Helpers</a></li>
<li class="pure-menu-item"><a class="pure-menu-link" href="/react">React Mixins</a></li>
<li class="pure-menu-item"><a class="pure-menu-link" href="/javascript">Intl Message Format</a></li>
</ul>
</li>
<li class="pure-menu-item"><a href="#" class="pure-menu-link">Contact</a></li>
<li class="pure-menu-item"><a href="#" class="pure-menu-link">GitHub</a></li>
<li class="pure-menu-item"><a href="#" class="pure-menu-link">Twitter</a></li>
</ul>
</div>
Here's what it looks like:

Customizing the menu
The menu now has various child classes that you can hook into. Here they are:
.pure-menu
: Hook into this to style the menu's bounding box.
.pure-menu-list
: All <ul>
tags within a menu should have this class.
.pure-menu-item
: All <li>
tags within a menu should have this class.
.pure-menu-link
: All <a>
tags within a menu should have this class.
.pure-menu-has-children
: A <li.pure-menu-item>
tag that has a nested menu should have this class.
.pure-menu-children
: A <ul.pure-menu-list>
tag that is a child of an <li.pure-menu-item> tag (nested menu) has this class.
.pure-menu-heading
: A <a>
tag that is outside the <ul.pure-menu-list>
and is the heading for the menu has this class.
.pure-menu-responsive-toggle
: A <a>
tag in a responsive menu that sits outside the <ul.pure-menu-list>
and is responsible for showing/hiding the toggle button has this class.
.pure-menu-is-active
: In a responsive menu, this class signifies when a menu is "open" (ie: showing its submenus).
Menus were probably the hardest part of the library to customize. You would have to write a ton of messy CSS to do it. Not anymore! This is how you customize a menu now:
HTML
Here's the HTML for a responsive horizontal menu. I've added some classes with the -custom
suffix to base my styles off of. I recommend doing the same when customizing any Pure component.
<div class="menu-custom pure-menu pure-menu-horizontal pure-menu-responsive">
<a href="#" class="heading-custom pure-menu-link pure-menu-heading">Title</a>
<a href="#" class="toggle-custom pure-menu-responsive-toggle">Toggle</a>
<ul class="list-custom pure-menu-list">
<li class="item-custom pure-menu-item"><a href="#" class="link-custom pure-menu-link">Home</a></li>
<li class="item-custom pure-menu-item"><a href="#" class="link-custom pure-menu-link">About</a></li>
<li class="item-custom pure-menu-item"><a href="#" class="link-custom pure-menu-link">Blog</a></li>
<li class="item-custom pure-menu-item"><a href="#" class="link-custom pure-menu-link">Contact</a></li>
<li class="item-custom pure-menu-item"><a href="#" class="link-custom pure-menu-link">GitHub</a></li>
<li class="item-custom pure-menu-item"><a href="#" class="link-custom pure-menu-link">Twitter</a></li>
</ul>
</div>
CSS
Here's what the CSS would look like. Notice how I've added my own class to the menu above to make it easier to style. However, I don't have to use any descendent selectors anymore.
/* Update background on menu. */
.menu-custom {
background: #111;
padding: 0.8em;
border-radius: 5px;
}
/* Make the heading white */
.heading-custom {
color: white;
}
/* Make links light-gray with a transition */
.link-custom {
color: #ddd;
transition: color 0.5s;
}
/* Color links blue on hover and focus */
.link-custom:hover,
.link-custom:focus {
color: #40a4ff;
}
/* Update the positioning of the toggle button
because we are modifying the menu's padding, and change its color. */
.toggle-custom {
margin-top: 6px;
margin-right: 15px;
color: white;
}
Looks like this:

Responsive Behavior and overriding Media Queries
To add the responsive behavior to menus, we obviously need to have a media query. I recommend doing the same thing that we did with Grids. Have pure-menu-responsive.min.css
available on the CDN, with a sane media query default (I recommend 48em
), but allow people to override this by not getting that file from the CDN, and instead adding the following CSS inside their app.css
:
@media (min-width: 48em) {
/*At 48em and higher, the list becomes display:inline-block (from display:none)*/
.pure-menu-responsive .pure-menu-list {
display: inline-block;
}
/*At 48em and higher, we hide the toggle, because we just showed the .pure-menu-list*/
.pure-menu-responsive-toggle {
display: none;
}
}
Responsive Behavior and JavaScript
You need to have some JS on the page to toggle the responsive menu. This would be something that users can copy/paste from the Pure site.
Example using YUI:
YUI().use('node', function (Y) {
//When you click on a .pure-menu-responsive-toggle, toggle the associated menu
Y.one('document').delegate('click', function (e) {
e.preventDefault();
e.target.get('parentNode').toggleClass('pure-menu-is-active');
}, '.pure-menu-responsive-toggle');
});
Tests
I've tested this on Latest Chrome/FF/Safari, and iOS 7. Haven't tested this on Android or IE yet, so I'll do that and report back here (help would be appreciated :smile: ). The manual test page has been updated with the new menu.
Next Steps
- [ ] Verify tests in IE
- [ ] Verify tests in Android 4.x
enhancement discussion