Treehouse

Google Extension Effect with CSS or jQuery or MooTools JavaScript

By on  

Both of the two great browser vendors, Google and Mozilla, have Extensions pages that utilize simple but classy animation effects to enhance the page. One of the extensions used by Google is a basic margin-top animation to switch between two panes: a graphic pane and a detail pane. I've taken a few moments to duplicate that effect with just CSS, and another enhanced version with jQuery and MooTools.

The Base HTML and CSS

I'm using minimal elements within this code since, theoretically, there would be many of these on a given page and large DOM trees can drastically effect page performance:

<div class="item">
	<a href="/angry-birds">
		<div class="item-billboard">
			<img src="angrybirds.jpg" />
			<h3>Angry Birds</h3>
		</div>
		<div class="item-detail">
			<p>There's more detail about the item inside this DIV!</p>
		</div>
	</a>
</div>

Remember that HTML5 says we can wrap block-level elements with A tags, so don't hate on me!

There's a fair amount of base CSS we need too:

.item {
	position: relative;
	width: 240px;
	overflow: hidden;
	border: 1px solid #ccc;
}
	.item {
		height: 200px;
	}
	
	.item a {
		text-decoration: none;
		color: #000;
	}
	
	.item-billboard, .item-detail {
		padding: 10px;
		height: 180px;
	}
	
	.item-billboard {
		margin-top: 0;
		background: #fff;
	}
		.item-billboard h3 {
			font-size: 13px;
			font-weight: bold;
			color: #262626;
			font-family: "Open Sans", arial, sans-serif;
		}
	
	.item-detail {
		background: #ececec;
	}

The only restriction with the CSS above is that we're explicitly setting a lesser height for the billboard and detail blocks because we're adding padding to them. We could use the full 200px height of the parent for each of those blocks, and wrap the content for each in an additional DIV, allowing for animating margin-top to 100%, but that would add 2 extra nodes per block.

The CSS-Only Method

Much like my Google Photo Stack post, the CSS-only version gets us 90% there. Browser-powered CSS animations give us the ability to animate to the second pane...

.item-billboard {
	margin-top: 0;
	background: #fff;
	
	/* add animations! */
	transition-property: margin-top;
	transition-duration: .5s;
}

/* animate on hover */
.itemCss:hover .item-billboard {
	margin-top: -200px;
}

Since the CSS transition settings are on the .billboard elements, the margin will animate both on hover and then back to its original state during mouseleave. Unfortunately you're out of luck if the client doesn't support CSS transitions. That's where we can use MooTools or jQuery to make it happen!

The jQuery and MooTools JavaScript

Overriding the CSS animation with a bit of JavaScript will allow the same animation in older browsers. We can jQuery or MooTools to make that happen:

// MooTools
window.addEvent("domready", function() {
	$$(".itemJs").addEvents({
		mouseenter: function() {
			var billboard = this.retrieve("billboardElement");
			if(!billboard) {
				billboard = this.getElements(".item-billboard")[0];
				this.store("billboardElement", billboard);
			}
			billboard.tween("margin-top", "-200px");
		},
		mouseleave: function() {
			this.retrieve("billboardElement").tween("margin-top", 0);
		}
	});
});

// jQuery
jQuery(document).ready(function() {
	jQuery(".itemJQuery").bind({
		mouseenter: function() {
			var self = jQuery(this), billboard = self.data("billboardElement");
			if(!billboard) {
				billboard = jQuery(jQuery(".item-billboard", this)[0]);
				self.data("billboardElement", billboard);
			}
			jQuery(billboard).stop().animate({
				"margin-top": "-200px"
			});
		},
		mouseleave: function() {
			jQuery(this).data("billboardElement").stop().animate({
				"margin-top": 0
			});
		}
	});
});

In each case, we lazy-find billboard elements when they're hovered over and animate them just as the CSS does. Simple!

I love the design of these blocks by Google. They provide a beautiful default view and allow for more detail when the user shows interest. I can see this strategy and effect being useful in many situations, as behind it is brilliant. A business that sells records could use the same sort of effect, for example. Well done to Google!

ydkjs-6.png

Recent Features

  • Create a CSS Cube

    CSS cubes really showcase what CSS has become over the years, evolving from simple color and dimension directives to a language capable of creating deep, creative visuals.  Add animation and you've got something really neat.  Unfortunately each CSS cube tutorial I've read is a bit...

  • CSS Animations Between Media Queries

    CSS animations are right up there with sliced bread. CSS animations are efficient because they can be hardware accelerated, they require no JavaScript overhead, and they are composed of very little CSS code. Quite often we add CSS transforms to elements via CSS during...

Incredible Demos

  • MooTools 1.2 Image Protector: dwProtector

    Image protection is a hot topic on the net these days, and why shouldn't it be? If you spent two hours designing an awesome graphic, would you want it ripped of in matter of seconds? Hell no! That's why I've created an image...

  • Multiple Background CSS Animations

    CSS background animation has been a hot topic for a long time, mostly because they look pretty sweet and don't require additional elements.  I was recently asked if it was possible to have multiple background animations on a given element and the answer is yes...with...

Discussion

  1. Alelo

    MT version is the smoothest for me(feeling – Chrome) CSS and jQ are a little bit too fast and dont know, doesnt feel right
    CSS : fasted + “laggy”
    jQ: fast (a little bit too fast)
    MT: perfect(slow and smooth)

    for me

    • Nelson

      I agree with you.
      MooTools has the smoothest experience.

  2. Ah I see you added in stop() to prevent animation queuing! Beat me to it… ;)

    However, can I ask why you have used $.data? Why is there a need to store the element?

    • The alternative is using a query to find the billboard element every time the parent is hovered.

  3. webbeloz

    is an interesting point to make a hidden form .. but the class “item-detail” should stop (fidex) when fully open .. . itemCss: hover. billboard-item {
    margin-top:-200px;
    }

  4. Alex

    For some reason my firefox v11 tab on windows 7 lags somewhat more with mootools than jquery…

  5. A small changes in the example of css:
    A bit more semantic markup, some negative delay with “ease” and another item with “ease-in-out”
    http://jsfiddle.net/kseso/XETSY/2/embedded/result/

  6. I also want to try this effect but i dont have enough knowledge to work with JS and Mootools. Please tell me how and where do i insert the JS code. Please do reply

  7. This works great David, thank you.
    I have implemented it on http://international.anahuacmayab.mx but for some reason on Chrome 21 works buggy (overlapping, blurred text, etc.). The problem seems to happen only when I go to the next billboard before the previous animation ends.
    The Chrome web store actually doesn’t overlap animations, it waits until a billboard’s animation ends before trigger the next one.
    My MooTools skills are very basic. Is possible to delay the billboard’s animation until previous animations ends?
    Thank you in advance.

    • In case someone’s experimenting the same issue, the fix was actually pretty easy. Just added the pseudo :pause(500) to the mouseover event.

      The complete code is like this:

      	$$(".item").addEvent('mouseenter:pause(510)', function(e) {
      		  var billboard = this.retrieve("billboardElement");
      		  if(!billboard) {
      			billboard = this.getElements(".item-billboard")[0];
      			this.store("billboardElement", billboard);
      		  }
      		  billboard.tween("margin-top", "-200px");
      		}
      	);
      	
      	$$(".item").addEvent('mouseleave', function(e) {
      		  this.retrieve("billboardElement").tween("margin-top", 0);
      		}
      	);
      

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!