JavaScript Hulu Content Slider with jQuery Cycle & CSS3Hulu.com has a stylish, fully-featured content slider on it’s homepage that was built using Flash. I set out to re-create this using HTML, CSS3, JavaScript and jQuery. Here are the results.

See the slideshow source in action!

Requirements

  1. Slide left to right, and seamlessly restart at the beginning from the last slide
  2. Slide the full width of the viewport like Hulu, even after a browser resize event
  3. A paged, or paginated, navigation to browse through slides
  4. A next and previous icons as an alternative navigation method
  5. Unobtrusive and easy to maintain
  6. Handle any number of slides
  7. Modular, extensible codebase that can easily and quickly be modified for re-use
  8. Semantic in structure, and search engine friendly

HTML

Each element marked with a class of slide will be included in the rotation. Each slide is relatively positioned to allow for easy customization using absolute positioning inside of this relative DIV. My demonstration contains simple linked images, but you could add whatever you would like by targeting the unique identifiers for each slide or by adding your own re-usable classes to the mix (.video, .featured, etc.).

SEO descriptive keywords / explanation of graphic here
SEO descriptive keywords / explanation of graphic here
SEO descriptive keywords / explanation of graphic here

CSS

I’ve used the box-shadow, rgba() and border-radius CSS3 properties to visually enhance the design. If a browser doesn’t support these the design will gracefully degrade.

/*** Slide container ***/
#cycle-fullwidth {
	width:100%;
	height:300px;
	position:relative;
	overflow:hidden;
	background:url(fullwidth-cycle-bg.png) top left repeat-x; /* Avoid white glitches when sliding */
}
#cycle-fullwidth .inner {
	width:960px;
	margin:0 auto;
}

/*** Slide content ***/
#cycle-fullwidth .slide {
	width:100%;
	background:url(fullwidth-cycle-bg.png) top left repeat-x;
}
#cycle-fullwidth .slide a, 
#cycle-fullwidth .slide img {
	display:block;
	width:960px;
	height:300px;
	border:none;
}

/*** Bottom shadow overlay for visual effect ***/
#cycle-fullwidth .inner-shdw-bottom {
	width:100%;
	position:absolute;
	bottom:0;
	height:25px;
	z-index:10;
	background:url(fullwidth-cycle-bottom.png) bottom left repeat-x;
}
#cycle-fullwidth .inner-shdw-top {
	width:100%;
	position:absolute;
	top:0;
	height:13px;
	z-index:10;
	background:url(fullwidth-cycle-top.png) top left repeat-x;
}

/*** Pagination ***/
#cycle-pager {
	position:absolute;
	bottom:10px;
	left:46%;
	z-index:100;
}
#cycle-pager a {
	display:block;
	float:left;
	padding:5px;
	outline:none;
}
/** CSS3 circles for worthy browsers, squares for chumps */
#cycle-pager span {
	text-indent:-2000em;
	display:block;
	width:14px;
	height:14px;
	-moz-box-shadow:inset 0 2px 3px rgba(0,0,0,0.5); /** for Firefox 3.5+ */
	-webkit-box-shadow:inset 0 2px 3px rgba(0,0,0,0.75); /** for Safari and Chrome */
	box-shadow:inset 0 2px 3px rgba(0,0,0,0.75); /** CSS 3 Spec */
	background:#fff;
	background:rgba(255,255,255,0.65);
	-webkit-border-radius:7px;
	-moz-border-radius:7px;
	border-radius:7px;
}
#cycle-pager a:hover span {
	background:#ffcf00;
}
#cycle-pager a.activeSlide span,
#cycle-pager a:active span {
	background:#412f13;
	background:rgba(0,0,0,0.75);
	-moz-box-shadow:0 0 3px rgba(255,255,255,0.5); /** for Firefox 3.5+ */
	-webkit-box-shadow:0 0 3px rgba(255,255,255,0.75); /** for Safari and Chrome */
	box-shadow:0 0 3px rgba(255,255,255,0.75); /** CSS 3 Spec */
}

/*** Next and previous navigation ***/
#cycle-next,
#cycle-prev {
	z-index:100;
	display:block;
	position:absolute;
	width:18px;
	height:36px;
	outline:none;
	cursor:pointer;
	top:132px; /* Height of slide (300px) minus the height of the next/prev icon, divided by 2 vertically centers the icons */
	background-image:url(cycle-next-prev.png);
}
#cycle-next {
	right:10px;
	background-position:0 0;
}
#cycle-next:hover,
#cycle-next:active {
	background-position:0 -36px;
}
#cycle-prev {
	left:10px;
	background-position:0 -72px;
}
#cycle-prev:hover,
#cycle-prev:active {
	background-position:0 -108px;
}

JavaScript/jQuery

I’ve built this using the jQuery Cycle slideshow plugin because its well-supported and provides a great framework to build upon and customize as needed. You’ll need to download and a copy of the full (labeled “all”) jQuery Cycle plugin and include it in the HEAD section of your document after jQuery and before the following code.

/* 
*	Cycle plugin by Malsup - http://jquery.malsup.com/cycle/
*	Implementation by Kevin Leary - 
*/
(function($){ 
	$(function(){
		/** Add the next and previous buttons with JavaScript to gracefully degrade */
		var cycle_container = $('#cycle-fullwidth');
		cycle_container.append('
'); cycle_start(cycle_container, 0); /** Restart the slideshow when someone resizes the browser to ensure that sliding distance matches the correct viewport */ $(window).resize(function(){ var current_slide = cycle_container.find('.slide:visible').index(); if(window.console&&window.console.log) { console.log('current_slide'+current_slide); } cycle_container.cycle('destroy'); new_window_width = $(window).width(); cycle_container.find('.slide').width(new_window_width); cycle_start(cycle_container, current_slide); }); }); /** Cycle configurations */ function cycle_start(container, index){ var window_width = $(window).width(); container.find('.slide').width(window_width); if (container.length > 0){ container.cycle({ timeout: 5000, speed: 1000, pager: '#cycle-pager', prev: '#cycle-prev', next: '#cycle-next', slideExpr: '.slide', fx: 'scrollHorz', easeIn: 'linear', easeOut: 'swing', startingSlide: index, pagerAnchorBuilder: cycle_paginate, before: cycle_before_slide_change }); } } function cycle_paginate(ind, el) { return ''+ind+''; } function cycle_before_slide_change( currSlideElement, nextSlideElement, options, forwardFlag ) { // Hide previous and next buttons for the first and last slide accordingly var slide_elements = $('#cycle-fullwidth .slide'); if ( window.console && window.console.log ) console.log( 'Current slide: ' + slide_elements.index(nextSlideElement) ); // First slide if ( slide_elements.index(nextSlideElement) == 0 ) { $( options.prev ).hide(); $( options.next ).show(); } // Last slide else if ( slide_elements.index(nextSlideElement) == (slide_elements.size() - 1) ) { $( options.next ).hide(); $( options.prev ).show(); } else { $( options.prev + ', ' + options.next ).show(); } } })(jQuery);

See the slideshow source in action!

Browser Support & Resources

I’ve included Photoshop CS5 source files for the slideshow items and next and previous sprites just in case anyone wants them.

This has been cross browser tested for quality in:

  • Firefox 3.6
  • Google Chrome 9
  • Safari 5
  • Internet Explorer 8

If you have any suggestions, recommendations or requests please let me know by posting a comment
!

Updates

I’ve just added an additional callback function to hide the previous arrow on the first slide, and the next arrow on the last slide. This has been included in the demo and code above.