Ricardo Zea
Ricardo Zea

Reputation: 10283

Sass: Create a "complex" mixin to use in different media queries

I'm new to Sass and since I'm not a programmer, wrapping my head around some of the concepts is a bit hard for me, so that's why I'm asking for help.

This should be an easy one for you Sass gurus.

I need to make a mixin that I can use in different media queries. This mixin is for the main nav of the site.

The scss looks like this:

/*Nav bar*/
a.menu-link { display:none; }       
.js nav[role=navigation] { max-height:0; }      
nav[role=navigation] ul { margin:0 0 0 -0.25em; border:none;
  & li { display:inline-block; margin:0 0.25em;
       & a { border:none; }
  }
}

I'm envisioning using the mixin like this: @include navBar, but I don't know if I'm oversimplifying it or what.

Any help is greatly appreciated.

Thanks.

Upvotes: 1

Views: 772

Answers (1)

cimmanon
cimmanon

Reputation: 68319

For your code block, this would be one way of writing that as a mixin:

@mixin navBar {
    a.menu-link { display:none; }

    .js & { max-height: 0; }

    ul { // note that the & isn't necessary here...
        margin: 0 0 0 -0.25em;
        border: none;

        li {
            display: inline-block;
            margin: 0 0.25em;
            a { border: none; }
        }
    }
}

nav[role=navigation] {
    @include navBar;
}

If you want to customize the appearance of your nav bar, you'll have to write duplicate selectors (maybe you want to have borders on your lis or have a special bg color on hover). It could be worse, but you wouldn't write your CSS by hand that way.

With the inclusion of nav[role=navigation] in your selector, that block of code looks a little too specific to me, since I might want a list of stuff to display inline but it isn't part of a nav element (maybe it's a tag cloud or a list of categories).

This is a mixin from my own library that only contains the barest essentials to turn a list into an inline list (of course, it doesn't have to be a list either, it could be a container with a bunch of divs in it if I wanted):

@mixin inline-menu($type: inline, $child: li) {
    @if $type == float {
        overflow: hidden;
    }

    > #{$child} {
        @if $type == float {
            float: left;
            //list-style: none;
        } @else {
            display: inline-block;
        }

        @content;

        a { white-space: nowrap }
    }
}

I would invoke it like this:

ul.drop-menu {
    margin: 0;
    padding: 0;

    a {
        color: red;
    }

    @include inline-menu {
        border: 1px solid red;
        > a {
            padding: .5em 1em;
            display: block;
        }

        &:hover > a {
            background: red;
            color: orange;
        }

        @include drop-menu {
            border: 1px solid;
            padding: 1em 1em 1em 2em;
            background: orange;
            color: red;
            margin: 0;
            left: -1px;
            z-index: 1;
        }
    }
}

Now, the advantage of doing it this way is that you don't end up with many (if any) duplicate selectors. If you want to add a border to your ul, it is completely exposed to you because the ul selector isn't part of the mixin at all: it is expected that the mixin is called from within some sort of container selector.

Here's the CSS that code generates:

ul.drop-menu {
  margin: 0;
  padding: 0;
}

ul.drop-menu a {
  color: red;
}

ul.drop-menu > li {
  display: inline-block;
  border: 1px solid red;
  position: relative;
}

ul.drop-menu > li > a {
  padding: .5em 1em;
  display: block;
}

ul.drop-menu > li:hover > a {
  background: red;
  color: orange;
}

ul.drop-menu > li ul {
  display: none;
}

ul.drop-menu > li:hover ul, ul.drop-menu > li.active ul {
  display: block;
  position: absolute;
  border: 1px solid;
  padding: 1em 1em 1em 2em;
  background: orange;
  color: red;
  margin: 0;
  left: -1px;
  z-index: 1;
}

ul.drop-menu > li a {
  white-space: nowrap;
}

No duplicate selectors in sight. The magic behind this mixin is the @content directive. Everything between the curly braces ({}) is contained within @content, which just needs to be invoked where appropriate.

Upvotes: 3

Related Questions