From our sponsor: Meco is a distraction-free space for reading and discovering newsletters, separate from the inbox.
With more and more users browsing the web with a mobile device, it’s time to begin with mobile web development. In this tutorial we are going to develop a simple mobile image gallery using the amazing jQTouch jQuery plugin for mobile web development. jQTouch is a jQuery plugin with native animations, automatic navigation, and themes for mobile WebKit browsers like iPhone, iPod Touch, G1, and Pre.
Our little application is going to show some albums in a list view which will reveal a wall of thumbnails once it’s clicked. When a thumbnail is clicked, we get to the full image view where we can navigate through all the photos by either clicking on the navigation buttons or swiping over the image.
This app is best viewed on a mobile device like the iPhone or the iPod Touch, or in a Webkit Browser like Google Chrome or Safari. If you are using the iPhone or the iPod Touch (or the iPad), add this app to your home screen to enjoy the full view and features.
Just like in our previous tutorial, the Fresh Sliding Thumbnails Gallery with jQuery and PHP we will be using PHP to automatically generate albums with PHP from the folder structure.
The great thing about jQTouch is that you don’t really have to worry about much, be it the style or the JavaScript. It has pretty much all the amazing effects that we know from the iPhone as default functionality and it takes care of the right head properties. This makes it really easy to create a mobile device friendly website.
We also have a static version without albums. You can find the demo and the ZIP file at the end of this post.
So, let’s start!
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 and JavaScript
The HTML is pretty simple: for each screen we will have a container that becomes visible when we are on that page.
The first screen that we will have in the HTML is the “About” section that get’s visible when clicking (or tapping) on the about button on the top right:
<div id="about" class="selectable"> <p><img src="codropsIcon.png"/></p> <p> <strong>Wonderwall Image Gallery</strong> <a href="http://www.codrops.com">By Codrops</a> </p> <p>A web app created with <br /> <strong>jQTouch</strong></p> <p><br /><br /><a href="#" class="grayButton goback">Close</a></p> </div>
The second container that we will have in our HTML structure, will be the part where we dynamically add a list of album links. We get that list automatically from our special folder structure.
The folder structure contains an image folder and a thumbs folder. Each one of those contains folders of albums. They have to be named the same, just like the images inside.
In the thumbnails album folders we will have an XML file called “desc.xml” which can be used to write a description for each image. In this file, we will write the name of the picture and it’s title. The description of each image is not obligatory which means that we can leave out images that don’t have any title or description.
The structure of that XML file will look as follows:
<descriptions> <image> <name>1.jpg</name> <text>Inna 02 © studio.es by Vincent Boiteau</text> </image> <image> <name>2.jpg</name> <text>Inna 01 © studio.es by Vincent Boiteau</text> </image> ... </decriptions>
With the thumbs.php file which we keep in a sub folder called “ajax” we will automatically get those descriptions. For a more detailed explanation of the workings, check out our previous tutorial.
The second container’s HTML structure is going to look like this:
<!-- The list of albums --> <div id="albums_container" class="current"> <div class="toolbar"> <h1>Albums</h1> <a class="button slideup" id="infoButton" href="#about">About</a> </div> <div class="loader" style="display:none;"></div> <ul id="albums" class="edgetoedge" style="display:none;"> </ul> </div>
The unordered list with the id “albums” will be populated with list items containing the links to the albums.
The toolbar will be at the top of the screen and present in every container. It will have a button to get to the about section and a back link that brings us back to the previous screen.
The first step in the JavaScript is to call the function loadAlbums() which gets the names of the albums with an AJAX request to the PHP side (albums.php):
/* name of the selected album */ var album = ''; /* index of li where there is the selected image */ var current = -1; /* 1 step : Load the Albums */ loadAlbums(); function loadAlbums(){ var $loader = $('#albums_container').find('.loader'); $loader.show(); var url = 'ajax/albums.php'; /* gets the names of the albums with an AJAX request to the PHP side */ $.get(url, function(data) { $loader.hide(); $('#albums').html(data).show(); },'html'); } /* clicking on an album: we keep track of which album is currently selected by getting the id (album name) of the clicked row */ $('#albums_container').delegate('li','click tap',function(e){ var $this = $(this); album = $this.attr('id'); });
The PHP file albums.php looks as follows:
<?php if(file_exists('../images')){ $files = array_slice(scandir('../images'), 2); if(count($files)){ natcasesort($files); foreach($files as $file){ if($file != '.' && $file != '..'){ echo '<li id="'.$file.'" class="arrow"><a href="#thumbs_container">'.$file.'</a></li>'; } } } } ?>
We are scanning the directory called “images” in order to get all the sub folders which are our albums. Note that the each list element link will have a href for the thumbs container. The JavaScript variable “album” will keep track of the current album when we click on one of the list items.
The third container is the section for the thumbnails. Here we will populate an unordered list #thumbs with the small thumbnail images as link elements.
As you can see in the image, the thumbnails will occupy all the screen. We use a centering function that determines how many thumbnails fit into one row given a certain window width. The left margin is calculated according to the left over space.
We also resize the thumbnails if they are bigger than our predefined width and height of 75px. So, if you use thumbnails that are not quadratic and of different sizes, they will be made to fit into the list element.
The thumbnails view has the following structure:
<!-- The list of images (thumbs) --> <div id="thumbs_container"> <div class="toolbar"> <h1>Thumbs</h1> <a class="back" href="#albums_container">Albums</a> <a class="button slideup" id="infoButton" href="#about">About</a> </div> <div class="loader" style="display:none;"></div> <ul id="thumbs" class="thumbView" style="display:none;"> </ul> </div>
In the JavaScript we need to load the thumbnails by making another AJAX request to the PHP side (thumbs.php) which lists us all the images inside of the current album. We also need to keep track of the currently clicked image which we save in the JavaScript variable “current”:
/* load thumbs when the panel thumbs_container slides in; hides the thumbs_container when it slides out */ $('#thumbs_container').bind('pageAnimationEnd', function(e, info){ if (info.direction == 'in'){ loadThumbs(); }else{ $('#thumbs').hide(); } }); /* gets the photos information with an AJAX request to the PHP side then creates and loads each one of the images, and appends it to the DOM after that, we need to center the grid of the images based on how many fit per row */ function loadThumbs(){ var $thumbscontainer = $('#thumbs_container'); var $loader = $thumbscontainer.find('.loader'); $loader.show(); var url = 'ajax/thumbs.php?album='+album; $.get(url, function(data) { var countImages = data.length; var $ul = $('#thumbs').empty(); var counter = 0; for(var i = 0; i < countImages; ++i){ try{ var description = data[i].desc[0]; }catch(e){ description = ''; } if(description == undefined) description = ''; $('<img alt="'+data[i].alt+'" title="'+description+'"/>').load(function(){ ++counter; var $this = $(this); /* we need to make sure the grid thumbs are no bigger than 75 px */ resizeGridImage($this); var $li = $('<li/>',{ className : 'pic' }); var $a = $('<a/>',{ href : '#photo_container' }); $ul.append($li.append($a.append($this))); if(counter == countImages){ $loader.hide(); $thumbscontainer.append($ul.show()); autoCenterPhotos(); } }).attr('src',data[i].src); } },'json'); } /* when clicking on an image we keep track of the index of the image, which is in the alt attribute of the thumb */ $('#thumbs_container').delegate('li','click tap',function(){ current = $(this).index(); });
The thumbs.php looks as follows:
<?php $album = $_GET['album']; $imagesArr = array(); $i = 0; /* read the descriptions xml file */ if(file_exists('../thumbs/'.$album.'/desc.xml')){ $xml = simplexml_load_file('../thumbs/'.$album.'/desc.xml'); } if(file_exists('../thumbs/'.$album)){ $files = array_slice(scandir('../thumbs/'.$album), 2); if(count($files)){ foreach($files as $file){ if($file != '.' && $file != '..' && $file!='desc.xml'){ if($xml){ $desc = $xml->xpath('image[name="'.$file.'"]/text'); $description = $desc[0]; if($description=='') $description = ''; } $imagesArr[] = array('src' => 'thumbs/'.$album.'/'.$file, 'alt' => 'images/'.$album.'/'.$file, 'desc' => $description); } } } } $json = $imagesArr; $encoded = json_encode($json); echo $encoded; unset($encoded); ?>
Our last container will be for the full image preview. Here we will use another resize function in order to adapt the width and height of the image to fit into the viewport.
We will also add two navigation buttons that will point to the next and previous images in full preview.
To browse through the images we can either use these navigation buttons or swipe over the image (if our mobile device supports that, i.e. iPhone or iPod Touch).
Between the navigation buttons, we will add the description of the current image.
The resize function that we will be using checks if the image is bigger than the window and if it is, the image gets resized accordingly.
The HTML structure for the last container looks as follows:
<!-- The single image container --> <div id="photo_container"> <div class="toolbar"> <h1>Photo</h1> <a class="back" href="#thumbs_container">Photos</a> <a class="button slideup" id="infoButton" href="#about">About</a> </div> <div class="loader" style="display:none;"></div> <div id="theimage" class="singleimage"></div> <div class="descriptionWrapper"> <p id="description"></p> <div id="prev" style="display:none;"></div> <div id="next" style="display:none;"></div> </div> </div>
And the JavaScript looks as follows:
/* load the large image when the panel photo_container slides in; empty the contents of the image element when it slides out */ $('#photo_container').bind('pageAnimationEnd', function(e, info){ if (info.direction == 'in'){ var $thumb = $('#thumbs_container li:nth-child('+parseInt(current+1)+')').find('img'); if(!$thumb.length) return; loadPhoto($thumb); } else{ $('#theimage').empty(); $('#description').empty(); $('#prev,#next').hide(); } }); /* loads a large photo */ function loadPhoto($thumb){ var $loader = $('#photo_container').find('.loader'); $loader.show(); var $theimage = $('#theimage'); $('<img/>').load(function(){ var $this = $(this); resize($this); $loader.hide(); var $a=$('<a/>');/*for swipe*/ $theimage.empty().append($a.append($this)); $('#description').empty().html($thumb.attr('title')); $('#prev,#next').show(); }).attr('src',$thumb.attr('alt')); } /* swipe image - navigate right/left */ $('#theimage').swipe(function(evt, data) { if(data.direction=='left') navigateNext(); else navigatePrevious(); }); /* Events for navigating through the images The current gives us our current photo, so we need to get the next / previous one from the thumbs container - these have the source for the large photo in the alt attribute */ $('#next').bind('click tap',function(){ navigateNext(); }); $('#prev').bind('click tap',function(){ navigatePrevious(); }); /* goes to next image */ function navigateNext(){ ++current; var $thumb = $('#thumbs_container li:nth-child('+parseInt(current+1)+')').find('img'); if(!$thumb.length) { --current; return; } loadPhoto($thumb); } /* goes to previous image */ function navigatePrevious(){ --current; var $thumb = $('#thumbs_container li:nth-child('+parseInt(current+1)+')').find('img'); if(!$thumb.length) { ++current; return; } loadPhoto($thumb); }
Initializing jQTouch
After adding the scripts of jQuery and jQTouch we also have to initialize the jQTouch plugin:
var jQT = new $.jQTouch({ icon : 'codropsIcon.png', cacheGetRequests: true, addGlossToIcon : false, startupScreen : 'codropsSplash.png', statusBar : 'black', preloadImages: [ 'themes/img/back_button.png', 'themes/img/back_button_clicked.png', 'themes/img/button_clicked.png', 'themes/img/grayButton.png', 'themes/img/whiteButton.png', 'themes/img/loading.gif' ] });
Beside others, we define the icon for the app and the start up screen image. We can also list what images shall be preloaded. There are several parameters that you can configure. You can find all about the initialization options here.
If we use a device where we can rotate the screen, our image preview will look like this:
And now, let’s take a look at the style.
The CSS
The style for this gallery is mainly based on the provided theme in the jQTouch plugin. We did some minor changes to the colors in the default style and added the following style for the gallery:
ul.thumbView{ list-style:none; margin:0px; border:none; } ul.thumbView li { float:left; position:relative; width:80px; height:80px; border:none; margin:0px; padding:0px; background:transparent; line-height:80px; overflow:visible; } ul.thumbView li a { height:80px; margin:0; padding:0; width:80px; text-align:center; vertical-align:middle; display:table-cell; overflow:visible; } ul.thumbView li a img{ border:none; vertical-align:middle; -webkit-box-shadow:2px 2px 8px #000; } div.singleimage{ text-align:center; width:100%; } div.singleimage img{ margin-top:10px; -webkit-box-shadow:2px 2px 8px #000; } .descriptionWrapper{ height:40px; position:relative; } p#description{ text-align:center; color:white; text-transform:uppercase; font-weight:bold; margin:10px 0px 0px 0px; padding:0px 45px; } div#prev,div#next{ cursor:pointer; position:absolute; top:10px; width:40px; height:40px; background-color:black; background-repeat:no-repeat; background-position:center center; } div#prev{ left:0px; background-image:url(img/prev.png); -webkit-border-top-right-radius:10px; -webkit-border-bottom-right-radius:10px; } div#next{ right:0px; background-image:url(img/next.png); -webkit-border-top-left-radius:10px; -webkit-border-bottom-left-radius:10px; } div.loader{ background:transparent url(img/ajax-loader.gif) no-repeat center center; position:absolute; top:90px; width:100%; left:0px; height:24px; }
And that’s it! I hope you enjoyed starting with mobile web development!
We also have a static version of this mobile photo gallery without the album functionality. Check out the static demo or download the ZIP file.
@ Sarah. Thanks. I will try it 😉 but after… it’s too expensive for us
It seems it’s most beautiful if we resize the image by 2 or 3 for example before cropping
PS: another newbie question 😉 how do these iphone screen-shot including “borders” ? like above
@ Alex. Thanks for your updated loadThumbs function but it seems don’t work for me 🙁 I only see the loading image at thumbs container
Is it possible to upload a correct version to Mary zip file available to download ?
PS: between //load the images into cache
and ++counter; is it a ” or twice ‘ into $(”).load(function(){ ?
Can you tell me how to change the names of the albums. ie: art, beauty, landscapes etc. Thanks!
Anybody found out how to make it possible to zoom in on the picture? it is needed very much.
I have found out how to do this, but the picture is 300xauto picture (edited with css from a 1152?×?1594 picture), and when i zoom in the resolution is reaallyyyy bad – it is a converted PDF.
Hi Mary Lou,
Great job! I see there is a handful of postings regarding the use of large number of images within a given album. Have you had the chance to look into this issue and implement a workaround?
Can this work within the context of jquery mobile? For example, I would like to include this functionality within the “content” div of my page, but it’s not working.
Hi,
Can anyone show me how to just make the first screen all thumbnails and then be able to click to an image? Not using the Albums screen.
Thanks great Tut!
Hi, thanks lot for the great gallery. I’m having issues where:
1. large image not match thumb, means when click thumb A, it show image B
2. iphone has problem on the album button, when click, it can’t load thumbnail page. (Ipad is working.)
Wish to get advice from you guys. Thanks!
Demo don’t works. It loads but not show anything. What’s the problem?
Hello! This is killer and I wish I could get it to work as well as it does here. I have read all the comments and a few have also asked my question… The album section loads fine but when going to the thumbnail page all I get is a constant loader animation and the thumbnails never load. I followed the tutorial over and over and everything seems right. Could this be on the server side? As far as I know php is working fine on the server….? Any help would be amazing!
Thanks
Show
I was wondering since this is essentially a website that works well on phones…is it possible to have a link that will direct someone on a normal pc directly to a particular album?
Nice development but I would recommand a non ajax approach so we could use this as a skin/template to an existing platform without additional and specific PHP script requirement (the thumb/photo loader in javascript).
First of all I want to say that I too love the smell of freshly grounded peppercorns. Secondly, I just discovered your Awesome Mobile Image Gallery Web App. As advertised, It is amazing. Thank you for making it.
I would really like to use it for a site I’m working on. What I would like to do is pull the images from my wordpress site. The images uploaded have been tagged so that I can create galleries based off of tags. How could I do that?
Thanks Mary, you saved the day for me with this app. I used this for a mobi site and many people have said how great it looks. I do need to ask for help though in that I need to urgently add a link/button so that people viewing the property images can return the home page of the mobi site. Can you, or someone else help me with this? I want to add it to the thumbs page only. Many thanks in advance 🙂
Hi,
love that script its so good on ipad and iphone….just wonder if there is a way put on a link on toolbar that point back to my home page ….
TIA.