Photo Gallery with AngularJS and CSS3

Photo Gallery with AngularJS and CSS3

28 39515
Photo Gallery with AngularJS and CSS3
Photo Gallery with AngularJS and CSS3

Photo Gallery with AngularJS and CSS3

Today I will show you the process of creating photo slider with AngularJS and CSS3. The slider itself is not very complicated, but it will have a unique 3D effect when we turn the slides. During of the creation our gallery – we will use AngularJS v1.2. This framework will help us create the HTML markup and the turning slides mechanism. We will have two buttons to switch slides back and forth, as well as a small panel with thumbnails to switch immediately to a desired slide.

Live Demo

Step 1. HTML

First at all we have to prepare a proper header (with including all necessary resources):


<!DOCTYPE html>
<html ng-app="example366">
    <meta charset="utf-8" />
    <meta name="author" content="Script Tutorials" />
    <title>Photo Gallery with AngularJS and CSS3 | Script Tutorials</title>
    <meta name="description" content="Photo Gallery with AngularJS and CSS3 - demo page">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />

    <!-- add styles -->
    <link href="css/style.css" rel="stylesheet" type="text/css" />

    <!-- add javascripts -->
    <script src="js/jquery-2.0.3.min.js"></script>
    <script src=""></script>
    <script src=""></script>
    <script src=""></script>
    <script src="js/app.js"></script>

This is rather ordinary header: different meta infos, styles and javascripts. Now – the slider itself:

<body ng-controller="MainCtrl">
        <a href="" class="logo"><img src="images/logo.png" /></a>

    <!-- slider container -->
    <div class="container slider">

        <!-- enumerate all photos -->
        <img ng-repeat="photo in photos" class="slide" ng-swipe-right="showPrev()" ng-swipe-left="showNext()" ng-show="isActive($index)" ng-src="{{photo.src}}" />

        <!-- prev / next controls -->
        <a class="arrow prev" href="#" ng-click="showPrev()"></a>
        <a class="arrow next" href="#" ng-click="showNext()"></a>

        <!-- extra navigation controls -->
        <ul class="nav">
            <li ng-repeat="photo in photos" ng-class="{'active':isActive($index)}">
                <img src="{{photo.src}}" alt="{{photo.desc}}" title="{{photo.desc}}" ng-click="showPhoto($index);" />


In the beginning, we indicated the main controller (for the <body>): MainCtrl. Then, to enumerate all the given photos, we used the following technique: ng-repeat="photo in photos". This allowed us to create multiple images and thumbnails for our navigation bar. To bind the onclick event, we used ‘ng-click’ event attribute. AngularJS also allows us to bind swipe actions (for mobile devices): ‘ng-swipe-left’ and ‘ng-swipe-right’.

Step 2. CSS

All styles are divided into three sections: styles for the slider and its slides, styles for the navigation arrows and styles for the thumbnail navigation bar:


.arrow {
    cursor: pointer;
    display: block;
    height: 64px;
    margin-top: -35px;
    outline: medium none;
    position: absolute;
    top: 50%;
    width: 64px;
    z-index: 5;
.arrow.prev {
    background-image: url("../images/prev.png");
    left: 20px;
    opacity: 0.2;
    transition: all 0.2s linear 0s;
} {
    background-image: url("../images/next.png");
    opacity: 0.2;
    right: 20px;
    transition: all 0.2s linear 0s;

.nav {
    bottom: -4px;
    display: block;
    height: 48px;
    left: 0;
    margin: 0 auto;
    padding: 1em 0 0.8em;
    position: absolute;
    right: 0;
    text-align: center;
    width: 100%;
    z-index: 5;
.nav li {
    border: 5px solid #AAAAAA;
    border-radius: 5px;
    cursor: pointer;
    display: inline-block;
    height: 30px;
    margin: 0 8px;
    position: relative;
    width: 50px;
.nav {
    border: 5px solid #FFFFFF;
.nav li img {
    width: 100%;

.slider {
    border: 15px solid #FFFFFF;
    border-radius: 5px;
    height: 500px;
    margin: 20px auto;
    position: relative;
    width: 800px;

    -webkit-perspective: 1000px;
    -moz-perspective: 1000px;
    -ms-perspective: 1000px;
    -o-perspective: 1000px;
    perspective: 1000px;

    -webkit-transform-style: preserve-3d;
    -moz-transform-style: preserve-3d;
    -ms-transform-style: preserve-3d;
    -o-transform-style: preserve-3d;
    transform-style: preserve-3d;
.slide {
    position: absolute;
    top: 0;
    left: 0;
} {

    -webkit-transition:1s linear all;
    -moz-transition:1s linear all;
    -o-transition:1s linear all;
    transition:1s linear all;

    -webkit-transform: rotateX(50deg) rotateY(30deg);
    -moz-transform: rotateX(50deg) rotateY(30deg);
    -ms-transform: rotateX(50deg) rotateY(30deg);
    -o-transform: rotateX(50deg) rotateY(30deg);
    transform: rotateX(50deg) rotateY(30deg);

    -webkit-transform-origin: right top 0;
    -moz-transform-origin: right top 0;
    -ms-transform-origin: right top 0;
    -o-transform-origin: right top 0;
    transform-origin: right top 0;
} {
} {
    -webkit-transition:1s linear all;
    -moz-transition:1s linear all;
    -o-transition:1s linear all;
    transition:1s linear all;

.slide, {

In order to achieve this beautiful 3D transition effects between slides – we used CSS3 transition effects with rotateX, rotateY and preserve-3d for the parent element

Step 3. JavaScript

This is the main AngularJS application controller:


'use strict';

angular.module('example366', ['ngAnimate', 'ngTouch'])
  .controller('MainCtrl', function ($scope) {

    // Set of Photos
    $ = [
        {src: '', desc: 'Image 01'},
        {src: '', desc: 'Image 02'},
        {src: '', desc: 'Image 03'},
        {src: '', desc: 'Image 04'},
        {src: '', desc: 'Image 05'},
        {src: '', desc: 'Image 06'}

    // initial image index
    $scope._Index = 0;

    // if a current image is the same as requested image
    $scope.isActive = function (index) {
        return $scope._Index === index;

    // show prev image
    $scope.showPrev = function () {
        $scope._Index = ($scope._Index > 0) ? --$scope._Index : $ - 1;

    // show next image
    $scope.showNext = function () {
        $scope._Index = ($scope._Index < $ - 1) ? ++$scope._Index : 0;

    // show a certain image
    $scope.showPhoto = function (index) {
        $scope._Index = index;

In the beginning we prepared a collection of photos. After we will bind it into the HTML code. After this collection – several functions to manage with an active image.

Step 4. Images

All used images were taken from the Marc Driesenga’s Photostream at Flickr

Live Demo


That’s all for today, thanks for your patient attention, and if you really like what we have done today – share it with all your friends in your social networks using the form below.



  1. I love it how it looks, but I dunno what to do in order to let this gallery works. It seems that I’m doing something wrong but who knows what.

  2. Looks great!

    What kinds of limits does this have? How many photos could reasonably be displayed using this technique?

  3. It’s f**ing AWESOME…….
    superb work dude…..
    looking to develop dynamic gallery like this…….

    Thanks for sharing…

    • Hi Nits,

      did you already develop this as dynamic gallery?
      I also plan to work on this, but maybe you’ve already done it? ;-)

  4. A better example would be to have the gallery as a directive. I made a quick one:,html,js,css/

  5. This is pretty cool, but it looks like it only works with AngularJS 1.2.0rc1. Apparently there were breaking changes introduced in AngularJS 1.2.0-rc.2. I fumbled around with it a bit, but I don’t have the time to fully investigate right now. Do you have any idea how to get this working with newer AngularJS? (preferably 1.2.10)

    • Did you find the problem? I’m running into the same issue, the animations don’t seem to work in the Angular version I’m using.

    • Nevermind, I found the issue. The transformation CSS has to be applied to the ng-hide-add-active class, NOT to the ng-hide-add class, and the ng-hde-add class needs to have display: block !important; added to it.

  6. Great Gallery! I’d like to have multiple sliders on a single page. The loading works fine, but navigation between images doesn’t. Is it possible and what changes are necessary. Thanks.

  7. Hi

    I m not able to run the code in Android emulator using phonegap 2.9,throws the error as uncaught reference error: angular is not defined.

  8. Not sure what I am doing differently, but every time I hit the next/prev button to trigger showNext()/showPrev(), the ._Index counter is reset to 0.

  9. Hello, I love the gallery works great. I was going to give one suggestion to those who noticed this too (or maybe you can tell me if this will cause me problems down the road):
    I’ve noticed that when I click the arrows, Chrome (haven’t tested on other browsers, yet) will see it as if I moved to a different page. So, everytime I want to go back a page after using the gallery, I’ll have to hit the back button however many times I clicked the arrows before it will take me back. What I did to resolve this was remove the href=’#’ from the arrows. It seems to fix the problem without causing new ones. Tell me what you think.

  10. Will the module handle the large number of images? In the case, the image thumb nav control will be too long to place in a single line in the single image. How to handle the rotation of thumb images?

    • Hi Eric, in case of big amount of images, you can consider creating a pagination to separate all images to pages

Leave a Reply