I have a navigation bar, where the buttons have a hover state but also need to be "active" on their respective page. Since this navigation bar is part of an include, I decided to do the active state via a class on the body tag, as in .dashboard .dashboard-button
. So I have the hover and this.
I was trying to figure out the most streamlined way to do this with Sass/Compass. I created a couple of mixins:
@mixin nav-button-on($icon) {
background-color: #2f3684; // Old browsers
@include filter-gradient($offwhite, #E5E5E5, vertical); // IE6-9
@include background-image(url('../images/'+$icon+'-on.png'),linear-gradient(top, $offwhite 0%, #E5E5E5 100%));
border-bottom: $borderbottom solid #F31A35;
a { color: $red;}
}
@mixin nav-button($icon){
background-color: #fff; // Old browsers
@include filter-gradient(#fff, #fff, vertical); // IE6-9
@include background-image(url('../images/'+$icon+'.png'),linear-gradient(top, #fff 0%, #fff 100%));
}
And then in the LI where the buttons are defined, I have
li {
&.dashboard {
@include nav-button('dashboard');
}
.dashboard &.dashboard {
@include nav-button-on('dashboard');
&:hover {
@include nav-button-on('dashboard');
}
}
}
HTML:
<body class="dashboard">
<div id="nav">
<ul>
<li class="first dashboard"><a href="/index.php">Dashboard</a></li>
<li class="challenges"><a href="/challenges.php">Challenges & Teams</a></li>
<li class="goals"><a href="/goals.php">Goals</a></li>
<li class="activity"><a href="/my-activity.php">My Activity</a></li>
<li class="destinations"><a href="/destinations.php">Destinations</a></li>
<li class="fitness last"><a href="/fitness-resources.php">Fitness Resources</a></li>
</ul>
</div>
This seems a bit convoluted, I was wondering if anyone had any advice to streamline this at all.
NOTE: I had to add the white-to-white gradient, since when hovering over a solid-color background with the gradient hover state caused a flash.
There are a number of things to improve here:
Are you really dealing with that hierarchy of dashboard
classes? For example, you're currently compiling to:
li.dashboard {
...
}
li .dashboard li.dashboard {
...
}
This seems wrong or at least poorly structured. Perhaps you could simplify things here.
Assuming you need this for each of your nav <li>
elements, DRY it up with an iterated mixin:
li {
@each $item in dashboard, challenges, goals, activity, destinations, fitness {
&.#{$item} {
@include nav-button($item);
}
.#{$item} &.#{$item} {
@include nav-button-on($item);
&:hover {
@include nav-button-on($item);
}
}
}
}
But #2 is not actually the best way. Use placeholders rather than mixins for this kind of stuff, or combine the two. I'd do something like this:
%nav-button {
background-color: #fff; // Old browsers
@include filter-gradient(#fff, #fff, vertical); // IE6-9
}
%nav-button-on {
background-color: #2f3684; // Old browsers
@include filter-gradient($offwhite, #E5E5E5, vertical); // IE6-9
border-bottom: $borderbottom solid #F31A35;
a { color: $red;}
}
@mixin li-image($icon) {
@include background-image(url('../images/'+$icon+'.png'),linear-gradient(top, #fff 0%, #fff 100%));
}
@mixin li-image-on($icon) {
@include background-image(url('../images/'+$icon+'-on.png'),linear-gradient(top, $offwhite 0%, #E5E5E5 100%));
}
@each $item in dashboard, challenges, goals, activity, destinations, fitness {
body.#{$item} li, li.#{$item}:hover {
@extend %nav-button-on;
@include li-image-on($item);
}
li.#{$item} {
@extend %nav-button;
@include li-image($item);
}
}
Compare the outputs and maintainability of these and I think you'll find this quite a bit more streamlined!