Design Lunatic Just another WordPress site 2013-11-12T17:22:29Z https://www.designlunatic.com/feed/atom/ WordPress Design Lunatic <![CDATA[Isotope infinite scroll]]> http://www.designlunatic.com/?p=1303 2012-12-25T07:02:39Z 2012-12-25T07:02:39Z The faster something loads, the happier the user is. This is something it is important to understand when creating websites. Today, I’ll show how to use jQuery’s AJAX capabilities in conjunction with isotope.js to dynamically load content in once the user reaches the bottom of the page, which makes everything seem faster and improves the user experience.

Before you begin this tutorial, make sure you have a local web server set up, because jQuery’s AJAX functions don’t work when the file is just opened locally.

HTML

The HTML remains the same as it was in the original isotope tutorial. However, you must create some more pages. Create a duplicate of the index.html file from the original isotope tutorial and call it page2.html. Do the same thing again, and call it page3.html. Put the pages you created in a directory called “pages”. Feel free to change the content of the boxes inside each page – that will just make it easier to distinguish which box came from what page.

CSS

The CSS remains unchanged from the original isotope tutorial.

jQuery

First, include the jquery that initializes isotope.

$(document).ready(function(){
	var $container = $('#content');
	$container.isotope({
		filter: '*',
		animationOptions: {
			duration: 750,
			easing: 'linear',
			queue: false,
		}
	});

	$('#nav a').click(function(){
		var selector = $(this).attr('data-filter');
		$container.isotope({ 
			filter: selector,
			animationOptions: {
				duration: 750,
				easing: 'linear',
				queue: false,
			}
		});
		
		return false;
	});
});

Now, can start on the AJAX functionality. First, we need a variable to store what page is currently being displayed on the page.

var page = 1;

This will go up by one every time another page is loaded in.

Next, we’ll create the window.scroll function that all of our code today will go into.

var page = 1;
$(window).scroll(function(){

});

This is where all the magic will happen. Since the whole purpose of the script is to detect when a user has scrolled down to the bottom of the page and load content in when that happens, we need a window.scroll function. Every time the user scrolls, the code inside this function is executed.

Now, we’ll create some variables.

var scrollTop = $(window).scrollTop();
var windowHeight = $(window).height();
var docuHeight = $(document).height();

We’ll use these three variables to determine whether or not the user has scrolled down to the bottom of the page yet.

if(scrollTop + windowHeight == docuHeight){

}

This statement is true if the user has scrolled to the bottom of the page.

Once the user has scrolled to the bottom of the page, a temporary div called “temp-load” will be created.

if(scrollTop + windowHeight == docuHeight){
	$('body').append('<div id="temp-load"</div>');
}

Next, we’ll use jQuery’s load function to get the boxes from the next page and put them into this temp-load div.

if(scrollTop + windowHeight == docuHeight){
	$('body').append('<div id="temp-load"</div>');

	page += 1;

	$('#temp-load').load('pages/page' + page + '.html #content');
}

The parameter inside the load function is what jquery is retrieving. In this case, it is a page inside the “pages” directory, and the page is whatever the next page is – that’s why page is being incremented by one. The second part of the parameter is “#content”, which means jquery is only retrieving the #content div from the next page, since we don’t need anything else. The HTML jquery retrieves is placed inside the “#temp-load” div.

Jquery .load can take another parameter, which is the callback.

$('#temp-load').load('pages/page' + page + '.html #content', function(){
	
});

The code inside the callback gets executed once the load function successfully completes, which means everything was retrieved and has been placed into the “#temp-load” div.

$('#temp-load').load('pages/page' + page + '.html #content', function(){
	$('#temp-load > #content').children().css({ 
		 opacity: 0 
	});	

	var toAdd = $('#temp-load > #content').html();
	
});

This code makes the elements inside the “temp-load” div have an opacity of 0, so that they can later on be nicely animated in. The “toAdd” variable contains the HTML for all the elements that were just loaded in with jquery. We’ll insert the content of this variable into the main container. To do this, we’ll use isotope’s insert function.

var toAdd = $('#temp-load > #content').html();

$container.isotope('insert', $(toAdd), function(){
	$container.children().css({
		opacity: 1
	});	
					
	$('#temp-load').remove();
					
});
				

Here’s what happens: isotope takes the value of “toAdd” and appends it to the inside of the $container. It then triggers a reLayout, which means everything inside is re-filtered. This way, all the items are now isotoped. Once the items have been added, the callback function fires. Inside that, we make all of $container’s children have an opacity of 1. Since the elements we just added all have an opacity of 0, they need to become visible. Modifying their styles to make their opacity 1 animates them to become visible. Lastly, the temporary div is removed since we no longer need it.

The final code looks like this:

$(document).ready(function(){
	var $container = $('#content');
	$container.isotope({
		filter: '*',
		animationOptions: {
			duration: 750,
			easing: 'linear',
			queue: false,
		}
	});

	$('#nav a').click(function(){
		var selector = $(this).attr('data-filter');
		$container.isotope({ 
			filter: selector,
			animationOptions: {
				duration: 750,
				easing: 'linear',
				queue: false,
			}
		});
		
		return false;
	});

	var page = 1;

	$(window).scroll(function(){

		var scrollTop = $(window).scrollTop();
		var windowHeight = $(window).height();
		var docuHeight = $(document).height();

		if(scrollTop + windowHeight == docuHeight){
				
			$('body').append('<div id="temp-load"</div>');

			page += 1;
			
			$('#temp-load').load('pages/page' + page + '.html #content', function(){
				
				$('#temp-load > #content').children().css({
					opacity: 0
				});	
			
				var toAdd = $('#temp-load > #content').html();

				$container.isotope('insert', $(toAdd), function(){
					
					$container.children().css({
					opacity: 1
					});	
					
					$('#temp-load').remove();
					
				});
		
			});
			
		}

	});

});

That’s the end of this tutorial; I hope you enjoyed it. If you have any questions or comments, feel free to leave them in the comments section below.

]]>
8
Design Lunatic <![CDATA[Custom Scrollbars with jQuery]]> http://www.designlunatic.com/?p=1281 2013-11-12T17:22:29Z 2012-11-22T21:13:01Z Sometimes, as web designers, we create a perfect design. Everything is exactly the way it should be, every pixel in the right spot, every color the right tinge. However, there is one thing that we often leave unchanged, and that is the scrollbar. Today, I’ll show how to create custom scrollbars using jQuery.

HTML

The HTML is extremely basic – it’s just a “section” with some paragraphs inside. The javascript we’re about to write inserts all the HTML the custom scrollbar needs, so you can place whatever you want into the HTML.

<section id="main">
<p>
Lorem ipsum dolor sit amet, christus eum ego. Rhenum ibat est amet consensit cellula filia in lucem. Maria non dum est Apollonius eius sed quod una litus ostendam Apollonio dares. Actum in rei civibus nescis admonente iustum ait in deinde duas particularis ad quia ad per dicis. Stans sed quod una Christi iube es est cum, athenagorae principio intus huius domus ad quia quod tamen adnuente rediens eam ad per. Quos essem rogo cum suam non ait mea in rei sensibilium acciperem. Corripit ars tolle Adfertur guttae sapientiae decubuerat. Inquisivi ecce habitu rubor virginitatem sunt antecedente tuus desiderio sic ut libertatem adhuc. Inter autem nobiscum paulo aureos fecit per accipere, dicis Deducitur potest flens praemio litore iunctionem quae. Domini in lucem genero in rei finibus veteres hoc! Equidem deceptum in deinde cepit roseo ruens sed eu fugiens laudo in.
</p>
<p>
Lugens quia iuvenis eum istam provoces Athenagora eius sed dominum oculos ne a civitas iter. Patriam Dianae non solutionem inveni quem suis alteri formam speciosam at at eius ad quia illum decidat quam cara patrem! Habes prima inrumpit dic hoc ambulare dolor invenerit, mytilenam Descendi eam in rei finibus veteres hoc. Inquisivi ecce prima substantiae Apollonius in deinde duas formis ei quoque non solutionem innocentem vis! Ait mea ego dum miror diligere quem est se in modo genito in. Adiuro me naufragus qui enim, unam emanabat cum obiectum ait. Miscetur vulnus fertur ardeat in modo genito in fuerat est se ad per animum est amet amet Cur meae. Antiochia videns de tuae illa caelum ad suis. Peregrini in lucem concitaverunt in rei finibus veteres hoc contra serpentibus isto. Post petiit materia amicis filia dedit beneficio ad quia ei. Accedens est cum obiectum est in fuerat se est cum suam vidit Dionysiadi me in. Eum est amet constanter approximavit te in lucem exitum vivit. Se vero non solutionem ascendens sed eu fugiens laudo misera haec vidit ad quia. Impietatem die audi discipuli Tyrius tu mihi Tyrum reverteretur ad nomine.
</p>
<p>
Laetare quod non solutionem invenerunt ita in. Abstulit meis dolor ad per sanctus ait. Probo artium studiose rosa ad per animum pares terris restituit. Meam ad quia iuvenis omnia bono quomodo possum es. Modum cura supponere ipsa Invitamus me! Erige me in deinde vero quo sanctis oravit. Antioche in fuerat eum ego dum miror puella est se ad nomine Maria non ait mea ego esse haec. Atqui plurium venenosamque serpentium ne civitatis civium currebant in, nescimus de me in deinde cupis hominem. Rogo ultimum favente his domino ab ornabo in modo invenit quasi plena violatam. Mutilenae ratio omnes deo adiuves finem. Credo puella mihi quidditas tuo dolor virgo permitte a civitas ad nomine Maria non ait est amet amet amet consensit cellula rei exultant deo. Maria cum unde non dum est amet consensit cellula filia puella. Ascendi in lucem exitum atque bona dei fundamus magister. Thebaeorum in fuerat eum est amet amet constanter determinatio debitis torporis quin.
</p>
<p>
Dicite enim formam se est in! Ardalio nos filiae gloriam virginis provolutus volo lacrimis colligantes amarissimo formas. Secundis est in modo ad suis alteri si non solutionem invenisti naufragus ferro conparuit de. Ni fluctus evasit dic ego illum Apollonii appropinquat tation ulterius a his e contrarius haec vidit Dionysiadi me in. Videns sed quod eam sed quod una Christi in lucem in fuerat accidens suos exteriores. Tantus puella sed haec aliquam habet comam apodixin mei in fuerat est se sed dominum sit in. Ephesum iube creasti hoc ait Cumque materia amicis in modo cavendum es ego dum est Apollonius ut a. Accede meae ad quia ad per te in rei completo litus vita Apolloni figitur acquievit. Etiam corpusculum subito animal irruit in, primam qui enim est in deinde plectrum anni ipsa Invitamus me.
</p>
<p>
Puto suam in lucem genero in fuerat accidens suos exteriores iuvenis eum in fuerat eum ego Pentapolim Cyrenaeorum. Nescimus de me naufragus habuisti sit in! Pater ostendit qui non ait Cumque materia eam eos. Litus sua Cumque persequatur sic vero cum suam ad per dicis filiam in lucem in. Horreo Athenagora eius non solutionem invenisti naufragus ait mea, unam emanabat cum autem illud huius domus respexit est amet coram regis fine omnino vero cum. Habet vero quo accumsan in rei finibus veteres hoc contra me. Permansit in lucem in deinde cupis ei Taliarchum. Ite in modo ad suis alteri si. Ecce codicellis desinit sestertia habeatis Apollonio sed dominum depressit filia navem causa alia qui auri. Sed eu fides se est amet coram regis suam! Quantum ait regem consolatus dum est se sed dominum depressit filia puella ut diem finito convocatis ad per. Ubi diceret modiorum fudit animo resignasset iubet contremuit in, spongia non solutionem inveni in rei sensibilium iussit divisit calvus dolor invenerit. Thebaeorum in rei completo litus sua in fuerat est in. Mutilenae ea communia ei quoque sed quod eam in, fige omnium ad quia ei sed eu fides Concordi fabricata ait. Iacentem substantiales statim iuxta quia iuvenis ut libertatem petitiones, adfertur guttae sapientiae ducitur multa confert eam sed.
</p>
</section>

CSS

The CSS is mostly just styling, but there are a couple of things it is important to have.

html {
overflow-y: hidden;
}

This causes the default scrollbar to disappear, which allows us to create a replacement.

Next, we have the scrollbar track. This is the vertical line on which the scrollbar goes up and down.

#scrollbar-track {
width: 10px;
position: fixed;
right: 0px;
height: 100%;
background: #ddd;
}

We’re giving it a width, fixing it to the viewport so that it stays in the same spot no matter where the user scrolls, we attach it to the right of the screen, and we give it a height of “100%”, which makes it the same height as the viewport. The last thing is just a light grey background.

Next, the scrollbar.

#scrollbar {
width: 10px;
position: fixed;
right: 0px;
background: #666;
-webkit-border-radius: 5px;
border-radius: 5px;
}

The CSS is almost the same as that of the scrollbar track’s, but here there is no “height: 100%”, since the height will vary depending on how much content there is on the page. The scrollbar also has a width of 10px, is attached to the right side of the viewport, and is given some mild styling.

Keep in mind that you won’t be able to see these styles yet, as the elements haven’t actually been created by the javascript yet.

jQuery

The first thing we need is to include a couple of scripts. Download the files for this tutorial. Inside, you’ll find “jquery-ui-draggable.js” and “jquery.mousewheel.js”. The “draggable” script is just a custom build of jQuery UI that only contains the code for “draggable”, and “mousewheel” gives us some handy functions based on the user’s mousewheel or trackpad. Place them in the directory in which you’re following this tutorial.

Now, include them in the “head” of the HTML document.

<script src="jquery.mousewheel.js"></script>
<script src="jquery-ui-draggable.js"></script>

Don’t forget to include a copy of jQuery as well.

Now, we’ll create the scrollbar and the track.

$(document).ready(function(){

	$('body').prepend('<div id="scrollbar-track"><div id="scrollbar"></div></div>');

});

This code adds the two “div” elements we need to the very beginning of the page, just inside the “body”.

Next, we’ll create the function that does all the work.

function scrollBar(){

	var viewportHeight = $(window).height();
	var docuHeight = $(document).height();

	var trackHeight = $('#scrollbar-track').height();

	var scrollbarHeight = (viewportHeight/docuHeight)*trackHeight;

	$('#scrollbar').height(scrollbarHeight);
}

There’s now a function called “scrollBar”, which has some variables inside it. The first one, “viewportHeight” is the height of the browser viewport. The next, “docuHeight”, is the height of the whole HTML page. “trackHeight” is the height of the scrollbar track, which is the same as “viewportHeight”. I just like to keep the two separate to make it clearer what the code actually does. Next, the “scrollbarHeight” variable. This variable is created by taking the ratio of the viewport height to the document height, which is usually between 0 to 1. If the ratio is higher, that means that the viewport is bigger than the whole HTML document, in which case the scrollbar doesn’t do anything. We take the ratio and multiply it by the “trackHeight”. This gives us the height of the scrollbar. Let’s imagine that the whole document is exactly twice as big as the viewport. For example, the height of the viewport is 500px and the height of the document is 1000px. 500/1000 is “0.5″, so the ratio is “0.5″. We then multiply “0.5″ by the trackHeight, which gives us a value exactly half the size of the track height. This is how the height of the scrollbar is determined.

Now, we’ll make the scrollbar draggable.

$('#scrollbar').draggable({
	axis: 'y',
	containment: 'parent',
	drag: function() {
		var scrollbarTop = parseInt($(this).css('top'));

		var scrollTopNew = (scrollbarTop/(trackHeight))*docuHeight;

		$(window).scrollTop(scrollTopNew);

	}
});

This is where the “draggable” script comes in. We use the “draggable” function to make the scroll bar draggable. The “axis” parameter is set to “y”, which means that it can only be dragged up or down. The “containment” parameter is set to “parent”, which means it can’t be dragged out of the boundaries of the parent, which in this case, is the “track”. The last thing is the “drag” paramater, which accepts a function as a value. Basically, whenever the scrollbar is being dragged, this function fires. Inside the function, the first thing we do is create a variable called “scrollbarTop”, which takes the CSS “top” value of the scrollbar (how far away it is from the top of the track) and converts it into an integer. This allows us to use it in mathematical equations such as the one that determines the value of the next variable, “scrollTopNew”. “scrollTopNew” is the new value of where the window should scroll to. In order to do this, we take the ratio of the scrollbar’s “top” value and the “trackHeight”. We then take this ratio and multiply it by the “docuHeight”, which gives us a value to which the window should scroll. The last line actually scrolls the window to this value.

Here’s what everything looks like so far:

$(document).ready(function(){

	$('body').prepend('<div id="scrollbar-track"><div id="scrollbar"></div></div>');

	function scrollBar(){

		var viewportHeight = $(window).height();
		var docuHeight = $(document).height();

		var trackHeight = $('#scrollbar-track').height();

		var scrollbarHeight = (viewportHeight/docuHeight)*trackHeight;

		$('#scrollbar').height(scrollbarHeight);

		$('#scrollbar').draggable({
			axis: 'y',
			containment: 'parent',
			drag: function() {
				var scrollbarTop = parseInt($(this).css('top'));

				var scrollTopNew = (scrollbarTop/(trackHeight))*docuHeight;

				$(window).scrollTop(scrollTopNew);

			}
		});
	}
});

Now, we can initialize the function so that the code actually happens.

function scrollBar(){
//Code in here...
}

scrollBar();

At this point, dragging the scroll bar should result in the page scrolling around. The last thing we need to do is make the mousewheel/touchpad work. We’ll do this by using the “mousewheel” script.

$("body").bind("mousewheel", function (event, delta) {

	var scrollTop = $(window).scrollTop();
	var scrollTopNew = scrollTop - (delta * 40);

	$(window).scrollTop(scrollTopNew);

	var scrollbarTop = ($(window).scrollTop()/docuHeight)*trackHeight;

	$('#scrollbar').css({
		top: scrollbarTop
	});
});

This code is just after the “draggable” scrollbar code. Here, we bind a “mousewheel” event to the body, so whenver the mousewheel is moved, the code inside is executed.

The first variable, “scrollTop”, is how far the window has already scrolled. The next one, “scrollTopNew”, is where the window should now scroll to. It is determined by taking the current “scrollTop”, and using teh “delta” variable. The “delta” variable is a number, “1″ or “-1″. It is “-1″ if the user just scrolled down, and “+1″ if the user scrolled up. This number is multiplied by “30″, so when the user moves their mouse wheel down once, the page scrolls down by 30 pixels. This new value is then applied to the window’s “scrollTop” by using the “scrollTop” function. “scrollbarTop” is where the scrollbar should be as a result of the user’s mouse wheel or touchpad scrolling. It takes the current scrollTop divides it by the document height to get the ratio, and multiplies the ratio by the trackHeight so that the scrollbar is in the right position. The scrollbar is then given a top of “scrollbarTop”.

This code should work well, but it doesn’t work when the user resizes their browser window. We can fix this by using the following code:

$(window).resize(function(){
	scrollBar();
});

This way, the function is re-executed whenever the window is resized.

Here’s what all the javascript should look like:

$(document).ready(function(){

	$('body').prepend('<div id="scrollbar-track"><div id="scrollbar"></div></div>');

	function scrollBar(){

		var viewportHeight = $(window).height();
		var docuHeight = $(document).height();

		var trackHeight = $('#scrollbar-track').height();

		var scrollbarHeight = (viewportHeight/docuHeight)*trackHeight;

		$('#scrollbar').height(scrollbarHeight);

		$('#scrollbar').draggable({
			axis: 'y',
			containment: 'parent',
			drag: function() {
				var scrollbarTop = parseInt($(this).css('top'));

				var scrollTopNew = (scrollbarTop/(trackHeight))*docuHeight;

				$(window).scrollTop(scrollTopNew);

			}
		});

		$("body").bind("mousewheel", function (event, delta) {

			var scrollTop = $(window).scrollTop();
			var scrollTopNew = scrollTop - (delta * 40);

			$(window).scrollTop(scrollTopNew);

			var scrollbarTop = ($(window).scrollTop()/docuHeight)*trackHeight;

			$('#scrollbar').css({
				top: scrollbarTop
			});
		});

	}

	scrollBar();

	$(window).resize(function(){
		scrollBar();
	});

});

That’s it for this tutorial – I hope you enjoyed it and learned something new. If you have any questions or comments, post them below and I’ll do my best to answer.

]]>
14
Design Lunatic <![CDATA[Awesome jQuery Tooltips]]> http://www.designlunatic.com/?p=1250 2012-11-04T17:58:06Z 2012-11-04T17:58:06Z Tooltips are a great way to display some information about an element on the page. Normally, these are used on links. In this post, I’ll explain how to create a jQuery script that allows for easy tooltips on a page.

HTML

All that’s on the page is just some Lorem Ipsum text and a couple of links.

<section id="container">

<p>
Lorem ipsum dolor sit amet, video cum autem quod non dum, audite deo adoptavit cum magna amici invocat manibusque removit benedictus. Ad per dicis Deducitur potest contremiscunt <a href="#" data-tooltip="A tooltip!">pater unica</a> suae ad nomine sed haec aliquam laetandum prudentia litteris erutis invenies eum. Euro in fuerat se est amet consensit cellula rei finibus veteres hoc contra piissimi sibi adsedit in deinde cepit roseo. <a href="#" data-tooltip="This is a tooltip">Vini in deinde</a> cepit roseo ruens sed dominum sit audivit illius actio viro prudentius ei. Erras nisi auri est in lucem, venis potest in modo compungi mulierem.
</p>

</section>

The important part is the “data-tooltip” attributes on the links. These are so the jQuery script we’ll write knows what to display in the tooltip.

CSS

First off, get a good CSS reset, as these are invaluable in getting rid of weird browser-related issues. Now, let’s just style the main container to make it look nice.

body {
background: #eee;
}

#container {
font-family: arial;
font-size: 15px;
line-height: 25px;
color: #515151;
width: 600px;
height: 2000px;
padding: 20px;
border-left: 1px solid #dedede;
border-right: 1px solid #dedede;
border-bottom: 1px solid #dedede;
background: #fff;
margin: 0 auto;
-webkit-border-radius: 0px 0px 5px 5px;
border-radius: 0px 0px 5px 5px;
}

The text inside the container will be 15px Arial with a line-height of 25px, and will be a dark grey color. The container will be 600px wide with some padding, and will have borders that are slightly rounded.

Next up, some link styling.

#container a {
color: #888;
text-decoration: none;
border-bottom: 1px dotted #888;
position:relative;
}

This is just for visual purposes, but notice the “position: relative”. This will be important in positioning the tooltip properly.

Now, we can style the tooltip. This will just be a simple rectanble, but it will have a triable facing downwards to indicate where the tooltip is coming from.

.tooltip {
width: 100px;
margin-left: -60px;
left: 50%;
line-height: 20px;
padding: 10px;
font-family: Arial;
font-size: 14px;
color: #777;
text-align: center;
border: 2px solid #bbb;
background: #fff;
text-indent: 0px;
position: absolute;
pointer-events: none;
opacity: 0;
box-shadow: 1px 1px 2px rgba(0,0,0,0.1);
-webkit-border-radius: 5px;
border-radius: 5px;
}

All of this is just for visual purposes. We’re giving it a width of 100px, some padding, styling the text inside – basically, we’re just making it pretty. Notice the “left: 50%” and “margin-left: -60px”. This positions the left edge of the tooltip to be halfway in the link, but that’s not what we want; we want it to be perfectly centered. The “margin-left: -60px” makes it perfectly centered by shifting it a value to the left equal to half of the width of the tooltip (since with the padding, the tooltip actually has a total width of 120px). Another important property is the “pointer-events: none” property – this makes the user unable to interact with the tooltip, so that it doesn’t get in the way when it isn’t visible.

With this code, the tooltip already looks pretty – but it doesn’t have a triangle pointing down to indicate where it originated from. Let’s fix that.

.tooltip::after {
content: '';
position: absolute;
left: 50%;
margin-left: -10px;
bottom: -10px;
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 8px solid #bbb;
}

Instead of creating a separate element just for the triangle, we’re using the CSS3 “after” pseudo element. The “content” property is so that the pseudo element actually contains something; without this, nothing will show up. Now, the next two lines are centering the triangle. The “left: 50%” will make the left edge of the triangle be halfway, but by giving it a negative margin equal to half of its width, the triangle is now perfectly centered. However, the triangle is not where we want it to be. The “bottom: -10px” makes it be right below the tooltip. The next lines are what make it a triangle. By giving it a width and height of 0, all that’s left is the borders. Each border behaves like a triangle, where four triangles create a square. By making the left and right borders transparent, the top border is all that remains. The top border has the same color as the border of the tooltip, so it fits in nicely.

Jquery

Before we begin writing code, here’s how everything will work:

  1. The script iterates over each link, or “a” element on the page.
  2. For each link, a “div” with a class of “tooltip” is added.
  3. Each tooltip div contains the text from the “data-tooltip” attribute inside its corresponding link.
  4. When a link is hovered over, its corresponding tooltip is animated slightly upwards and the opacity is increased.

Let’s get to work:

$(document).ready(function(){
	
	$('a[data-tooltip]').each(function(){
		
	});

});

This is just the typical jquery document ready function, which waits until the page is loaded to execute the code inside it. The “each” function repeats itself for each element selected; in this case, the code inside it is executed for each link with a “data-tooltip” attribute on the page.

Now, we’ll create the tooltip.

$('a[data-tooltip]').each(function(){
	var tooltipText = $(this).attr('data-tooltip');
	$(this).append('<div class="tooltip">'+tooltipText+'</div>');
});

The variable “tooltipText” is simply the value of the “data-tooltip” attribute of the link. The next line of code appends a div with a class of “tooltip” and with the value of “tooltipText” inside it.

Next, we’ll position the tooltip properly.

$('a[data-tooltip]').each(function(){
	var tooltipText = $(this).attr('data-tooltip');
	$(this).append('<div class="tooltip">'+tooltipText+'</div>');
	
	var tooltipHeight = $(this).find('.tooltip').outerHeight();	

	$(this).find('.tooltip').css({
		top: -tooltipHeight,
	});
});

The variable “tooltipHeight” is the height of the tooltip using the “outerHeight” function, which is just the “height” function but it includes padding and borders – this allows for a more accurate height. “$(this).find” finds a particular element inside the current element. In this case, we’re just finding the tooltip that is inside the link the script is currently on. We then give the tooltip a “top” equal to the negative of its height, which puts it right above the link.

The last thing that must be done is making the tooltip actually appear when a link is hovered over.

$('a[data-tooltip]').each(function(){
//Your code here...
});

$('a[data-tooltip]').hover(function(){
		
	$(this).find('.tooltip').animate({
		opacity: 1,
		marginTop: -7
	},200);
		
});

When a link with a “data-tooltip” attribute is hovered over, the tooltip inside it is animated to “opacity: 1″, and is shifted up 7 pixels. When the tooltip shifts up like that, it not only looks nice, but also shows where the tooltip is actually coming from. These two animations are done during 200 milliseconds. At this point, we’re almost done, but notice what happens when you move the mouse cursor away from a link – nothing. The tooltip stays where it is.

Fortunately, this can easily be fixed.

$('a[data-tooltip]').hover(function(){
	
	$(this).find('.tooltip').animate({
		opacity: 1,
		marginTop: -7
	},200);
	
}, function(){
	$(this).find('.tooltip').animate({
		opacity: 0,
		marginTop: 0
	},200);
});

Here, we’ve used a callback to the “hover” function; the code inside the “hover” callback executes when the cursor is no longer hovering over the link. In this callback, we simply move the tooltip back down and reduce its opacity.

Here’s all the jQuery in one place.

$(document).ready(function(){
	
	$('a[data-tooltip]').each(function(){
	
		var tooltipText = $(this).attr('data-tooltip');
		$(this).append('<div class="tooltip">'+tooltipText+'</div>');
		
		var linkWidth = $(this).width();
		var tooltipWidth = $(this).find('.tooltip').outerWidth();
		
		var tooltipHeight = $(this).find('.tooltip').outerHeight();	

		
		$(this).find('.tooltip').css({
			top: -tooltipHeight,
		});
		
		
	});
	
	$('a[data-tooltip]').hover(function(){
		
		$(this).find('.tooltip').animate({
			opacity: 1,
			marginTop: -7
		},200);
		
	}, function(){
		$(this).find('.tooltip').animate({
			opacity: 0,
			marginTop: 0
		},200);
	});
	
});

That’s the end of this tutorial. I hope you found it useful and enjoyable, and if you have any questions or comments, feel free to comment below – I’d be happy to answer.

]]>
0
Design Lunatic <![CDATA[Rearrange content when it’s too wide with jquery]]> http://www.designlunatic.com/?p=1222 2012-09-18T02:53:48Z 2012-09-18T02:53:48Z Media queries have proven to be extremely useful in responsive layouts. However, they do have a drawback: they can’t analyze the content on the page before deciding when to kick in. For example, if you have a fluid layout, CSS doesn’t know exactly what width the container has when the browser has a width of, for example, 742px. Javascript does. In this post, I’ll show how javascript can be used to make layouts even smarter and more adaptable.

HTML

The example we’ll be creating today is just the top of a web page – it will contain the title of the site and the navigation menu. That means the HTML is fairly straightforward.

<header>

<h1>The title of the site</h1>

<nav>
	<ul>
		<li><a href="#">Home</a></li>
		<li><a href="#">Portfolio</a></li>
		<li><a href="#">About</a></li>
		<li><a href="#">Contact</a></li>
	</ul>
</nav>

</header>

Header just contains everything, the “h1″ is the title of the site, and the “nav” contains the navigation menu. Feel free to add whatever you want to the HTML – the beauty of this script is that it will work no matter what you have in there.

CSS

In the CSS, we’ll first style the elements to look a certain way, and then we’ll add classes that will be applied to the elements when there isn’t enough space.

We’ll start off with some basic styling.

body {
font-family: Arial;
font-size: 15px;
line-height: 25px;
color: #595959;
background: #f8f8f8;
}

Now, the header. We’ll give this a percentage width of 60% to demonstrate the capabilites of the javascript we’ll write in a moment. You can set this to whatever you want, but I would suggest sticking with 60%.

header {
width: 60%;
min-width: 260px;
height: 50px;
margin: 0 auto;
margin-top: 30px;
background: #fff;
-webkit-box-shadow: 0px 0px 5px #888888;
box-shadow: 0px 0px 5px #888888;
-webkit-border-radius: 5px;
border-radius: 5px;
padding: 15px;
}

The “header” has a width of 60%, and it doesn’t get any smaller than 260px, because anything less than that is just unreasonably small. The height is 50px, and we’re setting it because the elements inside are floated. It’s centered using “margin: 0 auto”, and is 30px from the top of the page, and after that are just some styles to make it look nice.

Next up, we’re going to style the “h1″ title inside the header.

h1 {
font-size: 32px;
line-height: 50px;
float: left;
}

The font-size is 32px because that’s a reasonable size for the title of a website, and its line height is 50px so that it’s centered in the header. Since the header has a height of 50px, anything inside with a line-height of 50px will be vertically centered, and that’s what’s happening with the title and the navigation.

Now, we just need the “nav” to float to the right.

nav {
float: right;
}

However, the content inside the nav still looks ugly. Let’s fix this.

nav ul li {
display: inline;
padding-left: 10px;
line-height: 50px;
}

Each “li” is displayed inline so that they can all be on one line, they’re all 10 pixels from each other, and the line-height is 50px so that they’re vertically centered.

Unfortunately, the links inside still look pretty bad.

nav ul li a {
color: #515151;
text-decoration: none;
}

There. That nasty blue color is gone, and so is the underline. Much better.

At this point, everything is completely styled – but one thing is missing: the styles for the smaller, alternate versions of the header, the title, and the navigation.

Let’s make an alternate version of the header

.smallHeader {
height: 100px;
}

The height is now twice as tall as it was before, so that all the content inside still fits perfectly. Since the title and the navigation both have a line-height of 50px, and they’re on separate lines now, two rows of 50px is 100px.

Now, let’s make the title and the navigation both 100%, so they make the best use of the space availabe.

.smallTitle {
width: 100%;
text-align: center;
}

.smallNav {
width: 100%;
text-align: center;
}

They’re both as wide as possible, and have their text-align set to center so that the text inside is… centered.

jQuery

Make sure you have a copy of jQuery before starting this part.

Here’s how the javascript will work: at the beginning, we’ll declare 3 variables – the width of the title, the width of the navigation, and the width of both of them added together.

$(document).ready(function(){
			
	var origTitleWidth = $('h1').width();
	var origNavWidth = $('nav').width();
	var origSpaceTaken = origTitleWidth+origNavWidth;
	
});

These 3 variables are declared before any changes happen to the three elements, so we have their original widths, and not the altered ones.

Next, we declare the “rearrange” function.

function rearrange(){	

}

Now, we need to find out the width of the header to know whether or not to apply the modified styles to the title and the navigation.

function rearrange(){
	var headerWidth = $('header').width();
}

Once we have the header width, we need to set up two “if” statements.

function rearrange(){
	if(origSpaceTaken>headerWidth){

	}
	
	if(origSpaceTaken<headerWidth){

	}
}

This handles both possibilites: either the space taken is larger than the space available, or it is smaller.

If the space taken up by the elements inside is too large for the space available, we need those elements to receive their alternate styling.

function rearrange(){
	if(origSpaceTaken>headerWidth){
		$('header').addClass('smallHeader');
		$('h1').addClass('smallTitle');
		$('nav').addClass('smallNav');
	}
	
	if(origSpaceTaken<headerWidth){

	}
}

There. Now, if the header is too small, the elements inside are optimized for it. The other possibility is that they fit, so we don’t want the “small” classes.

function rearrange(){
	if(origSpaceTaken>headerWidth){
		$('header').addClass('smallHeader');
		$('h1').addClass('smallTitle');
		$('nav').addClass('smallNav');
	}
	
	if(origSpaceTaken<headerWidth){
		$('header').removeClass('smallHeader');
		$('h1').removeClass('smallTitle');
		$('nav').removeClass('smallNav');
	}
}

That makes sure that they have the proper styling when necessary.

Also, the function needs to be called to work.

rearrange();

Lastly, we need to set up a window resize function so that the script can change the elements without reloading the page.

$(window).resize(function(){
	rearrange();
});

Now, as soon as the window is resized, the script can check to see if the elements inside fit or not, and can apply the right styles when necessary.

Here’s the completed code:

$(document).ready(function(){
		
	var origTitleWidth = $('h1').width();
	var origNavWidth = $('nav').width();
	var origSpaceTaken = origTitleWidth+origNavWidth;
	
	function rearrange(){
	
		var headerWidth = $('header').width();
		
		if(origSpaceTaken>headerWidth){
			
			$('header').addClass('smallHeader');
			$('h1').addClass('smallTitle');
			$('nav').addClass('smallNav');
		}
		
		if(origSpaceTaken<headerWidth){
			
			$('header').removeClass('smallHeader');
			$('h1').removeClass('smallTitle');
			$('nav').removeClass('smallNav');
		}
		
	}
	
	rearrange();
	
	$(window).resize(function(){
		rearrange();
	});
	
});

I can see this as being especially useful for themes and templates, where you don’t know what the buyer will have as their site title or their navigation. This way, the styles will be applied at the perfect moment. That’s the end of this tutorial – if you have any questions or comments, feel free to post them below and I’ll do my best to help you out.

]]>
0
Design Lunatic <![CDATA[A Continuation of the Isotope Tutorial: Hash History with Isotope]]> http://www.designlunatic.com/?p=1200 2012-08-19T01:38:17Z 2012-08-19T01:38:17Z jQuery hashchange event.]]> I’ve written several tutorials on how to use isotope effectively and maximize its potential, and today’s post will be part of that series. What exactly does isotope do? It reorders the content on a page to only display what is necessary. The user can usually control this by clicking on links that change what the content is filtered by. But what if the user refreshes the page? Or decides that what the content was previously filtered by worked better, and presses the back button? Then, problems begin. The user has to reorder the content again to get back to where they were. Today’s post aims to solve that problem by using a plugin called jQuery hashchange event. This plugin works with the hash, the part after the url of the page that begins with “#”. It adds back button support to cycle through the hashes, and adds a handy “hashchange” jquery event.

As usual, before we begin on this post, grab a copy of the original isotope tutorial.

HTML

There are no changes from the HTML of the original isotope tutorial.

CSS

Nope, no changes here either. Keep reading.

Jquery

Here’s where the fun starts. We’ll rewrite the jquery from scratch, as there are several changes and optimizations to be made. Before you start writing the code, download the hashchange plugin. Once you’ve included the plugin, start off with jquery’s essential document.ready function.

$(document).ready(function(){

	var $container = $('#content');

});

There’s also a “$container” variable defined, which is just what we’re filtering.

Now, we need to create the code that will deal with appending values to the URL when a link is clicked.

$('#nav a').click(function(){
	var selector = $(this).attr('data-filter');

	location.hash = selector;

	return false;
});

The above code takes the “data-filter” attribute of the link that was just clicked, and appends it the url via the “location.hash” method. Then, there’s a return false, so the link isn’t followed. The above code works fine, but personally, I don’t like what is appended to the url. I think the dot before the category is extra – so let’s get rid of it.

$('#nav a').click(function(){
	var selector = $(this).attr('data-filter');

	var prettyselector = selector.substr(1);
  
	location.hash = prettyselector;

	return false;
});

With this addition, the URL looks cleaner and is nicer to look at. The above code now does exactly what we want it to do.

At this point, we’ll start using the capabilities of the “hashchange” plugin we’ve included.

$(window).hashchange( function(){

});

This is a “hashchange” function. When the hash of the URL is modified, the function fires. We can use this to filter the content as soon as a “hashchange” is detected.

$(window).hashchange( function(){
	var hashfilter = "." + location.hash.substr(1);
	
	$container.isotope({
		filter: hashfilter,
		animationOptions: {
			duration: 750,
			easing: 'linear',
			queue: false,
		}
	});

});

The “hashfilter” variable may seem a bit complex at first, but it’s quite simple. We’re taking the “location.hash”, which is the current hash of the URL, and deleting the first character. Why? Because the first character is a “#”, and we don’t need it. We then append a period to the beginning of a variable. Here’s what the process looks like: #cat1 => cat1 => .cat1.

While it may seem that the “hashchange” function works exactly as it has to, that’s incorrect. There’s one big issue with this – try clicking on the “All” button. Notice how nothing happens? That needs fixing.

$(window).hashchange( function(){
	
	if(location.hash!="#"){
		var hashfilter = "." + location.hash.substr(1);
	}
	else{
		var hashfilter = "*";
	}

	$container.isotope({
		filter: hashfilter,
		animationOptions: {
			duration: 750,
			easing: 'linear',
			queue: false,
		}
	});

});

The “if…else” statement fixes this. If the “location.hash” is NOT equal to a blank, the “hashfilter” is what created earlier. If it IS a blank space, then the “hashfilter” is a “*”, which basically means “All” in isotope.

We’re almost done – there’s just one thing left. If the page doesn’t get refreshed, everything works exactly as it should – but what if the page is refreshed, or is opened in a new window? The code doesn’t know what to filter it by, so it just goes with “*”. This is easy to fix though; we already wrote all the code we need.

$(document).ready(function(){
	var $container = $('#content');
		
	if(location.hash!=""){
		var hashfilter = "." + location.hash.substr(1);
	}
	else{
		var hashfilter = "*";
	}
		
	$container.isotope({
		filter: hashfilter,
		animationOptions: {
			duration: 750,
			easing: 'linear',
			queue: false,
		}
	});

Boom. Copy-pasted from inside the “hashchange” function, and it does exactly what we need to it do. At this point, everything should work perfectly for you. If it doesn’t, just download the files for the post and compare them to yours, but if it does, good job! That’s the end of this tutorial. If you have any questions or comments, feel free to post them below, and I’ll do my best to answer them.

]]>
10
Design Lunatic <![CDATA[A Continuation of the Isotope Tutorial: Combination Filters]]> http://www.designlunatic.com/?p=1177 2012-07-26T04:55:04Z 2012-07-26T04:55:04Z Isotope.js is a powerful tool for creating dynamic webpages with interactive capabilities. It does this by using “filtering”, by which certain elements on the page are removed or added, depending on what the user requests. This by itself is incredibly useful, but it can be made even better, by using combination filters. This allows the user to select two criteria by which content is filtered. In this tutorial, I’ll show how to do just that.

This post will be based on the code from the isotope tutorial I wrote a while ago, so grab a copy of the code from there.

HTML

The HTML structure is the same as in the original isotope tutorial, but with minor differences in the class names and titles.

Here’s a sample content box:

<div class="box june y2010">
	<h2 class="box-title">Lorem Ipsum - June, 2010</h2>
	<div class="box-text">
	Urna vut, eros aliquet sagittis augue? Augue adipiscing duis? Et a placerat, magna enim? Lacus sit. Nunc montes tristique purus auctor. Nascetur? Vut amet, phasellus pulvinar et odio. Ut aliquet integer sed enim ac amet nunc? Tincidunt sit, cum ridiculus, placerat cum, vut magna ridiculus ut phasellus ridiculus? Eu hac, mattis adipiscing, montes adipiscing urna montes rhoncus!
	</div>
</div>

We have a class called “june”, which is the month this post was published, and a class called “y2010″, which is the year. It’s not possible to have a class with just numbers, so the “y” is necessary. The same concept applies to every other post.

<div class="box june y2010">
	<h2 class="box-title">Lorem Ipsum - June, 2010</h2>
	<div class="box-text">
	Urna vut, eros aliquet sagittis augue? Augue adipiscing duis? Et a placerat, magna enim? Lacus sit. Nunc montes tristique purus auctor. Nascetur? Vut amet, phasellus pulvinar et odio. Ut aliquet integer sed enim ac amet nunc? Tincidunt sit, cum ridiculus, placerat cum, vut magna ridiculus ut phasellus ridiculus? Eu hac, mattis adipiscing, montes adipiscing urna montes rhoncus!
	</div>
</div>
			
<div class="box july y2010">
	<h2 class="box-title">Lorem Ipsum - July, 2010</h2>
	<div class="box-text">
	Urna vut, eros aliquet sagittis augue? Augue adipiscing duis? Et a placerat, magna enim? Lacus sit. Nunc montes tristique purus auctor. Nascetur? Vut amet, phasellus pulvinar et odio. Ut aliquet integer sed enim ac amet nunc? Tincidunt sit, cum ridiculus, placerat cum, vut magna ridiculus ut phasellus ridiculus? Eu hac, mattis adipiscing, montes adipiscing urna montes rhoncus! Odio placerat pellentesque risus urna elit, odio phasellus, rhoncus, est ridiculus purus etiam, penatibus integer! 
	</div>
</div>
			
<div class="box august y2010">
	<h2 class="box-title">Lorem Ipsum - August, 2010</h2>
	<div class="box-text">
	Urna vut, eros aliquet sagittis augue? Augue adipiscing duis? Et a placerat, magna enim? Lacus sit. Nunc montes tristique purus auctor. Nascetur?
	</div>
</div>
			
<div class="box june y2011">
	<h2 class="box-title">Lorem Ipsum - June, 2011</h2>
	<div class="box-text">
	Amet dolor? Diam cras ac quis a ut, augue massa cursus natoque cursus in sociis rhoncus, scelerisque mus ac. Pellentesque odio rhoncus, aliquet tempor? Nisi cursus lorem tincidunt penatibus eu scelerisque! Scelerisque mid rhoncus turpis eros? Nunc rhoncus in turpis, mus, nec augue, odio, mid tempor aliquam, ultricies.
	</div>
</div>

<div class="box july y2011">
	<h2 class="box-title">Lorem Ipsum - July, 2011</h2>
	<div class="box-text">
	Diam cras ac quis a ut, augue massa cursus natoque cursus in sociis rhoncus, scelerisque mus ac. Pellentesque odio rhoncus, aliquet tempor? Nisi cursus lorem tincidunt penatibus eu scelerisque! Scelerisque mid rhoncus turpis eros? Nunc rhoncus in turpis, mus, nec augue, odio, mid tempor aliquam, ultricies.
	</div>
</div>

<div class="box august y2011">
	<h2 class="box-title">Lorem Ipsum - August, 2011</h2>
	<div class="box-text">
	Urna vut, eros aliquet sagittis augue? Augue adipiscing duis? Et a placerat, magna enim? Lacus sit. Nunc montes tristique purus auctor. Nascetur? Vut amet, phasellus pulvinar et odio. Pellentesque odio rhoncus, aliquet tempor? Nisi cursus lorem tincidunt penatibus eu scelerisque! Scelerisque mid rhoncus turpis eros? Nunc rhoncus in turpis, mus, nec augue, odio, mid tempor aliquam, ultricies.
	</div>
</div>
			
<div class="box june y2012">
	<h2 class="box-title">Lorem Ipsum - June, 2012</h2>
	<div class="box-text">
	Urna vut, eros aliquet sagittis augue? Augue adipiscing duis? Et a placerat, magna enim? Lacus sit.
	</div>
</div>
			
<div class="box july y2012">
	<h2 class="box-title">Lorem Ipsum - July, 2012</h2>
	<div class="box-text">
	Amet dolor? Diam cras ac quis a ut, augue massa cursus natoque cursus in sociis rhoncus, scelerisque mus ac. Pellentesque odio rhoncus, aliquet tempor? Nisi cursus lorem tincidunt penatibus eu scelerisque! Scelerisque mid rhoncus turpis eros? Nunc rhoncus in turpis, mus, nec augue, odio, mid tempor aliquam, ultricies.
	</div>
</div>
			
<div class="box august y2012">
	<h2 class="box-title">Lorem Ipsum - August, 2012</h2>
	<div class="box-text">
	Urna vut, eros aliquet sagittis augue? Augue adipiscing duis? Et a placerat, magna enim? Lacus sit. Nunc montes tristique purus auctor. Amet dolor? Diam cras ac quis a ut, augue massa cursus natoque cursus in sociis rhoncus, scelerisque mus ac. Pellentesque odio rhoncus, aliquet tempor? Nisi cursus lorem tincidunt penatibus eu scelerisque! Scelerisque mid rhoncus turpis eros? Nunc rhoncus in turpis, mus, nec augue, odio, mid tempor aliquam, ultricies.
	</div>
</div>

The navigation is also slightly different. Since we have two different ways by which to filter the content, we’ll need two separate menus.

<div id="nav">
	<ul id="month">
		<li><a href="#" data-filter="*">All</a></li>
		<li><a href="#" data-filter=".june">June</a></li>
		<li><a href="#" data-filter=".july">July</a></li>
		<li><a href="#" data-filter=".august">August</a></li>
	</ul>
			
	<ul id="year">
		<li><a href="#" data-filter="*">All</a></li>
		<li><a href="#" data-filter=".y2010">2010</a></li>
		<li><a href="#" data-filter=".y2011">2011</a></li>
		<li><a href="#" data-filter=".y2012">2012</a></li>
	</ul>
</div>

There’s the menu for filtering the month, and the one for filtering the year. The data-filter attributes contain the class name by which the elements should be filtered.

CSS

Nothing to do here, carry on. The CSS is unchanged from the original isotope tutorial.

Jquery

We’ll rewrite the javascript from scratch here. First off, we’ll isotope the main container.

$(document).ready(function(){
	
	var $container = $('#content');
		
	$container.isotope({
		filter: '*',
		animationOptions: {
    		duration: 750,
    		easing: 'linear',
    		queue: false,
   		}
	});
});

Now, all the boxes are “isotoped”. Let’s get to work on the code powering the rearranging.

When the user clicks on a link, something needs to happen.

$('#month a').click(function(){
  		
  	var month = $(this).attr('data-filter');
  
  	$('#month').attr('data-active', month);

  	reorder();
 
 	return false;
});

When a link inside the “#month” div is clicked, that means the user wants to filter the posts according to a single month. So, we need to withdraw the value of the “data-filter” attribute to find out how exactly we need to filter the content. Now, we’ll create a “data-active” attribute to hold what month the content should be filtered by. Lastly, we call the reorder function, which we’ll create in a moment.

Very similar code can be used for the “year” links.

$('#year a').click(function(){
  		
  	var year = $(this).attr('data-filter');
  
  	$('#year').attr('data-active', year);
  
  	reorder();
  
  	return false;
});

Same logic as for the “month” links. When a link is clicked, store its “data-filter” attribute in the “data-active” attribute.

Lastly, we need to create the “reorder” function. When this function is called, it will check the values of the “#month” and “#year” divs, combine them, and filter the content with them. How is it possible to combine them? Simple: jQuery can use the following syntax in selecting elements:

$('.class1.class2')

This selects any elements with both classes. Isotope can also do this.

function reorder(){
		
	var month = $('#month').attr('data-active');
	var year = $('#year').attr('data-active');
	
	var filterString = month+year;
	
	$container.isotope({
		filter: filterString,
		animationOptions: {
   			duration: 750,
    		easing: 'linear',
   			queue: false,
   		}
	});		
}

This works in some cases, but there are some things this is missing. First of all, what if the user has only clicked a “month” link, but not a “year” link? The variable “filterString” will look something like this: “.julyundefined”. The “undefined” is there because the year hasn’t actually been defined yet, since a “year” link hasn’t been clicked yet.

So, to fix this:

if (typeof month === 'undefined') {
   	month = "";
}
if (typeof year === 'undefined') {
  	year = "";
}
		
var filterString = month+year;

This checks to see if each variable has been defined yet, and if it hasn’t, changes the variable’s value to “”, so isotope can filter properly even with only one link clicked.

The resulting function works better, but there are still some issues. If both “All” links are clicked, the “filterString” looks like this: “**”. That doesn’t work…

var filterString = month+year;
		
if(filterString=="**"){
	filterString = "*";	
}

…But this fixes it.

Lastly, we just need to tell the container to reorder its content:

$container.isotope({
	filter: filterString,
	animationOptions: {
  		duration: 750,
    	easing: 'linear',
   		queue: false,
   	}
});

So, the resulting function looks like this:

function reorder(){
	
	var month = $('#month').attr('data-active');
	var year = $('#year').attr('data-active');
	
	if (typeof month === 'undefined') {
    	month = "";
	}
	if (typeof year === 'undefined') {
    	year = "";
	}
		
	var filterString = month+year;
	
	if(filterString=="**"){
		filterString = "*";	
	}
		
	$container.isotope({
		filter: filterString,
		animationOptions: {
    		duration: 750,
    		easing: 'linear',
   			queue: false,
   		}
	});
			
}

With this code, you should be able to create combination filters on your site as well. That concludes this tutorial; I hope this helped in some way.

]]>
4
Design Lunatic <![CDATA[Create An Image Gallery With CSS3 3D Transforms]]> http://www.designlunatic.com/?p=1153 2012-06-23T07:16:48Z 2012-06-23T07:16:48Z CSS3 offers many exciting new opportunities for web designers looking to spice up their webpages, but one of the most interesting ones are the 3D transforms. Objects on the page can be manipulated in 3D space. In this tutorial, we’ll make an image gallery that utilizes 3D transforms to make things a bit more interesting.

HTML

The first thing we need is an element that will act as a container for the images.

<section id="images">

</section>

Now, we need to create the markup for each image.

<div class="image" title="This is random nonsense, this is random nonsense.">

	<img src="images/1.jpeg">

</div>

There’s a div with a class of “image”, along with a title. This title will be what’s contained in the caption on the back of the image. Inside the div, we have the actual image displayed.

Repeat this structure for 8 more images.

<section id="images">


<div class="image" title="This is random nonsense, this is random nonsense.">

	<img src="images/1.jpeg">

</div>

<div class="image" title="This is random nonsense, this is random nonsense.">

	<img src="images/2.jpeg">

</div>

<div class="image" title="This is random nonsense, this is random nonsense.">

	<img src="images/3.jpeg">

</div>

<div class="image" title="This is random nonsense, this is random nonsense.">

	<img src="images/4.jpeg">

</div>

<div class="image" title="This is random nonsense, this is random nonsense.">

	<img src="images/5.jpeg">

</div>

<div class="image" title="This is random nonsense, this is random nonsense.">

	<img src="images/6.jpeg">

</div>

<div class="image" title="This is random nonsense, this is random nonsense.">

	<img src="images/7.jpeg">

</div>

<div class="image" title="This is random nonsense, this is random nonsense.">

	<img src="images/8.jpeg">

</div>

<div class="image" title="This is random nonsense, this is random nonsense.">

	<img src="images/9.jpeg">

</div>


</section>

That’s all the HTML that’s necessary.

CSS

We’ll start off with some simple styling to make the page look nice. Right now, there’s just a bunch of images stacked vertically on the page. As far as layouts go, it’s not too bad. I’ve seen worse. But in this case, let’s make it a bit easier on the eyes.

body {
background: #eee;	
}

#images {
width: 450px;
height: 450px;
margin: 100px auto 0 auto;

-webkit-box-shadow: 0px 0px 20px 5px #888;
}

A box with a drop shadow on a grey background. Much better. Unfortunately, the images aren’t completely inside it yet.

.image {
width: 150px;
height: 150px;
float: left;
}

This looks nice, but there’s still a few things that need to be added.

.image {
width: 150px;
height: 150px;
float: left;
opacity: 0.9;
-webkit-transition: all 300ms ease;
}

.image:hover {
cursor: pointer;
opacity: 1;
}

That’s all the styles we need for now.

Remember the “title” attribute that each “image” div has? We need a way to put that on the back of each image, and this is where CSS3 psuedo-elements come in. Basically, with only CSS, it is possible to create another element right next to each “image” div we have on the page.

.image:after {
content: attr(title);
}

Now, right after each “image” will be an element with the contents of the “title” attribute inside. However, we also need to position this on the back of each image, and for that we will use CSS3 3D transforms. Before they can be used, the following code needs to be added to the parent element of whatever we’re going to manipulate.

-webkit-perspective: 1000;

Defining perspective is necessary for 3D elements to have… perspective, surprisingly enough. WSC does an excellent job of explaining this.

Without perspective, the elements would look boring and flat when rotating.

#images {
-webkit-perspective: 1000;
width: 450px;
height: 450px;
margin: 100px auto 0 auto;
background: #888;
-webkit-box-shadow: 0px 0px 20px 5px #888;
}

Now the “#images” section is properly set up.

You’ll notice that the “:after” part of each “image” still isn’t in the right spot. Let’s fix this.

.image:after {
content: attr(title);
display: block;
width: 138px;
height: 138px;
padding: 5px;
background: #eee;
border: 1px solid #999;
-webkit-transform: rotateY(180deg) translateY(-153px);
}

Right now, all the pseudo-elements are behind the images – but we can still see them. Paste this code into the “.image:after” part:

-webkit-backface-visibility: hidden;

This makes the backface of it invisible, which allows us to stick it to the back of another element without showing through.

Also, the text looks boring.

font-family: arial;
font-size: 16px;
line-height: 24px;
color: #333;

Better.

So far, for the “.image:after”, you should have the following code.

.image:after {
content: attr(title);
display: block;
width: 138px;
height: 138px;
padding: 5px;
background: #eee;
border: 1px solid #999;
-webkit-transform: rotateY(180deg) translateY(-153px);
-webkit-backface-visibility: hidden;

font-family: arial;
font-size: 16px;
line-height: 24px;
color: #333;
}

Javascript

What do we want to happen when we click on an image? For the image to flip over and reveal the caption underneath. There are several ways to do this, but let’s just use some javascript.

Before we begin, include the jquery library in your code.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>

Now, let’s start.

$(document).ready(function(){

});

This part is necessary so that the code inside only executes when all the elements on the page are fully loaded.

Let’s think this through; we want something to happen when an image is clicked.

$('.image').click(function(){

});

We want it to switch back and forth between being rotated 180 degrees around the Y axis and being rotated 0 degrees around the Y axis. For this, we’ll use the HTML5 “data-” attributes capability. Part of HTML5 is that it is now perfectly acceptable to define a custom attribute beginning with “data-”, such as “data-flipped”, which is what we’ll use. In here, we’ll store whether or not that particular element is flipped.

$('.image').click(function(){
	var flipped = $(this).attr('data-flipped');
});

We can now use this to check if the element is flipped or not.

if(flipped=='yes'){	
	$(this).attr('data-flipped','no');
}
else {
	$(this).attr('data-flipped','yes');			
}

If it isn’t flipped, it is after being clicked. If it was, now it isn’t. Simple. However, this doesn’t actually make the thing flip. Let’s fix that.

if(flipped=='yes'){	
	$(this).attr('data-flipped','no');
			
	$(this).attr('style','-webkit-transform: rotateY(0deg);');
}
else {
	$(this).attr('data-flipped','yes');
			
	$(this).attr('style','-webkit-transform: rotateY(-180deg);');
			
}

Done. Here’s all the code you should have:

$(document).ready(function(){
	
	$('.image').click(function(){
		var flipped = $(this).attr('data-flipped');
		
		
		if(flipped=='yes'){	
			$(this).attr('data-flipped','no');
			
			$(this).attr('style','-webkit-transform: rotateY(0deg);');
		}
		else {
			$(this).attr('data-flipped','yes');
			
			$(this).attr('style','-webkit-transform: rotateY(-180deg);');
			
		}
	
	});
	
});

At this point, you should have a working image gallery with flipping images and captions. I hope you enjoyed creating this, and that you learned something today. As always, the comment section is below if you have any questions or… well, comments.

]]>
0
Design Lunatic <![CDATA[A Continuation of the Isotope Tutorial: Highlight the currently active link]]> http://www.designlunatic.com/?p=1122 2012-05-20T19:52:33Z 2012-05-20T19:52:33Z Isotope.js, the user won't know what is currently being displayed. In this post, I'll show how that can be fixed so that the user can have an excellent experience even on a site using Isotope.]]> In web design, the navigation bar is crucial in telling the user where he is located. Usually, the user is further helped out by highlighting the currently active menu item. For example, if the user is on the “About Us” page, the “About Us” link in the navigation bar will be styled to look different. Unfortunately, if the site uses Isotope.js, the user won’t know what is currently being displayed. In this post, I’ll show how that can be fixed so that the user can have an excellent experience even on a site using Isotope.

This post will be based on the code from the isotope tutorial I wrote a while ago, so grab a copy of the code from there.

HTML

The HTML we’ll use is identical to the code from the isotope tutorial you just downloaded, except for one small thing.

Add data-current="" to the #content div, so that the result looks like this:

<div id="content" data-current="">

We’ll be using this attribute to store the category that is currently being shown.

CSS

The CSS is exactly the same as from the isotope tutorial previously. No need to change anything here.

Javascript

We’ll rewrite the javascript code from the previous tutorial, as it has changed considerably.

First of all, make a nice $(document).ready function:

$(document).ready(function(){

});

Now, we need to write the code that will “isotope” the boxes on the page.

var $container = $('#content');
var toFilter = '*';

$container.isotope({
	filter: toFilter,
	animationOptions: {
		duration: 750,
		easing: 'linear',
		queue: false,
	}
});

Here, the variable $container is whatever container you want to isotope. The variable toFilter is what the $container is filtered by. The reason we have a variable for this is because later on in the code, we have to know what what $container is filtered by. The rest of the code is isotope-specific, and is completely self-explanatory.

Remember that “data-current” attribute on the $container? We’ll start to use it now.

$container.attr('data-current',toFilter);

This code sets teh “data-current” attribute to what the $container was originally filtered by. This way, we can highlight the currently active navigation as soon as the page loads. More on that later.

We can now write the function that will determine what the $container is currently being filtered by, which we’ll call “checkActive”.

function checkActive(){

	$('#nav a').each(function(){
	
	});

}

Inside the “checkActive” function, we have a .each function. This basically iterates over each element that matches the selector. In this case, the code inside the “each” function repeats itself for each #nav a.

Now, take a look at the title of each nav link. Notice the fact that it doesn’t have a “.” at the beginning of it. This needs to be fixed before we can accurately compare the “data-current” attribute with the title of each nav link.

function checkActive(){

	$('#nav a').each(function(){
		
		var title = $(this).attr('title');	
		title = '.'+title;
		
	});

}

This takes the title attribute of the nav link the each function is currently iterating over, and adds a “.” to the beginnnig of it.

But wait! What if the title attribute is “*”, like in the link that says “All”?

function checkActive(){

	$('#nav a').each(function(){
		
		var title = $(this).attr('title');	
		title = '.'+title;
		
		if(title=='.*'){
			title = '*';
		}
		
	});

}


That fixes it.

In order to find out which link to highlight, we need to find out which category is currently being displayed.

function checkActive(){

	$('#nav a').each(function(){
		
		var title = $(this).attr('title');	
		title = '.'+title;
		
		if(title=='.*'){
			title = '*';
		}
		
		var currentCat = $container.attr('data-current');
	});

}

Now, we can compare the two to find out whether the link the each function is currently on is the right one or not.

if(title==currentCat){
	$(this).css({
		color: '#00ff00'
	});
}

Here’s what we have so far:

function checkActive(){

	$('#nav a').each(function(){
		
		var title = $(this).attr('title');	
		title = '.'+title;
		
		if(title=='.*'){
			title = '*';
		}
		
		var currentCat = $container.attr('data-current');
		
		if(title==currentCat){
			$(this).css({
				color: '#00ff00'
			});
		}
		
	});

}

However, there’s a slight problem with this code: the links won’t return to their previous states if the active category changes. We can fix this by making a type of “reset” that will make all links the way they were originally, and then changing whichever one needs to be changed.

function checkActive(){

	$('#nav a').each(function(){
		
		$(this).css({
			color: '#595959'
		});
		
		var title = $(this).attr('title');	
		title = '.'+title;
		
		if(title=='.*'){
			title = '*';
		}
		
		var currentCat = $container.attr('data-current');
		
		if(title==currentCat){
			$(this).css({
				color: '#00ff00'
			});
		}
		
	});

}

We can now create the rest of the javascript code.

Here’s where we left off:

var $container = $('#content');
var toFilter = '*';

$container.isotope({
	filter: toFilter,
	animationOptions: {
		duration: 750,
		easing: 'linear',
		queue: false,
	}
});

$container.attr('data-current',toFilter);

checkActive();

With this code, the “checkActive” function will fire right after the $container is isotoped, and will highlight the “All” link.

Now, we need to make the nav links actually work.

$('#nav a').click(function(){
	return false;
});

This way, when a nav link is clicked, it won’t actually redirect the user to a different page.

In order to filter the $container, we need to define a few variables.

$('#nav a').click(function(){
	
	var title = $(this).attr('title');
	var text = $(this).text();
		
	return false;
});		

Now, we have to check with or not the link that was just clicked is the “All” link or not.

$('#nav a').click(function(){
	
	var title = $(this).attr('title');
	var text = $(this).text();
		
	if(text == "All"){
		var selector = title;
	}
	else {
		var selector = "." + title;
	}	
	
	
	return false;
});	

Next, we need to set the “data-current” attribute of the $container to reflect what it is being filtered by.

$('#nav a').click(function(){
	
	var title = $(this).attr('title');
	var text = $(this).text();
		
	if(text == "All"){
		var selector = title;
	}
	else {
		var selector = "." + title;
	}	
	
	$container.attr('data-current',selector);
	
	return false;
});	

Now that we’ve defined what the $container is currently being filtered by, we need to actually filter the $container.

$('#nav a').click(function(){
	
	var title = $(this).attr('title');
	var text = $(this).text();
		
	if(text == "All"){
		var selector = title;
	}
	else {
		var selector = "." + title;
	}	
	
	$container.attr('data-current',selector);
	
	$container.isotope({ 
		filter: selector,
		animationOptions: {
			duration: 750,
			easing: 'linear',
			queue: false,
		}
	});
	
	return false;
});	

After the $container has been filtered, we have to run the “checkActive” function to highlight the currently active link.

$('#nav a').click(function(){
	
	var title = $(this).attr('title');
	var text = $(this).text();
		
	if(text == "All"){
		var selector = title;
	}
	else {
		var selector = "." + title;
	}	
	
	$container.attr('data-current',selector);
	
	$container.isotope({ 
		filter: selector,
		animationOptions: {
			duration: 750,
			easing: 'linear',
			queue: false,
		}
	});
	
	checkActive();
	
	return false;
});	

And there you have it: upon clicking a link in the navigation, it becomes different-looking so that the user knows what is currently being displayed. Now, you may wonder why we didn’t just make the link change color upon being clicked without worrying about the “data-current” attribute and all that. The reason is that this code works much more flexibly and with many other situations. For example, what if there’s a link inside the content of the page? All you need to do is modify the $('#nav a') selector to include links inside the post, and when a link in the post is clicked that filters the content, the navigation changes to reflect that. Or, what if there’s another piece of code that needs to know what category is currently being displayed? You don’t even have to modify anthing! Just find out the “data-current” attribute of the $container, and you’re done.

In other words, this code is highly flexible and adaptible, and not just this situation specific. I hope you learned something from this tutorial. If you have any questions or comments, feel free to use the comment form below.

]]>
13
Design Lunatic <![CDATA[CSS3 Fade Effect]]> http://www.designlunatic.com/?p=1049 2012-03-27T22:52:58Z 2012-03-27T22:52:58Z Today, I’ll be showing how to create an awesome CSS3 hover effect that is normally done with javascript. This one is particularly useful for masonry layouts and image galleries.

You’ll need to download the files if you want the images in the demo, or you can just dig up some of your own images.

HTML

The HTML here is extremely basic, with just a container element and 9 images inside.

<section id="images">

<img src="images/1.jpg">
<img src="images/2.jpg">
<img src="images/3.jpg">
<img src="images/4.jpg">
<img src="images/5.jpg">
<img src="images/6.jpg">
<img src="images/7.jpg">
<img src="images/8.jpg">
<img src="images/9.jpg">

</section>

This is all you need.

CSS

The CSS is where it gets a bit more interesting. First of all, we have to style the container div so that it sits in the center of the page.

#images {
width: 600px;
margin: 0 auto;
margin-top: 50px;
}
1

We'll need to add some basic styles to the "img" element.
1
#images img {
float: left;
opacity: 0.8;

-webkit-transition: all 400ms ease;
-moz-transition: all 400ms ease;
-ms-transition: all 400ms ease;
-o-transition: all 400ms ease;
transition: all 400ms ease;
}

Each image has a lower opacity to start off with and will animate its properties. The “float: left” is just for layout purposes.

Now, we have to actually create the CSS effect itself. Here’s how this works: When we hover over the #images container, we’ll style all of the images inside to animate to a lower opacity. We’ll also add a hover style to the “img” element so that its opacity becomes higher. This way, the hovered image will be the focus of the page.

#images:hover img {
opacity: 0.7;
}

#images img:hover {
opacity: 0.85;
}

#images:active img{
opacity: 0.65;
}

#images img:active {
opacity: 0.9;
}

As you can see, there are 4 different states for an image: Default, hovered, when another image is hovered, and active.

This creates an interesting effect, and with only CSS3! This method is also useful because it gracefully degrades in older browsers. Users with older browsers won’t get the cool effect, but they will still have all the functionality.

]]>
0
Design Lunatic <![CDATA[CSS3 Lavalamp Menu]]> http://www.designlunatic.com/?p=1037 2012-03-18T03:39:49Z 2012-03-18T03:39:49Z This jquery powered one, except for the keyboard control. Lavalamp menus are a unique way to add some creativity to your site, and if said menu is made with only CSS3 - that's pretty cool.]]> Today, I’ll be teaching you how to create a CSS3-only lavalamp menu. This menu will behave much like This jquery powered one, except for the keyboard control. Lavalamp menus are a unique way to add some creativity to your site, and if said menu is made with only CSS3 – that’s pretty cool.

HTML

The HTML here is very, very simple. It’s just a “ul” with some “li”s and links inside, as well as a “slider” div.

<ul id="nav">
<li><a href="#">Home</a></li>
<li><a href="#">Contact</a></li>
<li><a href="#">Help</a></li>
<li><a href="#">About</a></li>
<div id="slider"></div>
</ul>

This is all you need.

CSS

The CSS for this is very reusable. It’s very easy to just copy-paste this into your CSS file and have it working almost instantly, since all you need is just an unordered list, which is the format most nav menus follow.

First off, we’ll just give the “body” a simple grey background.

body {
background: #fbfbfb;
}

Now, we can style the “nav”.

#nav {
background: white;
border: 1px solid #CACACA;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-webkit-box-shadow: 0px 0px 3px 1px #ebebeb;
-moz-box-shadow: 0px 0px 3px 1px #ebebeb;
box-shadow: 0px 0px 3px 1px #ebebeb;	
height: 40px;
width: 400px;
margin: 0 auto;
margin-top: 50px;
position: relative;
}

Most of the stuff in there is purely for visual purposes, but one thing is necessary – the “position: relative”. Since our “slider” div will be “position: absolute”, we need it to be positioned “relative” to the nav.

Now, we just add some styles to the list items and the links inside.

#nav li {
float: left;
width: 100px;
height: 40px;
text-align: center;	
}

#nav li a {
color: #717171;
font-family: Arial;
font-size: 16px;
line-height: 40px;
display: block;
width: 100px;
height: 40px;
}

This is just for appearances, you can put whatever you want for these two elements.

The last thing we need to style is the “slider” div.

#slider {
left: 0px;
position: absolute;
top: 35px;
height: 5px;
background: #717171;
width: 100px;
-moz-border-radius-topleft: 0px;
-moz-border-radius-topright: 0px;
-moz-border-radius-bottomright: 10px;
-moz-border-radius-bottomleft: 10px;
-webkit-border-radius: 0px 0px 10px 10px;
border-radius: 0px 0px 10px 10px;
-webkit-transition: all 300ms ease;
-moz-transition: all 300ms ease;
-o-transition: all 300ms ease;
transition: all 300ms ease;
}

Once again, most of this is just for appearances, but there are a few necessary things in here. First of all, “position: absolute”. This allows us to put the div anywhere we want inside the “nav” without affecting any of the other elements. We also give it some CSS3 transition styling so that it smoothly animates to wherever we want it to be. One last thing about this div – it will animate back to whatever the “left” value originally is. Here, the “left” value is set to “0px”, so whenever the user hovers off of the menu, the “slider” div will move underneath the very first menu item. If you set the “left” value to be for example “100px”, the “slider” div will animate back to the second menu item when the user hovers off of the menu. This can be used to signal which is the currently active page.

Now, we can add the functionality to all this.

#nav li:nth-child(1):hover ~ #slider {
left: 0px;
}

#nav li:nth-child(2):hover ~ #slider {
left: 100px;
}

#nav li:nth-child(3):hover ~ #slider {
left: 200px;
}

#nav li:nth-child(4):hover ~ #slider {
left: 300px;
}

Boom. That’s it. Here’s how it works. When you hover over an “nth-child” of the “nav” menu, we use the “~” CSS selector to select the adjacent “slider” div and give it a new “left” value. The purpose of the “~” is to select any element that is after the first element. In our case, the “slider” is after each child of the “nav”, so we use the “~” to select it.

I hope you learned something useful from this tutorial. If you have any questions or comments, feel free to post them below.

]]>
5