Pull Out Content Panel with jQuery

In this tutorial we will create a content panel that slides out at a predefined scroll position. It will reveal a teaser with related content and it can be expanded […]

In this tutorial we will create a content panel that slides out at a predefined scroll position. It will reveal a teaser with related content and it can be expanded to full page size to show more. A custom slider allows to scroll through many items in the panel.

Depending on how many items can fit to the user’s screen, we will adapt the item container in order make the maximum number of items fit, centering it horizontally.

Since we want to use a little slider for the scrolling, we will be working with the jQuery UI library.

So, let’s get started with the markup.

The Markup

The HTML will have following structure:

<div class="pc_panel" id="pc_panel">
	<div class="pc_label expand"></div>
	<div class="pc_label close"></div>
	<div class="pc_title">More on this topic</div>
	<div id="pc_wrapper">
		<div id="pc_content">
			<div class="pc_item">
				<h2>Annotation Overlay Effect with jQuery</h2>
				<img src="images/22.jpg" alt=""/>
				<p>
					A slick overlay effect that let's
					you show notes on a portfolio item
				</p>
				<div class="pc_more">
					http://tympanus.net/codrops/2010/10/12/annotation-overlay-effect/
				</div>
			</div>
			<div class="pc_item">
				...
			</div>
			...
			<div class="clear"></div>
		</div>
	</div>
	<div id="pc_slider" class="pc_slider"></div>
</div>

To add new item elements, we just need to repeat the structure of the div with the class “pc_item”.
Because we will want to make the whole item clickable, we will add the link of the respective article into a div element with the class “pc_more”.

In our jQuery function we will then take care of that. Of course, you can simple add an href to a link element, but we want to show you how you can trigger links to open by reading them out from an element.

Let’s take a look at the style.

The CSS

For the style, we will define the looks of the main panel and it’s content and we will also manipulate some classes of the jQuery UI elements.

Let’s start with the main panel:

.pc_panel{
	position:fixed;
	background:transparent url(../images/bgSlide.png) repeat top left;
	color:#fff;
	font-size:11px;
	line-height:14px;
	width:100%;
	right:0px;
	display:none;
	font-family:Arial, Helvetica, sans-serif;
}

We will use fixed positioning for the panel since we want to make it follow us when we scroll the page. The panel will be initially invisible and when we scroll to the trigger position, we will slide it in from the right.

In our jQuery we will set its right value to minus the window width and then we will animate it to right:0px.

The little icons on the right for exanding/collapsing and for closing the teaser panel permanently will have the following style:

.pc_label{
	width:20px;
	height:20px;
	position:absolute;
	top:0px;
	text-align:center;
	letter-spacing:2px;
	text-shadow:0px 0px 1px #fff;
	cursor:pointer;
}
.pc_panel .expand{
	background:#010101 url(../images/expand.gif) no-repeat center center;
	right:24px;
}
.pc_panel .collapse{
	background:#010101 url(../images/collapse.gif) no-repeat center center;
	right:24px;
}
.pc_panel .close{
	background:#010101 url(../images/close.gif) no-repeat center center;
	right:2px;
}

If you are using two classes on an element and you want the, let’s say, second class (in our case expand, collapse and close) to overwrite the properties of the first one, you need to make the definition for those classes more specific. That’s why we have our class “pc_label” and then we define the “stronger” classes by adding their parent (pc_panel).

The title for the panel will have the following style:

.pc_title{
	width:100%;
	height:20px;
	background:#000;
	font-size:9px;
	text-transform:uppercase;
	line-height:20px;
	text-indent:10px;
	letter-spacing:1px;
}

Each item will have the following style:

.pc_item{
	width:200px;
	height:120px;
	cursor:pointer;
	overflow:hidden;
	background:transparent url(../images/bgSlide.png) repeat top left;
	float:left;
	margin:5px 10px 10px 10px;
	-moz-border-radius:4px;
	-webkit-border-radius:4px;
	-moz-box-shadow:0px 0px 5px #000;
	-webkit-box-shadow:0px 0px 5px #000;
	box-shadow:0px 0px 5px #000;
}
.pc_item h2{
	padding:10px 0px 10px 10px;
	font-size:14px;
	height:32px;
	color:#009ac6;
	line-height:11px;
	clear:both;
}
.pc_item p{
	text-align:justify;
	font-size:10px;
	text-shadow:1px 1px 1px #000;
	padding:0px 10px 5px 10px;
}
.pc_item img{
	width:50px;
	float:left;
	margin:0px 10px 0px 10px;
	border:4px solid #191919;
	-moz-box-shadow:0px 0px 5px #000;
	-webkit-box-shadow:0px 0px 5px #000;
	box-shadow:0px 0px 5px #000;
}
.pc_more{
	display:none;
}

When hovering over an item we will add the class “selected” to it, in order to make it look different:

.pc_panel .selected{
	background:#222;
}
.pc_panel .selected img{
	border:4px solid #010101;
}

The wrapper around the items needs to have the following style because we want to apply the slider on the container:

.pc_wrapper{
	overflow:hidden;
	position:relative;
	margin-top:10px;
}

The slider itself will have an absolute position:

.pc_slider{
	position:absolute;
}

We want a customized look for the slider and the little slider handle, so we will overwrite the classes that come with jQuery UI:

.ui-widget-content {
	background:#000;
}
.ui-state-default, .ui-widget-content .ui-state-default{
	border:none;
	background-color:#aaa;
	outline:none;
	cursor:pointer;
	height:17px;
	width:10px;
	left:0px;
	margin-bottom:-10px;
}

And, finally, a little helper class to clear the float in the end of the items so that we can work with the height of it’s container:

.clear{
	clear:both;
}

And that’s all the style. Let’s look at the jQuery.

The JavaScript

The main idea is to make the panel appear at a certain position of the page. For that we will add a id=”pc_reference” to the last paragraph of our demo page because we want the panel to appear at the end of the page and show related items to the reader.

The shown panel will be of a specific height, revealing only the first row of related items/articles. When the user then expands the panel, it will occupy the full page and the user can use a scroll to see all items.

We want to have the possibility to expand the panel but also to remove it completely, since it could be annoying to the user (every time he scrolls past the specific trigger, it will appear).

Let’s first define some variables:

//window width and height
var window_w 					= $(window).width();
var window_h 					= $(window).height();
//the main panel div
var $pc_panel = $('#pc_panel');
//the wrapper and the content divs
var $pc_wrapper					= $('#pc_wrapper');
var $pc_content					= $('#pc_content');
//the slider / slider div
var $pc_slider					= $('#pc_slider');
//the element reference - reaching this element
//activates the panel
var $pc_reference 				= $('#pc_reference');

var maxWidth,maxHeight,marginL;

Now, we will call the function buildPanel(), that already constructs the panel like it will look, when we expand it:

buildPanel();

function buildPanel(){
	$pc_panel.css({'height': window_h + 'px'});
	hidePanel();
	//we want to display the items in a grid.
	//we need to calculate how much width and height
	//the wrapper should have.
	//we also want to display it centered, so we need to calculate
	//the margin left of the wrapper

	//First, lets see how much of height:
	//maxHeight = Math.floor((window_h-20)/135)*135;
	//20 => pc_titles height
	//135 => 125 of each items height plus its margin (10)
	maxHeight 		= Math.floor((window_h-20)/135)*135;
	//maxWidth = Math.floor((window_w-35)/220)*220;
	//220 = item width + margins (left and right)
	maxWidth 		= Math.floor((window_w-35)/220)*220;
	marginL  		= (window_w - maxWidth)/2;
	$pc_wrapper.css({
		'width' 		: maxWidth + 20 + 'px',
		'height'		: maxHeight +'px',
		'margin-left' 	: marginL + 'px'
	});

	//innitialize the slider
	try{
		$pc_slider.slider('destroy');
	}catch(e){}
	//total_scroll is the number of how much we can scroll
	var total_scroll = $pc_content.height()-maxHeight;
	//add a slider to scroll the content div
	//hidden until the panel is expanded
	if(total_scroll > 0){
		$pc_slider.slider({
			orientation	: 'vertical',
			max			: total_scroll,
			min			: 0,
			value		: total_scroll,
			slide		: function(event, ui) {
				$pc_wrapper.scrollTop(Math.abs(ui.value-total_scroll));
			}
		}).css({
			'height'	: maxHeight -40 + 'px',//40 extra
			'left'		: maxWidth + 20 + marginL + 'px',
			'top'		: 30 + 20 + 'px',
			//30 = 20 of title + 10 margin, 20 extra
			'display'	: 'none'
		});
	}
}

Initially, we want to hide the panel outside of the viewport on the right side, so we define the following function:

function hidePanel(){
	//165 => 20 pc_title + 120 item + margins
	$pc_panel.css({
		'right'	: -window_w + 'px',
		'top'	: window_h - 165 + 'px'
	}).show();
	try{
		//position the slider in the beginning
		slideTop();
	}catch(e){}
	$pc_slider.hide();
	$pc_panel.find('.collapse')
	.addClass('expand')
	.removeClass('collapse');
}

For our custom slider that will let us scroll through the items, we will define a function that resets it by sliding it all to the top:

function slideTop(){
	var total_scroll 	= $pc_content.height()-maxHeight;
	$pc_wrapper.scrollTop(0);
	$pc_slider.slider('option', 'value', total_scroll );
}

Now, we want to define what happens when we reach the element that has the ID “pc_reference” while we scroll our page. We need to get the distance from the top to slide the panel out at the right position, and hide it, if we are more up than the trigger again:

$(window).bind('scroll',function(){
	var distanceTop = $pc_reference.offset().top - window_h;
	if($(window).scrollTop() > distanceTop){
		if(parseInt($pc_panel.css('right'),10) == -window_w)
			$pc_panel.stop().animate({'right':'0px'},300);
	}
	else{
		if(parseInt($pc_panel.css('right'),10) == 0)
			$pc_panel.stop().animate({'right': -window_w + 'px'},300,function(){
				hidePanel();
			});
	}
}).bind('resize',function(){
	//on resize calculate the windows dimentions again,
	//and build the panel accordingly
	window_w 			= $(window).width();
	window_h 			= $(window).height();
	buildPanel();
});

When we click on the expand button, we animate the panel to the size of the window and reset the custom slider and show it:

$pc_panel.find('.expand').bind('click',function(){
	var $this = $(this);
	$pc_wrapper.hide();
	$pc_panel.stop().animate({'top':'0px'},500,function(){
		$pc_wrapper.show();
		slideTop();
		$pc_slider.show();
		$this.addClass('collapse').removeClass('expand');
	});
})

When we click on “collapse”, we will hide the slider and minimize the panel again:

$pc_panel.find('.collapse').live('click',function(){
	var $this = $(this);
	$pc_wrapper.hide();
	$pc_slider.hide();
	$pc_panel.stop().animate({'top':window_h - 165 + 'px'},500,function(){
		$pc_wrapper.show();
		$this.addClass('expand').removeClass('collapse');
	});
});

Clicking “close” will make the panel disappear permanently:

$pc_panel.find('.close').bind('click',function(){
	$pc_panel.remove();
	$(window).unbind('scroll').unbind('resize');
});

And finally, we want to add a hover effect to the items, and open a new window with the right location when the user clicks on it:

$pc_wrapper.find('.pc_item').hover(
function(){
	$(this).addClass('selected');
},
function(){
	$(this).removeClass('selected');
}
).bind('click',function(){
	window.open($(this).find('.pc_more').html());
});

And that’s it! We hope you enjoyed the tutorial and find it useful!

Tagged with:

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay up to date with the latest web design and development news and relevant updates from Codrops.