Awesome Mobile Image Gallery Web App

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 […]

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.

Message from TestkingWe offer guaranteed ccna security training program to help you pass ccna voice exam on time. Complete your ccie certification using certified resources.

Manoela Ilic

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

Stay in the loop: Get your dose of frontend twice a week

Fresh news, inspo, code demos, and UI animations—zero fluff, all quality. Make your Mondays and Thursdays creative!

Feedback 118

Comments are closed.
  1. Nice ! I was looking exactely for that !

    Maybe a suggestion/improvement: in the php, to automatically reseize the pictures in mobile size.

  2. Great tutorial. Is it possible for the static demo to have the ability show albums as well ( so PHP is not needed)? Being a novice javascript coder, it seems the thumbs_container div would need a different id for each group of thmbs for it to work. I’m guessing that function could be written in javascript in some way? Unfortunately, beyond my limited skill.

  3. Hi, is php needed for the gallery? Can i just place all the images in separate divs with the same functionalities? I’m trying to use it without php for offline possibilities with phonegap.

  4. Great tutorial but the site doesn’t work in Opera mini and Works with bugs in Safari (iPhone OS 4) – landscape images do not enlarge when viewing horizontaly (they shrink).

    Is there anything I can do to make the swapping of images smooth like when viewing images in appstore?

    Thanks.

  5. This is awesome, but i have a question i have incorporated this with a full site from witch photos are uploaded and php and mysql take care of building the folder structure and xml. And I know in the previous tutorial you mentioned that the images and thumbs folder have to be in the root folder where the index.php is well my thumbs and images folder are for ex: ../../webimages/thumbs/’.$album.’/desc.xml and I just cant get it to work i load the albums but can’t load the thumbs any suggestions or does the folder structure definitely have to be with he index.php?

  6. Hii amazing tutorial. But i have a doubt, i downloaded the .zip file and installed it in my server but it doesnt run the menu. Can u give me some help ?? thanks..

  7. I needed to create a .htaccess with the following line to make scandir work.

    SetEnv PHP_VER 5

    Thanks,
    Rob

  8. hello, I downloaded both the static zip and the actual one and i cant get them to run in the browser. Once i click the index file the album view doesnt show up and i just get some symbols ,;}}}}?>
    does anyone know a solution to this?

  9. Hello Alex, the normal one needs to run in something like XAMPP because it uses PHP. You can find it here: http://www.apachefriends.org/en/xampp.html
    In the static one I forgot to remove the pictures in the HTML that are not in the images folder. Just do the following. Remove all the li with the class “pic” in the “thumbView” container except the ones with images 1 to 5. I will update the ZIP file for the static demo soon. Hope it helps, cheers, ML

  10. thanks a lot im going to try using the static version now.
    however if i want to use the main file with phonegap lets say how would that work. Does XAMPP work on idevices?

  11. Hi Alex, this is a web app which means that it runs on a server and you access it with a device using its browser. Basically, it is a website that is made to look and work well on mobile browsers. Cheers, ML

  12. hey thanks a lot mary lou
    so this code cant be used to use it as an image gallery that uses photos from local storage?

  13. Hi Alex, no, it cannot be used as an on-device app 🙂 As I said, it simply a website that works very nicely when viewed on a mobile phone. Cheers, ML

  14. How would you get html code to work within the description area? like href for instance

  15. I’ve uploaded the script, change the desc.xml file to correspond to the 6 photos that are included in the demo. When i run the program… it’s stuck ioading the thumbnails… they never load.

  16. it seems that the multiple appends creates some trouble. my having a single append in loadThumbs seems to solve the issue

    $ul.append(‘‘ );

  17. Nice work!

    A plugin version for JQueryMobile instead of JQTouch would be great!

    I can help you to code this!

    Interested?

  18. Very Nice.. Thanks!

    Just one question. When adding to home screen the ability to save image disappears. Any ideas how I can get it back?

  19. Hi,
    first, thanx for this great gallery. I’ve only one problem. How can I controll the order of the images in each directory?

    I arranged the names in my first directory 101.jpg, 102.jpg, 103.jpg, … in the second directory 201.jpg, 202.jpg, 203.jpg, … and in the third directory 301.jpg, 302.jpg, 303.jpg, …

    But the script shows the images every time in another order. sometimes is the order ok, sometimes not. I get this problem in iPhone/iPad (Safari) and FF, IE, Flock. Can someone help me. Thanks a lot.

  20. $ul.append(‘‘ );

    seems not to work properly on iphone/ipad. The order is OK in galleries, but I can not get the links on “start page/home page” to work. if you change this line in script, the links ALBUM1, ALBUM2 will disappear 🙁

  21. On the resize function in the gallery.js, the variable widthMargin miss a semicolon after the 10.

    Just a heads up:)

  22. Amazing tutorial: clear, well designed, and most of all, USEFUL!

    You’ve won a new reader 🙂 Will keep an eye on your site.

    Regards from Spain

  23. the demo does not work on my older iPod touch running version 3.1.3 of the operating system which is the latest available for this device.

  24. Hi and thanks for this! really fantastic stuff!

    I got only one problem which I hope might find help here

    I’d like to get rid of ajax_loader.gif and replace it by fading transition but my javascript skills are very poor

    Trying to figure out how to set fadeOut() on current image when unloading so it smoothly fades into next/previous image

    any ideas?

    cheers

  25. please help:)

    – how do I rename ALBUM1, ALBUM2, ALBUM3, for example, to MY FAMILY, TRAVEL, MY HOUSE?

    – how to make a fourth album?

    thanks!

  26. landscape version of image does not resize properly on iPhone. iPad works fine. Anyone else experiencing this? Any ideas?

  27. Ok, so I just downloaded this image gallery and it is great! but I’m thinking about creating “download” button, like replacing the “about” button to download button, or making an new one. So I was thinking code like this:

    mydatabase/(example album 2)/(image1.jpg)

    . So how I can replace those example texts to some tag that specifies what image in which category user is currently browsing?

  28. Ok, I’m sorry but can’t get the code to show for ya… (moderator can delete my message above and if you can, show the code of my first comment the download one..)

  29. So anyone, how can I enable photo saving/downloading for the user that doesn’t use safari?

  30. Hello Mary Lou, great tutorial and great gallery.
    It’s there any possibility to charge directly the thumbs without charging the page of the albums? I only have one album and I like to begin in a page of thumbs.
    Maybe if I change something on the jquery.gallery.js is possible that this happens but i’m trying and i can’t.
    Thank you.

    • Hi Luis, thanks!
      quick solution:
      in the html add the class “current” to the thumbs_container, and remove it from the albums_container (you can also remove this div). Also remove the back anchor from the thumbs_container. In the javascript file, initialize the album variable with the name of your album (e.g. album1). Then just replace the line loadAlbums() with loadThumbs() .
      Hope it helps!
      Cheers,
      ML

  31. Thank you, i try it now, and hope it works (the joke of all of this is that i tried everything that you say but i think that i lose some steps in the way), anyway, thanks in advance because i don’t have great knowledges in js/php.
    And forget about my english, it’s so bad…

  32. Thank you Mary Lou it works fine now! Now the only problem i have is with php and my hosting service but i hope i can fixed it…

  33. Nice work! Thanks!
    How can i make the landscape version of image to be resizable? landscape version does not resize properly on iPhone.

  34. Thank you Mary Lou for the tutorial! I’m in a similar boat as NewGuyinTown and would like to make the images in my gallery downloadable to the phones gallery. Is this possible. Sorry I’m a bit of a noob and I’m learning trial by fire at the moment.

  35. hi,
    great webapp! only one question.. using the php version (i need multiple albums) how does it behave regarding cache? i’m afraid i will exceed the ipad safari cache limit..
    and is there a way to use it offline?

    many thanks
    cheers
    Pino