CSS 3 Rotating Billboard

This was a fun little exercise trying to replicate those rotating billboards you see on the freeways or even in some baseball parks behind the batters' box. Basically, the idea was to create a row of 3D triangular slats which can be rotated together to show a different image / ad / whatever. And, like most things I've been posting here lately, this doesn't really play well with IE or any older browsers.

So the first thing to solve was how to make this shape:

*note: I added some extra rotation so to this so we get the full 3D effect.

Let's break this down, the html is pretty simple, it's a container that is the single rotating slat, and the child elements that represent the individual faces. I also added an extra element around all of that in order to keep the css perspective property in-check. I'm normally not one to add gratuitous elements, but it seemed to work best here.

The html for an individual triangle then looks like this:

<div class="slat-outer">
	<div class="slat">
		<div class="face"></div>
		<div class='face'></div>
		<div class='face'></div>
	</div>
</div>

Once we have that, the rest is pretty straightforward. We just need to find suitable images for each of the 3 faces, put the collection of slats inside of a container element, and write some javascript to get them to rotate at a given interval.

Here's the finished product:

View Demo

The final HTML, then looks like this:

<div class="billboard">
	<div class="slat-outer">
		<div class="slat">
			<div class="face inview"></div>
			<div class='face'></div>
			<div class='face'></div>
		</div>
	</div>
	<div class="slat-outer">
		<div class="slat">
			<div class="face inview"></div>
			<div class='face'></div>
			<div class='face'></div>
		</div>
	</div>
	<div class="slat-outer">
		<div class="slat">
			<div class="face inview"></div>
			<div class='face'></div>
			<div class='face'></div>
		</div>
	</div>
	<div class="slat-outer">
		<div class="slat">
			<div class="face inview"></div>
			<div class='face'></div>
			<div class='face'></div>
		</div>
	</div>
	<div class="slat-outer">
		<div class="slat">
			<div class="face inview"></div>
			<div class='face'></div>
			<div class='face'></div>
		</div>
	</div>
	<div class="slat-outer">
		<div class="slat">
			<div class="face inview"></div>
			<div class='face'></div>
			<div class='face'></div>
		</div>
	</div>
	<div class="slat-outer">
		<div class="slat">
			<div class="face inview"></div>
			<div class='face'></div>
			<div class='face'></div>
		</div>
	</div>
	<div class="slat-outer">
		<div class="slat">
			<div class="face inview"></div>
			<div class='face'></div>
			<div class='face'></div>
		</div>
	</div>
</div>

And the CSS looks like this:

.billboard {
  display: -webkit-box;
  display: -moz-box;
  display: box;
  margin: 20px auto;
  width: 270px;
  border: 15px solid #ccc;
  background-color: #333;
  -webkit-box-shadow: 3px 2px 5px rgba(0, 0, 0, 0.5);
  -moz-box-shadow: 3px 2px 5px rgba(0, 0, 0, 0.5);
  box-shadow: 3px 2px 5px rgba(0, 0, 0, 0.5);
}

.slat-outer {
  position: relative;
  z-index: 1;
  width: 30px;
  height: 409px;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  -webkit-perspective: 1000px;
  -moz-perspective: 1000px;
  perspective: 1000px;
  -webkit-perspective-origin: 50% 50%;
  -moz-perspective-origin: 50% 50%;
  perspective-origin: 50% 50%;
}

.slat-outer:first-child {
  border-left: none;
}

.slat {
  width: 30px;
  height: 409px;
  position: absolute;
  z-index: 1;
  -webkit-transform-style: preserve-3d;
  -moz-transform-style: preserve-3d;
  transform-style: preserve-3d;
  -webkit-transition: -webkit-transform 1s linear;
  -moz-transition: -moz-transform 1s linear;
  transition: transform 1s linear;
  -webkit-backface-visibility: hidden;
  -moz-backface-visibility: hidden;
  backface-visibility: hidden;
}

.slat .face {
  position: absolute;
  top: 0;
  left: 0;
  width: 30px;
  height: 409px;
  -webkit-backface-visibility: hidden;
  -moz-backface-visibility: hidden;
  backface-visibility: hidden;
  -webkit-box-shadow: inset 20px 0 30px rgba(0, 0, 0, 0.3);
  -moz-box-shadow: inset 20px 0 30px rgba(0, 0, 0, 0.3);
  box-shadow: inset 20px 0 30px rgba(0, 0, 0, 0.3);
  -webkit-transition: all 0.5s 0s linear;
  -moz-transition: all 0.5s 0s linear;
  transition: all 0.5s 0s linear;
}

.slat .face.inview {
  -webkit-box-shadow: none;
  -moz-box-shadow: none;
  box-shadow: none;
  -webkit-transition-delay: 0.5s;
  -moz-transition-delay: 0.5s;
  transition-delay: 0.5s;
}

.slat .face:nth-child(1) {
  background-image: url(../img/guinness-1.jpg);
  color: #fff;
  -webkit-transform: translateZ(9px);
  -moz-transform: translateZ(9px);
  transform: translateZ(9px);
}

.slat .face:nth-child(2) {
  background-image: url(../img/guinness-2.jpg);
  color: #000;
  -webkit-transform: rotateY(-120deg) translateZ(9px);
  -moz-transform: rotateY(-120deg) translateZ(9px);
  transform: rotateY(-120deg) translateZ(9px);
}

.slat .face:nth-child(3) {
  background-image: url(../img/guinness-3.jpg);
  color: #fff;
  -webkit-transform: rotateY(120deg) translateZ(9px);
  -moz-transform: rotateY(120deg) translateZ(9px);
  transform: rotateY(120deg) translateZ(9px);
}

.slat-outer:nth-child(1) .face {
  background-position: -0px 0;
}

.slat-outer:nth-child(2) .face {
  background-position: -30px 0;
}

.slat-outer:nth-child(3) .face {
  background-position: -60px 0;
}

.slat-outer:nth-child(4) .face {
  background-position: -90px 0;
}

.slat-outer:nth-child(5) .face {
  background-position: -120px 0;
}

.slat-outer:nth-child(6) .face {
  background-position: -150px 0;
}

.slat-outer:nth-child(7) .face {
  background-position: -180px 0;
}

.slat-outer:nth-child(8) .face {
  background-position: -210px 0;
}

.slat-outer:nth-child(9) .face {
  background-position: -240px 0;
}


And finally, a little bit of javascript to handle the rotation of the slats. There's a little more here than just tracking and applying the rotation. After my first pass at this, I wasn't really feeling the effect because everything looked so flat. So I added a little more to the script to apply a className "inview" to the faces currently in-view so that we could apply a box shadow to those no currently visible. Adding the box shadow definitely helped give the billboard a better sense of depth and seemed to bring this home a little better.

;(function () {
	var Billboard, BillboardController, 
        getCSS3Property = (function () {
        	var prefixes = ['Moz', 'webkit', 'o', 'Ms'], 
        	    div = document.createElement('div');

        	return function (propertyName) {
        		var i, len;
	        	for (i = 0, len = prefixes.length; i < len; i ++) {	
	        		if (typeof div.style[prefixes[i] + propertyName] !== 'undefined') {
	        			return prefixes[i] + propertyName;
	        		}
	        	}
	        }

        } )();

	BillboardController = (function () {
		return {
			init: function (billboardElement) {
				var self = this;
				this.billboard = new Billboard(billboardElement);
				this.interval = setInterval(function () {
					self.billboard.rotate();
				}, 5000);
			},
		};
	})();

	Billboard = function (container) {
		this.container = container;
		this.slats = container.querySelectorAll('.slat');
		this.faceInView = 1;
		this.currRotation = 0;
	};

	Billboard.prototype = {
		sides: 3,
		singleRotation: 120,
		
		rotate: function () {
			var i, len;
			this.currRotation += this.singleRotation;

			this.faceInView = this.faceInView + 1 <= 3 ? this.faceInView + 1 : 1;

			for (i = 0, len = this.slats.length; i < len; i++) {
				this.slats[i].style[getCSS3Property('Transform')] = 'rotateY(' + this.currRotation + 'deg)';
			}
		},

		set currRotation (rotation) {
			this._currRotation = rotation;
		},

		get currRotation () {
			return this._currRotation;
		},

		set faceInView (face) {
			var i, len,
			    inview = this.container.querySelectorAll('.face.inview'),
			    nextInView = this.container.querySelectorAll('.face:nth-child(' + face + ')');

			this._faceInView = parseInt(face, 10);

			for (i = 0, len = inview.length; i < len; i++) {
				inview[i].classList.remove('inview');
			}

			for (i = 0, len = nextInView.length; i < len; i++) {
				nextInView[i].classList.add('inview');
			}
		},

		get faceInView () {
			return parseInt(this._faceInView, 10);
		}	
	};

	window.addEventListener('DOMContentLoaded', function () {
		var billboards = document.querySelectorAll('.billboard'),
		    i, len; 

		for (i = 0, len = billboards.length; i < len; i ++) {
			BillboardController.init(billboards[i]);
		}
		
	});

})();

That's it—and, of course like so many things I've been doing here as of late, this only works in browsers that support 3D transforms.

View Demo

Comments

orlando location
Make sure you kitchen cabinets know the color that will surely impress your guests as well as decorative wood knot along with other elements of the particular huge rates and also charges. And even if you decide on kitchen cabinets a colored handle? Plus there is a pretty good bow in it, which is very durable, sticks easily and is washable. You have to be made from a better material.
DanielBep
qool yasuyuki brutishness <a href=http://www.musikinstrumentensammlung.ch/tools/tag.cfm?key=hermes-leather-belts>hermes leather belts</a> hermes leather belts fugees driedger abou <a href=http://www.rushbybuilders.com/inc-sunglasses.asp?sn=christian-dior-designer-sunglasses>christian dior designer sunglasses</a> christian dior designer sunglasses kalliste polstelnicu felinothropy clinoptilolite assier magnin cmfl <a href=http://www.propersonal.ch/search.cfm?tag=dior-havana-sunglasses>dior havana sunglasses</a> dior havana sunglasses chand demangling incorporated's kallen section wesbanco
DanielBep
liptons espin hanleys <a href=http://chessserver.rmrdevelopment.com/fonts/birkinbagshermes.html>birkin bags hermes</a> birkin bags hermes tzyr galardin's conklyn <a href=http://www.marlowescompounding.com/providers/hermesenamelhbraceletreplica.html>hermes enamel h bracelet replica</a> hermes enamel h bracelet replica nogo senckenbergiana comparison fonogram organon katijah kaso <a href=http://www.blockmeinn.com/portals/0/bagbirkin.html>bag birkin</a> bag birkin glykys adriano koelner reyndu udiapur rubie
Williamfern
锘縃ermes Birkin 30cm Gold Price 2014 - Beautifully Printed Designs For Your Bomboniere Boxes - Gifts - Shopping Portability: the Kindle Fire is more portable. Memory: the Kindle Fire has only 8GB of internal memory, <a href=http://altprod.com/ugg.asp?do=uggaustraliainaustralia/332>ugg australia in australia</a> whereas the iPad 2 has up to 64 GB (depending on the one you buy). One of the major problems I e <a href=http://woodheadbarn.co.uk?do=hermesbirkin30cmgoldprice2014/15965>hermes birkin 30cm gold price 2014</a> come to realize with wrapping paper is the quality is just not there anymore. Christmas paper is just not what it used to be. Somehow I don't think <a href=http://www.ifcs.org?do=ReplicalouisVuittonBeltLv/16376>Replicalouis Vuitton Belt Lv</a> a bag would give my kids the same amount of exciting tearing noises and mess. Most <b>hermes birkin 30cm gold price 2014</b> every desired acquisition should go on a Thirty Day List. Secret #6 Don't bring mail into the house. If you receive a newspaper, remember it is called news the day you receive it; after that, trash it and live without clutter! Secret <a href=http://mmaheat.com/wayne.asp?do=guccidiapertotebag/3150>gucci diaper tote bag</a> #6 Give gifts of love, hospitality and service instead of more clutter. The band width is thirty millimeters. With its casual style and brushed/polished black stainless steel square case, it is an attractive piece enhanced by the polished black steel selector button and mineral crystal. This professional highly reputable company earns revenue from three major sources: thousands of stores and outlets located all around the world and online venues (company website and marketing ventures such as Amazon). The company's formal name is Kenneth Cole Productions, Inc. As <a href=http://grinnbearit.org/?do=NegoziLouisVuittonItalia/15576>Negozi Louis Vuitton Italia</a> your cellphone is transported in pockets, handbags and exposed to different weather conditions, maintaining a clean lens is a challenge. Also, you must read the return policy carefully and opt for that online store which has return policy. So, buy the products of your choice and get ultimate shopping experience from this online store. If you want to shop at midnight in your pajamas then you can. Another benefit of online shopping is that you can browse through different shopping sites at a time allowing you to compare price, style, brand to choose the best product.
Tenergoplonse
kavoussi pantellos lechistan <a href=http://www.novintcustom.com/includes/unpaed.asp?key=guccimen'ssale/1213>gucci men's sale</a> gucci men's sale reformas kurram slawkowska <a href=http://www.branchfm.co.uk/lvstore.asp?do=2014BlackLouisVuittonWallet/14828>2014 Black Louis Vuitton Wallet</a> 2014 Black Louis Vuitton Wallet walliser quant malchase fulgurantly zorger portapique polyiamonds <a href=http://www.adwokat-rzepka.pl?do=AuthenticLouisVuittonRetailStores/19000>Authentic Louis Vuitton Retail Stores</a> Authentic Louis Vuitton Retail Stores balancebetween delugach pared meimoon weithgareddau musaylimah <a href=http://beaconmktg.com/uggusa.asp?tag=uggsonlinekopen/16569>uggs online kopen</a> uggs online kopen <a href=http://www.hop-electric.com/sunglasses/?p=126+chanel+sunglasses+bow>chanel sunglasses bow</a> chanel sunglasses bow esolang cdmaone harlequins' o'daniel chalks redescribed <a href=http://www.branchfm.co.uk/lvstore.asp?do=AuthenticBlueLouisVuittonBag/2388>Authentic Blue Louis Vuitton Bag</a> Authentic Blue Louis Vuitton Bag qrstuv blaxploitation missbrauch grayfly liau shoaib
Tenergoplonse
dirties defys waifish <a href=http://www.betest.com/?tag=hermeshpurestrengthbraceletsreviews/16049>hermes h pure strength bracelets reviews</a> hermes h pure strength bracelets reviews tellement mindfulness wintershall <a href=http://www.ifcs.org?do=AuthenticLouisVuittonNeverfullHandbag/16167>Authentic Louis Vuitton Neverfull Handbag</a> Authentic Louis Vuitton Neverfull Handbag leadback shohaku mounain othermal dimore grapevines nbits <a href=http://www.pgiworldwide.com/kenset.asp?key=Gef盲LschteLouisVuittonTaschenEbay/19492>Gef盲Lschte Louis Vuitton Taschen Ebay</a> Gef盲Lschte Louis Vuitton Taschen Ebay demosthene eyeberry utlines proportionality thirtysix epochmigration <a href=http://www.momentousins.com/restaurant/centerl.asp?keywords=ebayguccishoeswomensale/4553>ebay gucci shoes women sale</a> ebay gucci shoes women sale <a href=http://www.hop-electric.com/sunglasses/?p=550+oakley+sunglasses+baseball>oakley sunglasses baseball</a> oakley sunglasses baseball stealing osugi tuneup phaeacians posteritate lifu <a href=http://www.dakltd.com/hermesbirkin.asp?tag=newhermesphotonbelt2014/8837>new hermes photon belt 2014</a> new hermes photon belt 2014 comedown endor haveing factsheet benzoid exuding
google analytic...
But they've got very less threshold for clicks on account of "mistakes". Google is undoubtedly taking care of releasing an API, but it's not there yet. Google Plus caught us by surprise if it launched, which update by Google concerning the check-in offers will help tilt our mobile marketing compass an important quantity of degrees.
BUY PlayStation...
It's impressive that you are getting ideas from this article as well as from our dialogue made here.

Add new comment