So far we’ve built a solid HTML page and applied some styles. This tutorial will focus on adding interactivity to the website through JavaScript. We’ll split it in two parts:
- Adding the plugins and preparing the workspace
- Initializing the plugins and customizing them for our use
Plugins Overview
There are plenty of jquery plugins that we can use for this tutorial, but we’ll stick with the following:
Filter & sort magical layouts
This library is vast and powerful, but still requires some good programming skills to use. It has support for various type of layouts, for filtering and sorting.
Easily reveal elements as they enter the viewport.
I chose this library because it has support for both downward and upward scrolling. It reveals elements whenever they are visible in your viewport and it’s very easy to implement.
A jQuery plugin that provides smooth scrolling and advanced navigation for single page websites.
fancyBox is a tool that offers a nice and elegant way to add zooming functionality for images, html content and multi-media on your webpages. It is built on the top of the popular JavaScript framework jQuery and is both easy to implement and a snap to customize.
Preparing the Workspace
After finding the necessary plugins for our website, it’s time to download and reference them in our index.html
like this:
<!-- Javascript –––––––––––––––––––––––––––––––––––––––––––––––––– --> <script type="text/javascript" src="js/jquery.2.1.3.min.js"></script> <script type="text/javascript" src="js/isotope.pkgd.min.js"></script> <script type="text/javascript" src="js/scrollreveal.js"></script> <script type="text/javascript" src="js/singlenav.js"></script> <script type="text/javascript" src="js/jquery.fancybox.js"></script> <script type="text/javascript" src="js/scripts.js"></script>
As you can see, I downloaded them to a new folder called js
because in this way it’s easy to maintain and the files are organized.
The scripts.js
file is a blank file for now. We’ll use it to write extra JavaScript and initialize the plugins.
Now that everything is set in place let’s move to the next section, where we’ll play with each plugin.
Writing the Scripts
The first thing that you need to learn when writing jQuery
is $(document).ready(function(){});
. This will run everything inside the function once the DOM
is loaded. You can read more about it on learning jquery.
I really like to keep my code clean, so that’s why you’ll often see me storing selectors in variables (as you’ll see below), using two spaces for indentation and the guideline at 80 chars.
Hero Section
The hero section in our design should ideally have window.height
, effectively full-height. This is possible through CSS unit vh but since not all browsers support these units, we’ll stick to JavaScript.
To get the window height we’ll use window.innerHeight which outputs the height of the viewport
in px
.
// =Hero // Alway make hero-container height equal to window height var $heroContainer = $('.hero'); $heroContainer.height(window.innerHeight);
Here we applied the viewport height to the heroContainer
, but we also need to ensure that whenever the user resizes the browser, we will reapply the viewport height to the heroContainer
. The following code will listen to window resize and will modify the height of the heroContainer
on the fly:
// When user resize browser window, hero container needs to have the same // height as browser window height. $(window).resize(function() { $heroContainer.height(window.innerHeight); });
Storing selectors in variables makes them easy to maintain and reuse. You should have something like this:
// =Hero // Alway make hero-container height equal to window height var $heroContainer = $('.hero'); $heroContainer.height(window.innerHeight); // When user resize browser window, hero container needs to have the same // height as browser window height. $(window).resize(function() { $heroContainer.height(window.innerHeight); });
Menu
First things first, let’s store the selectors that we are going to use in variables. For now, we need the menuIcon
, navigation
, mainNavigation
and navigationLink
. The variables should look like this:
var $menuIcon = $('.menu-icon'), $navigation = $('.navigation'), $mainNavigation = $('.main-navigation'), $navigationLink = $('.main-navigation a');
When we have multiple variable declarations, there’s no need to repeat var
, you can comma separate the variables.
Let’s attach a click event on menuIcon
which should add a class name active
to the mainNavigation
. The active
class on mainNavigation
is styled within our CSS and makes it visible.
$menuIcon.click(function(e) { e.preventDefault(); $navigation.toggleClass('active'); });
Let’s now use the SingleNavPage
plugin and initiliaze it in the mainNavigation
selector like this:
$mainNavigation.singlePageNav({ filter: ':not(.external)', speed: 1000, currentClass: 'current', easing: 'swing', updateHash: false, beforeStart: function() { }, onComplete: function() { $navigation.removeClass('active'); } });
Here I also added a scroll listener that will add a different class to the menuItem
if the user scrolls more than viewport height. I check if window.scrollY
is greater than window.innerHeight
(viewport height) I toggle active
class for the menuItem
$(window).scroll(function() { if(window.scrollY > window.innerHeight) { $menuIcon.addClass('active'); } else { $menuIcon.removeClass('active'); } });
The entire code for the menu now looks like this:
// Menu initialization var $menuIcon = $('.menu-icon'), $navigation = $('.navigation'), $mainNavigation = $('.main-navigation'), $navigationLink = $('.main-navigation a'); $(window).scroll(function() { if(window.scrollY > window.outerHeight) { $menuIcon.addClass('active'); } else { $menuIcon.removeClass('active'); } }); $menuIcon.click(function(e) { e.preventDefault(); $navigation.toggleClass('active'); }); $mainNavigation.singlePageNav({ filter: ':not(.external)', speed: 1000, currentClass: 'current', easing: 'swing', updateHash: false, beforeStart: function() { }, onComplete: function() { $navigation.removeClass('active'); } });
Scrollreveal
The initialization for ScrollReveal
is quite simple but I added a little configuration to it. If you’d like to find out more about the usage of it and more config options you should check the project on Github. The code for the scrollreveal initialization is as follows:
// Scrollreveal initialize var config = { easing: 'hustle', reset: false, delay: 'onload', opacity: .2, vFactor: 0.2, mobile: false } window.sr = new scrollReveal(config);
Work
In this case, what is our script going to do for us? There are three big things:
- transform work list into an isotope layout
- filter the items
- add an
active
class to the active filter option
We’ll begin by storing the required variables for this plugin.
javascript
var $workFilterLinks = $('.work-filters li'),
$container = $('.work-items');
The next thing is to attach a click handler for each filter link. This will remove the active
class from all filters and add it to the clicked item.
$workFilterLinks.find('a').click(function(){ $workFilterLinks.removeClass('active'); $(this).parent().addClass('active'); return false; });
Inside the click callback function, we’ll target the container
and create an isotope instance with filter and layout mode as options.
$container.isotope({ // options filter: $(this).attr('data-filter'), itemSelector: '.isotope-item', animationEngine : "best-available", masonry: { columnWidth: '.isotope-item' } });
This will filter the isotope items by the filter’s data-filter
attribute and will add the masonry
layout for the work section.
The code for our work section should now look similar to this:
// =Work // Isotope filters var $workFilterLinks = $('.work-filters li'), $container = $('.work-items'); $workFilterLinks.find('a').click(function(){ $workFilterLinks.removeClass('active'); $container.isotope({ // options filter: $(this).attr('data-filter'), itemSelector: '.isotope-item', animationEngine : "best-available", masonry: { columnWidth: '.isotope-item' } }); $(this).parent().addClass('active'); return false; });
Fancybox
The last plugin that we are going to use is Fancybox
. This plugin will be attached to the play
button from the video section.
// Fancybox $('.video-play').fancybox({ width : '100%', closeClick : false });
After writing the JavaScript part, this is how the code should look:
$(document).ready(function(){ // =Hero // Alway make hero-container height equal to window height var $heroContainer = $('.hero'); $heroContainer.height(window.innerHeight); // When user resize browser window, hero container needs to have the same // height as browser window height. $(window).resize(function() { $heroContainer.height(window.innerHeight); }); // =Work // Isotope filters var $workFilterLinks = $('.work-filters li'), $container = $('.work-items'); $workFilterLinks.find('a').click(function(){ $workFilterLinks.removeClass('active'); $container.isotope({ // options filter: $(this).attr('data-filter'), itemSelector: '.isotope-item', animationEngine : "best-available", masonry: { columnWidth: '.isotope-item' } }); $(this).parent().addClass('active'); return false; }); // Menu initialization var $menuIcon = $('.menu-icon'), $navigation = $('.navigation'), $mainNavigation = $('.main-navigation'), $navigationLink = $('.main-navigation a'); $(window).scroll(function() { if(window.scrollY > window.outerHeight) { $menuIcon.addClass('active'); } else { $menuIcon.removeClass('active'); } }); $menuIcon.click(function(e) { e.preventDefault(); $navigation.toggleClass('active'); }); $mainNavigation.singlePageNav({ filter: ':not(.external)', speed: 1000, currentClass: 'current', easing: 'swing', updateHash: false, beforeStart: function() { }, onComplete: function() { $navigation.removeClass('active'); } }); // Scrollreveal initialize var config = { easing: 'hustle', reset: false, delay: 'onload', opacity: .2, vFactor: 0.2, mobile: false } window.sr = new scrollReveal( config ); // Fancybox $(".video-play").fancybox({ closeClick : false, }); });
Final Thoughts
And we’re done! Take a look at what we’ve built!
I hope that you enjoyed this series and you learned plenty of new things. Throughout this process I’ve shared some techniques that I use on a daily basis and I hope you’ll take them onboard and share them.
I’d love to see what you’ve coded so far–share with us anything you build using some of these techniques!
Clik here to view.

Clik here to view.
Clik here to view.