From our sponsor: Meco is a distraction-free space for reading and discovering newsletters, separate from the inbox.
In this tutorial we will create a fullscreen gallery with jQuery. The idea is to have a thumbnail of the currently shown fullscreen image on the side that flips when navigating through the images. The big image will slide up or down depending where we are navigating to. We will add navigation controls for the mousewheel and for keys. The thumbnail will have a zoom and and a fullscreen option, making the image in the background appear in fullscreen mode or as a complete image, resized to fit in the page.
We will be using Flip!, a jQuery plugin by Lucca Manno that flips elements.
And we will also be using the jQuery Mousewheel Plugin by Brandon Aaron.
The beautiful images are by talented Polina Efremova. Visit her website and check out her profile on Behance.
Let’s get started with the markup!
Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.
The Markup
First, we will add a loading element that we want to show when the images are being loaded:
<div id="tf_loading" class="tf_loading"></div>
Then, we will create a container for all the images that will be shown in fullscreen:
<div id="tf_bg" class="tf_bg"> <img src="images/1.jpg" alt="Image 1" longdesc="images/thumbs/1.jpg" /> <img src="images/2.jpg" alt="Image 2" longdesc="images/thumbs/2.jpg"/> <img src="images/3.jpg" alt="Image 3" longdesc="images/thumbs/3.jpg"/> <img src="images/4.jpg" alt="Image 4" longdesc="images/thumbs/4.jpg"/> <img src="images/5.jpg" alt="Image 5" longdesc="images/thumbs/5.jpg"/> <img src="images/6.jpg" alt="Image 6" longdesc="images/thumbs/6.jpg"/> <div class="tf_pattern"></div> </div>
We will use the “longdesc” attribute to indicate the path to the respective thumbnail. The last div element will server as the overlay pattern.
Next, we will add a container for the contents that are shown on the left bottom corner of the screen.
<div id="tf_content_wrapper" class="tf_content_wrapper"> <div class="tf_content" id="content1" style="display:block;"> <h2>Dreamer</h2> <p>Far far away, behind the word mountains, ... </p> </div> <div class="tf_content" id="content2"> ... </div> ... </div>
Each box with a heading will be inside of an element with the class “tf_content”.
The structure for the thumbnail image on the right side of the screen we look as follows:
<div id="tf_thumbs" class="tf_thumbs"> <span id="tf_zoom" class="tf_zoom"></span> <img src="images/thumbs/1.jpg" alt="Thumb1"/> </div>
The span will either have the class “tf_zoom” or “tf_fullscreen” depending on in which mode we are in.
And finally, we will add some elements for the navigation:
<div id="tf_next" class="tf_next"></div> <div id="tf_prev" class="tf_prev"></div>
Let’s take a look at the style.
The CSS
After doing a simple reset to the body and html, we will define the style for the full images container:
.tf_bg{ width:100%; height:100%; position:fixed; top:0px; left:0px; }
The container will be fixed and occupy the whole screen. The images inside will be of absolute positioning and the real width and height will be calculated dynamically in our jQuery function:
.tf_bg img{ position:absolute; top:0px; left:0px; width:100%; z-index: 1; display:none; }
The pattern will as well be absolute and have a repeated background image:
.tf_pattern{ position:absolute; width:100%; height:100%; background:transparent url(../images/pattern.png) repeat top left; z-index:2; }
We will position the content absolutely, too:
.tf_content{ position:absolute; bottom:50px; left:50px; z-index:10; display:none; }
The heading of the content will have a different font, that we will embed using the Google Font API. We’ll come back to that later.
.tf_content h2{ color:#fff; font-size:90px; padding:0; margin:0; font-family: 'Dancing Script', arial, serif; text-shadow:1px 1px 2px #000; }
The paragraph of the content will have a repeated image as background and some nice box- and text-shadow:
.tf_content p{ color:#fff; padding:0; margin:0; background:transparent url(../images/bg_content.png) repeat top left; padding:40px; width:500px; font-family: 'PT Sans Narrow', arial, serif; font-size:20px; line-height:25px; text-transform:uppercase; text-shadow:2px 2px 1px #000; -moz-box-shadow:1px 1px 5px #202020; -webkit-box-shadow:1px 1px 5px #202020; box-shadow:1px 1px 5px #202020; border:4px solid #fff; }
The thumbnail container will be positioned in the middle of the screen on the right side. We accomplish that with setting the top to 50% and the top margin to negative half of its height. We will give the container a reflection, that can be seen in Webkit browsers:
.tf_thumbs{ position:absolute; z-index:12; right:50px; top:50%; margin-top:-79px; border:4px solid #fff; -moz-box-shadow:1px 1px 5px #202020; -webkit-box-shadow:1px 1px 5px #202020; box-shadow:1px 1px 5px #202020; -webkit-box-reflect: below 5px -webkit-gradient( linear, left top, left bottom, from(transparent), color-stop(0.6, transparent), to(rgb(18, 18, 18)) ); } .tf_thumbs img{ display:block; }
The navigation elements will be placed next to the thumbnail container:
.tf_next, .tf_prev{ width:35px; height:14px; position:absolute; top:50%; right:320px; z-index:100; cursor:pointer; background:transparent url(../images/nav.png) no-repeat top left; opacity:0.5; } .tf_next{ background-position:0px -14px; margin-top:80px; } .tf_prev{ background-position:0px 0px; margin-top:-55px; } .tf_next:hover, .tf_prev:hover{ opacity:0.9; }
The little icons for zoom and fullscreen mode will appear at the right top corner of the thumbnail:
.tf_zoom, .tf_fullscreen{ width:20px; height:20px; position:absolute; top:6px; right:6px; cursor:pointer; z-index:100; opacity:0.6; background:transparent url(../images/icons.png) no-repeat top left; } .tf_zoom{ background-position:0px -20px; } .tf_fullscreen{ background-position:0px 0px; } .tf_zoom:hover, .tf_fullscreen:hover{ opacity:0.9; }
The loading element will be positioned in the center of the screen:
.tf_loading{ position:fixed; top:50%; left:50%; margin:-30px 0px 0px -30px; width:60px; height:60px; background:#fff url(../images/loader.gif) no-repeat center center; z-index:999; opacity:0.7; }
And that was all the style. Let’s take a look at the JavaScript.
The JavaScript
First, we will include the following scripts:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js"></script> <script type="text/javascript" src="js/jquery.flip.js"></script> <script type="text/javascript" src="js/jquery-mousewheel-3.0.4/jquery.mousewheel.min.js"></script>
Then, we will add the preload function for the images:
(function($) { $.fn.preload = function(options) { var opts = $.extend({}, $.fn.preload.defaults, options); o = $.meta ? $.extend({}, opts, this.data()) : opts; var c = this.length, l = 0; return this.each(function() { var $i = $(this); $('<img/>').load(function(i){ ++l; if(l == c) o.onComplete(); }).attr('src',$i.attr('src')); }); }; $.fn.preload.defaults = { onComplete : function(){return false;} }; })(jQuery);
In our jQuery function, we will first cache some element and define some variables:
var $tf_bg = $('#tf_bg'), $tf_bg_images = $tf_bg.find('img'), $tf_bg_img = $tf_bg_images.eq(0), $tf_thumbs = $('#tf_thumbs'), total = $tf_bg_images.length, current = 0, $tf_content_wrapper = $('#tf_content_wrapper'), $tf_next = $('#tf_next'), $tf_prev = $('#tf_prev'), $tf_loading = $('#tf_loading');
Then, we will preload the images:
$tf_bg_images.preload({ onComplete : function(){ $tf_loading.hide(); init(); } });
The next function will show the first image and initialize some events:
function init(){ //get dimentions for the image, based on the windows size var dim = getImageDim($tf_bg_img); //set the returned values and show the image $tf_bg_img.css({ width : dim.width, height : dim.height, left : dim.left, top : dim.top }).fadeIn(); //resizing the window resizes the $tf_bg_img $(window).bind('resize',function(){ var dim = getImageDim($tf_bg_img); $tf_bg_img.css({ width : dim.width, height : dim.height, left : dim.left, top : dim.top }); }); //expand and fit the image to the screen $('#tf_zoom').live('click', function(){ if($tf_bg_img.is(':animated')) return false; var $this = $(this); if($this.hasClass('tf_zoom')){ resize($tf_bg_img); $this.addClass('tf_fullscreen') .removeClass('tf_zoom'); } else{ var dim = getImageDim($tf_bg_img); $tf_bg_img.animate({ width : dim.width, height : dim.height, top : dim.top, left : dim.left },350); $this.addClass('tf_zoom') .removeClass('tf_fullscreen'); } } ); //click the arrow down, scrolls down $tf_next.bind('click',function(){ if($tf_bg_img.is(':animated')) return false; scroll('tb'); }); //click the arrow up, scrolls up $tf_prev.bind('click',function(){ if($tf_bg_img.is(':animated')) return false; scroll('bt'); }); //mousewheel events - down / up button trigger the scroll down / up $(document).mousewheel(function(e, delta) { if($tf_bg_img.is(':animated')) return false; if(delta > 0) scroll('bt'); else scroll('tb'); return false; }); //key events - down / up button trigger the scroll down / up $(document).keydown(function(e){ if($tf_bg_img.is(':animated')) return false; switch(e.which){ case 38: scroll('bt'); break; case 40: scroll('tb'); break; } }); }
The next function takes care of showing the next or previous image:
function scroll(dir){ //if dir is "tb" (top -> bottom) increment current, //else if "bt" decrement it current = (dir == 'tb')?current + 1:current - 1; //we want a circular slideshow, //so we need to check the limits of current if(current == total) current = 0; else if(current < 0) current = total - 1; //flip the thumb $tf_thumbs.flip({ direction : dir, speed : 400, onBefore : function(){ //the new thumb is set here var content = ''; content +='<img src="' + $tf_bg_images.eq(current).attr('longdesc') + '" alt="Thumb' + (current+1) + '"/>'; $tf_thumbs.html(content); } }); //we get the next image var $tf_bg_img_next = $tf_bg_images.eq(current), //its dimentions dim = getImageDim($tf_bg_img_next), //the top should be one that makes the image out of the viewport //the image should be positioned up or down depending on the direction top = (dir == 'tb')?$(window).height() + 'px':-parseFloat(dim.height,10) + 'px'; //set the returned values and show the next image $tf_bg_img_next.css({ width : dim.width, height : dim.height, left : dim.left, top : top }).show(); //now slide it to the viewport $tf_bg_img_next.stop().animate({ top : dim.top },1000); //we want the old image to slide in the same direction, out of the viewport var slideTo = (dir == 'tb')?-$tf_bg_img.height() + 'px':$(window).height() + 'px'; $tf_bg_img.stop().animate({ top : slideTo },1000,function(){ //hide it $(this).hide(); //the $tf_bg_img is now the shown image $tf_bg_img = $tf_bg_img_next; //show the description for the new image $tf_content_wrapper.children() .eq(current) .show(); }); //hide the current description $tf_content_wrapper.children(':visible') .hide() }
The resize function will animate the image to a screen fitting size:
function resize($img){ var w_w = $(window).width(), w_h = $(window).height(), i_w = $img.width(), i_h = $img.height(), r_i = i_h / i_w, new_w,new_h; if(i_w > i_h){ new_w = w_w; new_h = w_w * r_i; if(new_h > w_h){ new_h = w_h; new_w = w_h / r_i; } } else{ new_h = w_w * r_i; new_w = w_w; } $img.animate({ width : new_w + 'px', height : new_h + 'px', top : '0px', left : '0px' },350); }
The last function will give us the dimensions of an image and its correct positioning:
function getImageDim($img){ var w_w = $(window).width(), w_h = $(window).height(), r_w = w_h / w_w, i_w = $img.width(), i_h = $img.height(), r_i = i_h / i_w, new_w,new_h, new_left,new_top; if(r_w > r_i){ new_h = w_h; new_w = w_h / r_i; } else{ new_h = w_w * r_i; new_w = w_w; } return { width : new_w + 'px', height : new_h + 'px', left : (w_w - new_w) / 2 + 'px', top : (w_h - new_h) / 2 + 'px' }; }
And that was all the jQuery. Now, we want to embed some fonts. For that we will include the following references in the head of our HTML:
<link href='http://fonts.googleapis.com/css?family=PT+Sans+Narrow' rel='stylesheet' type='text/css' /> <link href='http://fonts.googleapis.com/css?family=Dancing+Script' rel='stylesheet' type='text/css' />
And that’s all! We hope you enjoyed the tutorial and learning something new today!
Is it possible to have the images slide to the left or right, as well as up and down?
For example, could a user navigate down to a section which acts as the “title card” for a series of photographs, and then tap their right arrow so the “title card” slides away to the left, allowing them to navigate through the series by continuing to move right?
very impressive !!! thank
Hi !
Super Nice =)
I have the same question as KYAU.
Is there a short line of code to add to include buttons to slide to a specific image ?
Example: If I have 40 images I want to add one button for each image that scrolls to that specific image.
I would be super happy if anyone know
Thanks again…
Very nice work.
Just one word…Amazing 🙂
Which piece of the code do I need to change to remove those dots from the image and display the image as is.
Thanx in advance.
Keep rocking Mary Lou..
Got it…
I have the same question as Shawn.
Great stuff, like the “full screen” view.
mary lou,
first of all – thank you.
second: same question as chris – i’d love to have the pictures move lef-right instead of top-bottom. i manage to do so with the flip, but not the main picture. but isn’t that just a slight change to the js?
third: as others here, i wonder if there is a way to link directly to image 4, 8 or 11 from an additional text or image navigation.
thank you!
rik
Wonderful Work. I am impressed by your site. Thank you. I love it when I saw it at my first galence.
Wonderfull job, very nice!
But, when I activated the theme at my wp blog, I got the message: “The active theme is broken. Reverting to the default theme.”
Any idea about it?
Thanks…
oh sorry, I made a confusion… it´s not a wp theme 🙁
Is it possible to add a navigation to this kind of site instead of the arrows???
I am totally diggin this style!
Thanks !
No slide using Easing plugin 🙁
Thank you for a wonderful tutorial.
One question – all your images are roughly the same landscape size. Is there a recommended portrait size for the large images? When I use a portrait image it seems to scale off the screen.
Hi! Another Great Tutorial!
I am trying to fade from one image to another (instead of sliding). I would like to keep the keyboard & mouse control?
Any idea how to do that?
Thanks.
i tried it with IE 7 and the performance is horrible (as known the engine of it sucks big time)..
my question: are there some work-arounds or something to speed things up in IE7?
Thx a lot..
This is a great tutorial, !!!
One question i need to align my images to the top, cause on widescreens i see the middle of my pictures,
any help?
Thanks
How do you license your tutorials? Are they free to use in e.g commercial work like themes? Cause I just saw exactly your idea here http://www.gallyapp.com/tf_themes/atlas_wp/wp-content/themes/Atlas/switcher.php?pp_homepage_style=flip
Hello from Melbourne Australia
I have been looking for this for ages… however I need it horizontal…. and I Will pay $ if needed.
I have a horizontal 1 page site with 8 sections all requiring a full background image that needs to re-size proportionally with the browser.
just like this: Hello from Melbourne Australia
I have tried and tried… I need someone to DO this for me and I Will pay $ if needed.
I have a horizontal 1 page site with 8 sections all requiring a full background image that needs to re-size proportionally with the browser.
Please look at: [http://www.dancephotography.net.au/test1.htm]
.
Belinda X
infact… I just need to get this scrolling horizontally. Any suggestions and I would be so greatefuL ! xxxx
hi,many thanks! it looks wonderful! but, you know, i’m trying to use this for my portfolio, and i’d like it to be in the middle of my page (500px x 500px, let’s say) how can I achieve that? I’ve been dealing with css 100%s I’ve found so far, but doesn`t seem to work. Do i have to do anything with js? I can hardly understand js :((
is it possible to just have fullsize on the height and a fixed width? have almost only potrait images. not sure where to change this hm
Hey Michel and others who need portret support in the slider.
I noticed that the slider focuses on the horizontal/ landscape images when using it on a project myself yesterday. Below there is a fix for it, simple replace the below codes with the suggestions.
Replace the below function
—
function resize($img){
……
}
function getImageDim($img){
……
}
Replace with
—-
//animate the image to fit in the viewport
function resize($img){
var w_w = $(window).width(),
w_h = $(window).height(),
i_w = $img.width(),
i_h = $img.height(),
r_i = i_h / i_w,
new_w,new_h;
if(i_h > i_w){
new_w = w_w;
new_h = w_w * r_i;
if(new_h > w_h){
new_h = w_h;
new_w = w_h / r_i;
}
}
else{
new_h = w_w * r_i;
new_w = w_w;
}
$img.animate({
width : new_w + ‘px’,
height : new_h + ‘px’,
top : ‘0px’,
left : ((w_w/2) – (w_w/5.5)) + ‘px’
},700); /* Center the image */
}
//get dimentions of the image,
//in order to make it full size and centered
function getImageDim($img){
var w_w = $(window).width(),
w_h = $(window).height(),
r_w = w_h / w_w,
i_w = $img.width(),
i_h = $img.height(),
r_i = i_h / i_w,
new_w,new_h,
new_left,new_top;
if(r_w > r_i){
new_h = w_h;
new_w = w_h / r_i;
}
else{
new_h = w_w * r_i;
new_w = w_w;
}
return {
width : new_w + ‘px’,
height : new_h + ‘px’,
left : (w_w – new_w) / 10 + ‘px’, /* Standard /2 */
top : (w_h – new_h) / 10 + ‘px’ /* Standard /2 */
};
}
Thanks again for the tutorial Codrops.
Keep on rocking.
Hello Robin, I would like the same thing as Michel.
I tried your solution but it doesn’t work.
There is only the loading. Can you help me?
Thank you!!
Amelie please check the path to your images first. If he can’t find them the loader keeps showing. Also the thumbs need to have the names 1,2,3,4,5 (but not sure about it).
If that doesn’t fix it, then you can try the below code again.
//show next / prev image
function scroll(dir){
//if dir is “lr” (top -> bottom) increment current,
//else if “rl” decrement it
current = (dir == ‘lr’)?current + 1:current – 1;
//hide other content
$main_content.removeClass(“visible”);
$main_content_text.removeClass(“visible”);
$tf_content_wrapper.removeClass(“invisible”);
//we want a circular slideshow,
//so we need to check the limits of current
if(current == total) current = 0;
else if(current < 0) current = total – 1;
//flip the thumb
$tf_thumbs.flip({
direction : dir,
speed : 400,
bgColor : '#252525',
color : '#252525',
onBefore : function(){
//the new thumb is set here
var content = '’;
content +=”;
$tf_thumbs.html(content);
}
});
//we get the next image
var $tf_bg_img_next = $tf_bg_images.eq(current),
//its dimentions
dim = getImageDim($tf_bg_img_next),
//the top should be one that makes the image out of the viewport
//the image should be positioned up or down depending on the direction
top = (dir == ‘lr’)?$(window).height() + ‘px’:-parseFloat(dim.height,10) + ‘px’;
//set the returned values and show the next image
$tf_bg_img_next.css({
width : dim.width,
height : dim.height,
left : dim.left,
top : top
}).show();
//now slide it to the viewport
$tf_bg_img_next.stop().animate({
top : dim.top
},1000);
//we want the old image to slide in the same direction, out of the viewport
var slideTo = (dir == ‘lr’)?-$tf_bg_img.height() + ‘px’:$(window).height() + ‘px’;
$tf_bg_img.stop().animate({
top : slideTo
},1000,function(){
//hide it
$(this).hide();
//the $tf_bg_img is now the shown image
$tf_bg_img = $tf_bg_img_next;
//show the description for the new image
$tf_content_wrapper.children()
.eq(current)
.show();
});
//hide the current description
$tf_content_wrapper.children(‘:visible’)
.hide()
}
//animate the image to fit in the viewport
function resize($img){
var w_w = $(window).width(),
w_h = $(window).height(),
i_w = $img.width(),
i_h = $img.height(),
r_i = i_h / i_w,
new_w,new_h;
if(i_h > i_w){
new_w = w_w;
new_h = w_w * r_i;
if(new_h > w_h){
new_h = w_h;
new_w = w_h / r_i;
}
}
else{
new_h = w_w * r_i;
new_w = w_w;
}
$img.animate({
width : new_w + ‘px’,
height : new_h + ‘px’,
top : ‘0px’,
left : ((w_w/2) – (w_w/5.5)) + ‘px’
},700);
}
//get dimentions of the image,
//in order to make it full size and centered
function getImageDim($img){
var w_w = $(window).width(),
w_h = $(window).height(),
r_w = w_h / w_w,
i_w = $img.width(),
i_h = $img.height(),
r_i = i_h / i_w,
new_w,new_h,
new_left,new_top;
if(r_w > r_i){ /* Hoogte x Breedte window > Hoogte x Breedte image */
new_h = w_h;
new_w = w_h / r_i;
}
else{
new_h = w_w * r_i;
new_w = w_w;
}
return {
width : new_w + ‘px’,
height : new_h + ‘px’,
left : (w_w – new_w) / 10 + ‘px’, /* Standard /2 */
top : (w_h – new_h) / 10 + ‘px’ /* Standard /2 */
};
}
Robin, the path is ok. I tried your second code but the image is still fixed on the width.
I will continue to work on it.
Thanks!
it doesn’t work on widescreen monitors, on my 27′ imac it explodes
Beatiful gallery, but till it won’t somehow suppot the vertical images, it’s useless (at least for me)…
How can I make the images to move from left to right instead of up and down?
Thanks,
Wolffang
Wow! Another wonderful tutorial.
You´re great. Thanks for sharing!
Guys, can you help me with vertical images zoom for this script? I need to reduce image height to screen size.
Great tutorial,
wanted to ask if there’s a way to make the images slide automatically ?
thanks in advance
wanted to ask if there’s a way to make the images slide automatically ?
I (as others) am also new here.
you, are, aweseom! added you directly to my igoolge rss
another great tut and i have to say the you have a great taste, the picture you choose are amazing. and i think it will be very cool if we can make the text fade away once we click the magnifier on the thumbnail… can it be done ?
wonderful wonderful !
however, I’m working on a modification of this template.
and can’t seem to get any variation of a lightbox effect to work, i’m trying to click on an image/icon i added to the tf_content area, to show a hidden div via modal/lightbox, but to no avail.
any thoughts.
Mary Lou, U R God! What amazing stuff. Thanks so much for sharing.
Love the website. Is there a way to get it working in ie8? Thanks.
Thank you ! Works great, though I had to do some adjustments to move the thumbnails a bit lower and replace the arrows. Other than that it is great.
Amazing and creative.
You’re my inspiration Mary Lou
thank you mary for this tutorial 🙂
i wanted to ask how can i make this slide autoplay ?
Thank you for this tutorial.
for those who ask about play automaticly here is the solution -> just add this code before the scroll() function
‘$(document).ready(function() {
setInterval(function() { scroll(‘tb’)}, 2000);’
});
great tutorial 🙂
but i can’t get it work on IE9 🙁
any suggestions?
thanks.. i am really the jquery.
Keep share
Hi, great tutorial.
Would it be possible to flip the thumbnail and not a white area?
Greetings
Is there a way to make it so that the default of the large image is the zoomed out option and the user has the option to make it full size?