Create an Exploding Logo with CSS3 and MooTools or jQuery
When MooTools contributor and moo4q creator Ryan Florence first showed me his outstanding CSS animation post, I was floored. His exploding text effect is an amazing example of the power of CSS3 and a dash of JavaScript. I wanted to implement this effect on my new blog redesign but with a bit more pop, so I wrote some MooTools code to take static image and make it an animated, exploding masterpiece. Let me show you how I did it, and as a bonus, I'm created a snippet of jQuery that accomplishes the same effect.
Ryan Florence's Animation Library
Ryan's CSS animation library, available with vanilla JavaScript, MooTools, or jQuery, and can only be described as a fucking work of art. His animation library is mobile-enabled, works a variety of A-grade browsers, and is very compact. Download and study Ryan's animation library before proceeding with this post.
Ryan's post also features an awesome demo and a few helpful functions. A few of these functions include:
// reset transforms to this var zeros = {x:0, y:0, z:0}; // Implement animation methods on the element prototype Element.implement({ // Scatter elements all over the place scatter: function(){ return this.translate({ x: Number.random(-1000, 1000), y: Number.random(-1000, 1000), z: Number.random(-500, 500) }).rotate({ x: Number.random(-720, 720), y: Number.random(-720, 720), z: Number.random(-720, 720) }); }, // Return them to their original state unscatter: function(){ return this.translate(zeros).rotate(zeros); }, // Frighten the image! AHHHHHHHH! frighten: function(d){ this.setTransition('timing-function', 'ease-out').scatter(); setTimeout(function(){ this.setTransition('timing-function', 'ease-in-out').unscatter(); }.bind(this), 500); return this; }, // Zoooooom into me zoom: function(delay){ var self = this; this.scale(0.01); setTimeout(function(){ self.setTransition({ property: 'transform', duration: '250ms', 'timing-function': 'ease-out' }).scale(1.2); setTimeout(function(){ self.setTransition('duration', '100ms').scale(1); }, 250) }, delay); }, // Create a slider makeSlider: function(){ var open = false, next = this.getNext(), height = next.getScrollSize().y, transition = { property: 'height', duration: '500ms', transition: 'ease-out' }; next.setTransition(transition); this.addEvent('click', function(){ next.setStyle('height', open ? 0 : height); open = !open; }); }, // Scatter, come back fromChaos: (function(x){ var delay = 0; return function(){ var element = this; //element.scatter(); setTimeout(function(){ element.setTransition({ property: 'transform', duration: '500ms', 'timing-function': 'ease-out' }); setTimeout(function(){ element.unscatter(); element.addEvents({ mouseenter: element.frighten.bind(element), touchstart: element.frighten.bind(element) }); }, delay += x); }, x); } }()) });
Now let's jump on the exploding logo!
The HTML
The exploding element can be of any type, but for the purposes of this example, we'll use an A element with a background image:
<a href="/" id="homeLogo">David Walsh Blog</a>
Make sure the element you use is a block element, or styled to be block.
The CSS
The original element should be styled to size (width and height) with the background image that we'll use as the exploding image:
a#homeLogo { width:300px; height:233px; text-indent:-3000px; background:url(/wp-content/themes/2k11/images/homeLogo.png) 0 0 no-repeat; display:block; z-index:2; } a#homeLogo span { float:left; display:block; background-image:url(/wp-content/themes/2k11/images/homeLogo.png); background-repeat:no-repeat; } .clear { clear:both; }
Remember to set the text-indent setting so that the link text will not display. The explosion shards will be JavaScript-generated SPAN elements which are displayed as in block format. Note that the SPAN has the same background image as the A element -- we'll simply modify the background position of the element to act as the piece of the logo that each SPAN represents.
The MooTools JavaScript
The first step is putting together a few variables we'll need to to calculate element dimensions:
// Get the proper CSS prefix from the page var cssPrefix = false; switch(Browser.name) { // Implement only for Chrome, Firefox, and Safari case "safari": case "chrome": cssPrefix = "webkit"; break; case "firefox": cssPrefix = "moz"; break; } if(cssPrefix) { // 300 x 233 var cols = 10; // Desired columns var rows = 8; // Desired rows var totalWidth = 300; // Logo width var totalHeight = 233; // Logo height var singleWidth = Math.ceil(totalWidth / cols); // Shard width var singleHeight = Math.ceil(totalHeight / rows); // Shard height var shards = []; // Array of SPANs
You'll note that I've explicitly set the number of columns and rows I want. You don't want the shards to be too large or too small, so feel free to experiment. You could probably use another calculation to get column and row numbers, but I'll leave that up to you.
The next step is looping through each row and column, creating a new SPAN element for each shard. The background position, width, and height of the SPAN will be calculated with the ... calculations ... we ... calculated ... above.
// Remove the text and background image from the logo var logo = document.id("homeLogo").set("html","").setStyles({ backgroundImage: "none" }); // For every desired row rows.times(function(rowIndex) { // For every desired column cols.times(function(colIndex) { // Create a SPAN element with the proper CSS settings // Width, height, browser-specific CSS var element = new Element("span",{ style: "width:" + (singleWidth) + "px;height:" + (singleHeight) + "px;background-position:-" + (singleHeight * colIndex) + "px -" + (singleWidth * rowIndex) + "px;-" + cssPrefix + "-transition-property: -" + cssPrefix + "-transform; -" + cssPrefix + "-transition-duration: 200ms; -" + cssPrefix + "-transition-timing-function: ease-out; -" + cssPrefix + "-transform: translateX(0%) translateY(0%) translateZ(0px) rotateX(0deg) rotateY(0deg) rotate(0deg);" }).inject(logo); // Save it shards.push(element); }); // Create a DIV clear for next row new Element("div",{ clear: "clear" }).inject(logo); });
With the SPAN elements, you'll note that several CSS3 properties are being set to it, allowing the browser to do its magic. Using CSS3 is much less resource-consuming within the browser than using JavaScript to do all of the animation.
The last step is calling the fromChaos method provided by Ryan Florence's CSS animation code to set into motion the madness!
// Chaos! $$(shards).fromChaos(1000);
There you have it! A completely automated method of exploding an image using CSS3 and MooTools JavaScript!
The jQuery JavaScript
Ryan also wrote the CSS animation code in jQuery so you can easily create a comparable effect with jQuery!
Number.random = function(min, max){ return Math.floor(Math.random() * (max - min + 1) + min); }; var zeros = {x:0, y:0, z:0}; jQuery.extend(jQuery.fn, { scatter: function(){ return this.translate({ x: Number.random(-1000, 1000), y: Number.random(-1000, 1000), z: Number.random(-500, 500) }).rotate({ x: Number.random(-720, 720), y: Number.random(-720, 720), z: Number.random(-720, 720) }); }, unscatter: function(){ return this.translate(zeros).rotate(zeros); }, frighten: function(d){ var self = this; this.setTransition('timing-function', 'ease-out').scatter(); setTimeout(function(){ self.setTransition('timing-function', 'ease-in-out').unscatter(); }, 500); return this; }, zoom: function(delay){ var self = this; this.scale(0.01); setTimeout(function(){ self.setTransition({ property: 'transform', duration: '250ms', 'timing-function': 'ease-out' }).scale(1.2); setTimeout(function(){ self.setTransition('duration', '100ms').scale(1); }, 250) }, delay); return this; }, makeSlider: function(){ return this.each(function(){ var $this = $(this), open = false, next = $this.next(), height = next.attr('scrollHeight'), transition = { property: 'height', duration: '500ms', transition: 'ease-out' }; next.setTransition(transition); $this.bind('click', function(){ next.css('height', open ? 0 : height); open = !open; }); }) }, fromChaos: (function(){ var delay = 0; return function(){ return this.each(function(){ var element = $(this); //element.scatter(); setTimeout(function(){ element.setTransition({ property: 'transform', duration: '500ms', 'timing-function': 'ease-out' }); setTimeout(function(){ element.unscatter(); element.bind({ mouseenter: jQuery.proxy(element.frighten, element), touchstart: jQuery.proxy(element.frighten, element) }); }, delay += 100); }, 1000); }) } }()) }); // When the DOM is ready... $(document).ready(function() { // Get the proper CSS prefix var cssPrefix = false; if(jQuery.browser.webkit) { cssPrefix = "webkit"; } else if(jQuery.browser.mozilla) { cssPrefix = "moz"; } // If we support this browser if(cssPrefix) { // 300 x 233 var cols = 10; // Desired columns var rows = 8; // Desired rows var totalWidth = 300; // Logo width var totalHeight = 233; // Logo height var singleWidth = Math.ceil(totalWidth / cols); // Shard width var singleHeight = Math.ceil(totalHeight / rows); // Shard height // Remove the text and background image from the logo var logo = jQuery("#homeLogo").css("backgroundImage","none").html(""); // For every desired row for(x = 0; x < rows; x++) { var last; //For every desired column for(y = 0; y < cols; y++) { // Create a SPAN element with the proper CSS settings // Width, height, browser-specific CSS last = jQuery("<span />").attr("style","width:" + (singleWidth) + "px;height:" + (singleHeight) + "px;background-position:-" + (singleHeight * y) + "px -" + (singleWidth * x) + "px;-" + cssPrefix + "-transition-property: -" + cssPrefix + "-transform; -" + cssPrefix + "-transition-duration: 200ms; -" + cssPrefix + "-transition-timing-function: ease-out; -" + cssPrefix + "-transform: translateX(0%) translateY(0%) translateZ(0px) rotateX(0deg) rotateY(0deg) rotate(0deg);"); // Insert into DOM logo.append(last); } // Create a DIV clear for row last.append(jQuery("<div />").addClass("clear")); } // Chaos! jQuery("#homeLogo span").fromChaos(); } });
Not as beautiful as the MooTools code, of course, but still effective!
And there you have it: CSS animations, JavaScript, and dynamic effects. My favorite part of this effect is how little code is involved. You get a lot of bang with your buck with this. Of course, using this effect everywhere would surely get groans so use it wisely!
Hasn’t your logo been exploding for about a month or so?
This is really nice, adding it ;)
looks really cool in webkit browsers, sadly awful in Firefox and Opera just mushes your face lol. Shame Firefox isn’t keeping up with Safai & GC these days