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!

Recent Features

  • By
    How I Stopped WordPress Comment Spam

    I love almost every part of being a tech blogger:  learning, preaching, bantering, researching.  The one part about blogging that I absolutely loathe:  dealing with SPAM comments.  For the past two years, my blog has registered 8,000+ SPAM comments per day.  PER DAY.  Bloating my database...

  • By
    Camera and Video Control with HTML5

    Client-side APIs on mobile and desktop devices are quickly providing the same APIs.  Of course our mobile devices got access to some of these APIs first, but those APIs are slowly making their way to the desktop.  One of those APIs is the getUserMedia API...

Incredible Demos

  • By
    Control Element Outline Position with outline-offset

    I was recently working on a project which featured tables that were keyboard navigable so obviously using cell outlining via traditional tabIndex=0 and element outlines was a big part of allowing the user navigate quickly and intelligently. Unfortunately I ran into a Firefox 3.6 bug...

  • By
    Introducing MooTools ScrollSide

    This post is a proof of concept post -- the functionality is yet to be perfected. Picture this: you've found yourself on a website that uses horizontal scrolling instead of vertical scrolling. It's an artistic site so you accept that the site scrolls left to right.

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!