Skip to content

Instantly share code, notes, and snippets.

@nathos
Last active September 25, 2015 17:47
Show Gist options
  • Save nathos/959764 to your computer and use it in GitHub Desktop.
Save nathos/959764 to your computer and use it in GitHub Desktop.
Compass fancy-hover - snazzy-looking image replacement hovers with an animated opacity ramp. Now using Compass sprites so you don't have to do the dirty work! See the demo at http://nathos.github.com/fancy-hovers/
@mixin fancy-hover($sprite_dir, $off_state, $hover_state, $speed: 0.3s)
$sprites: sprite-map("#{$sprite_dir}/*.png")
$width: image-width(sprite_file($sprites, $off_state))
$height: image-height(sprite_file($sprites, $off_state))
@include hide-text
width: $width
height: $height
background: sprite($sprites, $off_state) no-repeat
display: block
position: relative
span
width: $width
height: $height
background: sprite($sprites, $hover_state) no-repeat
display: block
position: absolute
top: 0
left: 0
opacity: 0
@include transition(opacity $speed ease-in-out)
.no-opacity &
visibility: hidden
&:hover span
opacity: 1
.no-opacity &
visibility: visible
<div class="fancy-hover-links">
<ul>
<li id='twitter'>
Twitter
<span></span>
<!-- don't forget this empty span! -->
</li>
<li id='facebook'>
Facebook
<span></span>
</li>
<li id='forrst'>
Forrst
<span></span>
</li>
<li id='rss'>
RSS
<span></span>
</li>
</ul>
</div>
// in this example, the "my_sprites" directory contains 8 pngs, 2 for each image
#twitter
// pass the sprite directory, the off state name, and the hover state name
// you can optionally pass a fourth argument for the duration of the fade
@include fancy-hover(my_sprites, twitter_off, twitter_on)
#facebook
// repeat for each pair of sprites you want to make fancy!
@include fancy-hover(my_sprites, facebook_off, facebook_on)
#forrst
@include fancy-hover(my_sprites, forrst_off, forrst_on)
#rss
@include fancy-hover(my_sprites, rss_off, rss_on)
@nathos
Copy link
Author

nathos commented May 6, 2011

Snazzy-looking image replacement hovers with animated opacity ramp.

The image should be a vertically oriented, 2-state sprite. It (sadly) does require an empty <span> in the element you mix into (see HTML snippet) -- I haven't found a way to properly animate pseudo elements yet.

Falls back to a visibility toggle for browsers that don't support the opacity property (requires Modernizr).

@chriseppstein
Copy link

It would be especially neat if you combined it with compass sprites ;)

@nathos
Copy link
Author

nathos commented May 6, 2011

@chriseppstein: I was just thinking that! In this case I already had some manual sprites done up.

I'll experiment and see what I can come up with :)

@nathos
Copy link
Author

nathos commented Jun 11, 2011

@chriseppstein: I've updated the mixin to use Compass sprites now :)

For anyone not familiar with Compass sprites: Just pass in the name of a directory of PNG images, and the filenames (sans extension) for the off & hover states.

A sprite sheet will be generated automatically, and the mixin handles all the background positioning. It's magic!

See the demo at http://nathos.github.com/fancy-hovers/

@scottdavis
Copy link

thats freaking awesome im glad someone is doing cool things with sprites =D

@avclark
Copy link

avclark commented Mar 28, 2012

This is great man. I tried to convert it to SCSS, but am getting errors. Can you mix SASS and SCSS with compass?

@nathos
Copy link
Author

nathos commented Mar 28, 2012

@avclark: you can only use a single syntax in a file (determined by file extension).

If you're converting this to SCSS syntax, be sure to change the shorthand mixin syntax + to the full @include.

Alternatively, "sass-convert" command line utility should also be able to do the conversion for you automatically.

@avclark
Copy link

avclark commented Mar 28, 2012

Yeah, I know you can only use one syntax within the same file. I was curious if it would work if I named this file _mixins.sass for example and then had compass import it into my main screen.scss. It doesn't seem to be. I'll try that sass-convert tool. Thanks.

@nathos
Copy link
Author

nathos commented Mar 28, 2012

@avclark: importing as you described should work fine.

Make sure that Compass is loaded before this import, and that the necessary mixins (in this case CSS3 Transition) are in fact loaded. (error message should tell you if there's a problem there).

@avclark
Copy link

avclark commented Mar 28, 2012

It worked. Thanks!

@avclark
Copy link

avclark commented Mar 28, 2012

How hard would it be to add support in this for $offset-x and $y-offset?

@nathos
Copy link
Author

nathos commented Mar 28, 2012

Should be pretty easy. Just add the two variables to the fancy-hover mixin declaration, then make sure to pass those variables to both instances of sprite.

@avclark
Copy link

avclark commented Mar 29, 2012

So, I just realized that using this mixin means that I don't need to generate the sprites with compass. e.g.:

@import "sub-nav/*.png";
@include all-sub-nav-sprites;

However, how would I use any of the config variables with this mixing? I'm trying to accomplish this:

$sub-nav-spacing: 20px;
@import "sub-nav/*.png";
@include all-sub-nav-sprites;

Thanks.

@avclark
Copy link

avclark commented Mar 30, 2012

I figured it out. I guess there are two ways of generating sprites. The method I mentioned above (e.g. @import "icon/.png";) and the way you are doing it in your mixing (e.g. $icon: sprite-map("icon/.png");). I'm not really sure what the differences are, but the config variables are different for the two methods.

@Elloro
Copy link

Elloro commented Feb 20, 2013

This is really great, i am trying to implement this, but i cannot manage to do it.

I am relatively new to compass and sublime text 2 so I am experimenting with your function.

How do i include the mixin? Where do i put the file hover-demo.sass? Codekit gives errors on compiling.

Thnx.

@nathos
Copy link
Author

nathos commented Feb 20, 2013

@Elloro: the mixin is included by the line @include fancy-hover(my_sprites, twitter_off, twitter_on) (in this case, for the twitter icon).

Remember, my_sprites is the name of a directory with the sprite images (PNG files) inside it. This directory should be inside your images directory (as configured w/ Compass).

The contents of hover-demo.sass would just go inside your main stylesheet. Also remember that with Sass, you need to declare your mixins before including them, so make sure that the contents of fancy-hover-mixin.sass are before the @include statement.

@Elloro
Copy link

Elloro commented Feb 21, 2013

I was using SCSS so i needed to convert your sass file. Everything worked except the fading. This is what i have:

@import "compass/reset";
@import "compass/css3";
@import "compass/css3/pie";
@import "compass/typography/links/link-colors";
@import "compass/typography/links/hover-link";
@import "compass/typography/lists";
@import "compass/css3/transition";
@import "compass/utilities/general/clearfix";
@import "compass/typography/text/replacement";
@import "compass/css3/opacity";

@mixin fancy-hover($sprite_dir, $off_state, $hover_state, $speed: 1s) {
  $sprites: sprite-map("#{$sprite_dir}/*.png");
  $width: image-width(sprite_file($sprites, $off_state));
  $height: image-height(sprite_file($sprites, $off_state));
  @include hide-text;
  width: $width;
  height: $height;
  background: sprite($sprites, $off_state) no-repeat;
  display: block;
  position: relative;
  span {
    width: $width;
    height: $height;
    background: sprite($sprites, $hover_state) no-repeat;
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    opacity: 0;
    @include transition(opacity, $speed, ease-in-out);
    .no-opacity & {
      visibility: hidden;
    }
  }
  &:hover span {
    opacity: 1;
    .no-opacity & {
      visibility: visible;
    }
  }
}

#twitter {@include fancy-hover(my_sprites, twitter_off, twitter_on, 2);}

@nathos
Copy link
Author

nathos commented Feb 21, 2013

@Elloro: my apologies, there was a change in Compass a while back that changes the syntax of the transition mixin to take multiple transitions at once. This means you can either use the single-transition mixin instead, or change the list passed to transition to be space-separated.

I've updated the Gist with the latter, like so:

@include transition(opacity $speed ease-in-out)

@Elloro
Copy link

Elloro commented Feb 25, 2013

YES did the trick! Thnx!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment