Sonntag, 20. April 2014

[Web Development] An overall tutorial in web development at the example of a gallery

First I would like to mention that I never learned web development professionally. I have taught everything concerning web development myself by creating a website for my brother who is a model (Lukas Bachert). So if you have any best-practices or improvements please let me know. Have fun :)

What we are going to do:

We are going to create a fancy image gallery as seen on my website. We will achieve this step by step while I am trying to explain a lot so you can do similar projects after you finished this tutorial.

What you should know to follow this tutorial:

I am trying to make this tutorial as easy as possible but you should know the following things in order to follow and understand the tutorial:

  • The basics of HTML including the types of elements and their usages
  • The basics of CSS including simple selection (If you are lacking skills in selecting elements in CSS check out this link)
  • You should know what JQuery is


The structure:

black:   the div containing our gallery
blue:     the div our content will be
green:   the arrows to navigate through the images
red:      the div containing the thumbs
orange: the arrows to scroll through the thumbs

The HTML:

As a start we will implement the mentioned structure as HTML code.
<!-- This is our all aroung container -->
<div id="epicGallery">
 <!-- This will contain our thumbs -->
 <div id="epicThumbs">
 </div>
 <!-- The following two are for scrolling the thumbs -->
 <div class="epic-thumb-nav" id="epicThumbsLeft">
 </div>
 <div class="epic-thumb-nav" id="epicThumbsRight">
 </div>
 <!-- This will contain our content -->
 <div id="epicContent">
  <!-- This is the big image -->
  <img id="epicImage" src=""/>
  <!-- The following divs are for navigating through the images -->
  <div class="epic-nav" id="epicNext">
  </div>
  <div class="epic-nav" id="epicPrevious">
  </div>
 </div>
</div>
Because I take the source code of the plugin I published the ids are structured like that. I started naming ids in camel-case and classes seperated by "-". Do you guys have any best-practices for that?

Now we got some empty divs. Time to fill them:
 <div id="epicGallery">
 <!-- This will contain our thumbs -->
 <div id="epicThumbs">
 </div>
 <!-- The following two are for scrolling the thumbs -->
 <div class="epic-thumb-nav" id="epicThumbsLeft">
  <!-- Left Arrow to scroll the thumbs-->
  <img class="epic-thumb-nav-image" src="LeftBlackArrow.png" alt=""/>
 </div>
 <div class="epic-thumb-nav" id="epicThumbsRight">
  <!-- Right Arrow to scroll the thumbs-->
  <img class="epic-thumb-nav-image" src="RightBlackArrow.png" alt=""/>
 </div>
 <!-- This will contain our content -->
 <div id="epicContent">
  <!-- This is the big image -->
  <img id="epicImage" src="" onclick="epicPopup();" alt=""/>
  <!-- The following divs are for navigation -->
  <div class="epic-nav" id="epicNext">
   <!-- Right Arrow to show the next image -->
   <img class="epic-nav-image" src="RightBlackArrow.png" onclick="epicNext();" alt=""/>
  </div>
  <div class="epic-nav" id="epicPrevious">
   <!-- Left Arrow to show the previous image -->
   <img class="epic-nav-image" src="LeftBlackArrow.png" onclick="epicPrevious();" alt=""/>
  </div>
 </div>
</div>
I hope you could follow so far. Now we just need to add a little magic until we are finished. You need to place a span in front of each image to vertically align it. Thanks to Steve Clay solving the problem in this post. If you do that you finally get this code:
<!-- This is our all aroung container -->
<div id="epicGallery">
 <!-- This will contain our thumbs -->
 <div id="epicThumbs">
 </div>
 <!-- The following two are for scrolling the thumbs -->
 <div class="epic-thumb-nav" id="epicThumbsLeft">
  <!-- Left Arrow to scroll the thumbs-->
  <span class="epic-helper"><img class="epic-thumb-nav-image" src="LeftBlackArrow.png" alt=""/>
 </div>
 <div class="epic-thumb-nav" id="epicThumbsRight">
  <!-- Right Arrow to scroll the thumbs-->
  <span class="epic-helper"><img class="epic-thumb-nav-image" src="RightBlackArrow.png" alt=""/>
 </div>
 <!-- This will contain our content -->
 <div id="epicContent">
  <!-- This is the big image -->
  <span class="epic-helper"><img id="epicImage" src="" onclick="epicPopup();" alt=""/>
  <!-- The following divs are for navigation -->
  <div class="epic-nav" id="epicNext">
   <!-- Right Arrow to show the next image -->
   <span class="epic-helper"><img class="epic-nav-image" src="RightBlackArrow.png" onclick="epicNext();" alt=""/>
  </div>
  <div class="epic-nav" id="epicPrevious">
   <!-- Left Arrow to show the previous image -->
   <span class="epic-helper"><img class="epic-nav-image" src="LeftBlackArrow.png" onclick="epicPrevious();" alt=""/>
  </div>
 </div>
</div>
Because the four arrows we see now if we are executing out website are not really what we want we need to add some CSS to make it at least good looking.

The CSS: We start by some general CSS lines we need.
//Our main container
#epicGallery {
    position: absolute;
    width: 80%;
    height: 80%;
    top: 10%;
    left: 10%;
    overflow: hidden;
}

//This is the span that helps to align images vertically
.epic-helper {
    display: inline-block;
    height: 100%;
    vertical-align: middle;
}
The .epic-helper is the span i talked about earlier. It is needed to align the images.
Let's go on by styling the thumbs.
//The thumb container
#epicThumbs {
    position: absolute;
    left: 0px;
    min-width: 100%; //Needs to be at least 100%. If it's larger you can scroll it
    bottom: 0px;
    max-height: 80px;
    height: 80px;
    overflow: hidden;
    white-space: nowrap;
    //Animate the scrolling
    transition: left 0.2s linear;
    -moz-transition: left 0.2s linear;
    -o-transition: left 0.2s linear;
    -webkit-transition: left 0.2s linear;
}

.epic-thumb {
    display: inline-block; //Prevent the wrap of divs
    height: 100%;
    margin-left: 5px; //A little gap between the thumbs
    cursor: pointer;
}
To finish the thumbs we need to define the arrows which we will use to scroll the thumbs later. I guess I need to mention now that every animation in our gallery will be a CSS transition. I really love these animations. They look smooth and are compatible to common browsers.
.epic-thumb-nav {
    position: absolute;
    width: 50px;
    height: 80px;
    bottom: 0px;
    //Make it a transparent white background
    background-color: rgba(255,255,255,0.4);
    //opacity will be set if you hover the thumbs
    opacity: 0;
    //Animate the opacity so it looks a lot better
    transition: opacity 0.5s ease-in-out;
    -moz-transition: opacity 0.5s ease-in-out;
    -o-transition: opacity 0.5s ease-in-out;
    -webkit-transition: opacity 0.5s ease-in-out;
}

#epicThumbsRight {
    right: 0px;
}

//The animation I mentioned. Fading in/out the arrows of the thumbs
#epicThumbs:hover ~ .epic-thumb-nav {
    opacity: 1;
}

.epic-thumb-nav:hover {
    opacity: 1;
}

//Vertically align the image
.epic-thumb-nav-image {
    vertical-align: middle;
    width: 100%;
}
Now that we finished our thumbs we can start with the content. First of all we will do the general stuff and after that we will style the arrows in the content.
#epicContent {
    text-align: center;
    width: 100%;
    height: calc(100% - 90px);
    max-width: 100%;
    max-height: calc(100% - 90px);
}

#epicImage {
    max-width: 100%;
    max-height: 100%;
    vertical-align: middle;
    cursor: pointer;
}

/* ----------------------------------------------------------------------------- CONTENT-NAV */

//Fade in the content arrows if you hover the content
#epicContent:hover > .epic-nav {
    opacity: 1;
}

.epic-nav {
    position: absolute;
    top: 0px;
    height: calc(100% - 90px);
    width: 50px;
    //Initially the arrows aren't visible
    opacity: 0;
    //Animate the opacity so it looks smooth
    transition: opacity 0.5s ease-in-out;
    -moz-transition: opacity 0.5s ease-in-out;
    -o-transition: opacity 0.5s ease-in-out;
    -webkit-transition: opacity 0.5s ease-in-out;
}

//Position both arrows
#epicNext {
    right: 0px;
}

#epicPrevious {
    left: 0px;
}

//Vertically align the images
.epic-nav-image {
    vertical-align: middle;
    width: 100%;
    cursor: pointer;
}
Finally we will style something we didn't even implement in our HTML. If you are asking yourself why we should do such a thing you are right. That sounds really stupid. But the answer is easy. Later on we want a pretty popup which extends the current image. The popup will be loaded by a template we will create at the end of the tutorial.
//A black transparent background
#epicBackground {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0px;
    left: 0px;
    background-color: rgba(0,0,0,0.7);
}

//The content of the popup including the image and the navigation arrows
#epicFullscreenContainer {
    position: absolute;
    text-align: center;
    width: 90%;
    height: 90%;
    max-width: 90%;
    max-height: 90%;
    top: 5%;
    left: 5%;
}

#epicFullscreenImage {
    max-width: 100%;
    max-height: 100%;
    vertical-align: middle;
}

/* ----------------------------------------------------------------------------- POPUP-NAV */

.epic-popup-nav {
    position: absolute;
    top: 5%;
    height: 90%;
    width: 50px;
}

#epicPopupNext {
    left: 95%;
}

#epicPopupPrevious {
    left: calc(5% - 50px);
}
Well done, you finished the CSS part. I hope you understood everything. If you had any troubles or some things you don't understand please let me know :)
Just one step left to our final gallery. We will now start using JavaScript and JQuery.

The JavaScript/JQuery:

Good job so far. Let's start the JavaScript and JQuery part by initializing the variables and set up the eventhandlers.
//Out current image index
var epicIndex = -1;
//Is needed for better detection by scrolling the thumbs
var isHover = false;

$(document).ready(function() {
    setUpEventHandler();
});
Now to the core of our JavaScript file, the setUpEventHandler() method.
//sets up the needed handler
function setUpEventHandler() {
 //Executes when an thumb image is clicked
    $('.epic-thumb').click(function() {
  //Check if clicked element is current element
        if ($('#epicThumbs').children().index($(this)) !== epicIndex) {
   //Update the image and the current index
            var src = $(this).attr('src');
            $('#epicImage').attr('src', src);
            $('#epicFullscreenImage').attr('src', src);
            epicIndex = $('#epicThumbs').children().index($(this));
        }
    });
 //that unbind is needed so if you execute this method twice the following method
 //won't be executed twice
    $(document).unbind('keyup');
 //This method is used so you can navigate the gallery with the arrow keys on your keyboard
    $(document).keyup(function(e) {
        if (e.keyCode === 37) { //LEFT-ARROW
            epicPrevious();
        } else if (e.keyCode === 39) { //RIGHT-ARROW
            epicNext();
        } else if (e.keyCode === 27) { //ESCAPE
   //If the popup is shown it will be faded out
            $('#epicBackground').fadeOut(200, function() {
                $('#epicBackground').remove();
                $('#epicGallery').fadeIn('fast');
            });
        }
    });
 //This method is needed so the thumb arrows are hidden or shown at the correct times
 //E.g. if you scrolled the whole thumbs to the end you should not see the arrow to scroll further
    $('#epicThumbs').mouseenter(function() {
        if ($('#epicThumbs').width() > $('#epicGallery').width()) {
            var left = parseInt($('#epicThumbs').css('left'));
            if (left < 0) {
                $('#epicThumbsLeft').show();
            }
   //Again some mathematical calculations...
            var divWidth = $('#epicGallery').width();
            var thumbWidth = $('#epicThumbs').width();
            var maxLeft = -(thumbWidth - divWidth);
            var left = parseInt($('#epicThumbs').css('left'));
            if (left > maxLeft) {
                $('#epicThumbsRight').show();
            }
        } else {
            $('#epicThumbsLeft').hide();
            $('#epicThumbsRight').hide();
        }
    });
    $('#epicThumbsRight').mouseenter(function() {
        isHover = true;
        moveThumbsLeft();
    });
    $('#epicThumbsRight').mouseleave(function() {
        isHover = false;
    });
    $('#epicThumbsLeft').mouseenter(function() {
        isHover = true;
        moveThumbsRight();
    });
    $('#epicThumbsLeft').mouseleave(function() {
        isHover = false;
    });
    $('#epicThumbs').children().first().click();
}
That was a hell of a lot of code. I hope there are no difficulties in it and the comments i made are clear.
Now we need to be able to navigate through the images in our gallery. We will implement the methods epicNext() and epicPrevious().
//Updates the image to the next image in the gallery.
//If you reached the end the gallery starts all over again.
function epicNext() {
    epicIndex++;
    if (epicIndex > $('#epicThumbs').children().size() - 1) {
        epicIndex = 0;
    }
    var next = $('#epicThumbs').children().get(epicIndex);
    var nextSrc = $(next).attr('src');
    $('#epicImage').attr('src', nextSrc);
    $('#epicFullscreenImage').attr('src', nextSrc);
}

//Updates the image to the previous image in the gallery.
//If you reached the end the gallery starts all over again.
function epicPrevious() {
    epicIndex--;
    if (epicIndex < 0) {
        epicIndex = $('#epicThumbs').children().size() - 1;
    }
    var next = $('#epicThumbs').children().get(epicIndex);
    var nextSrc = $(next).attr('src');
    $('#epicImage').attr('src', nextSrc);
    $('#epicFullscreenImage').attr('src', nextSrc);
}
Only three methods left. Two for the scrolling of the thumbs and one for the popup.
//moves the thumbs left
function moveThumbsLeft() {
 //some mathematical calculations
    var divWidth = $('#epicGallery').width();
    var thumbWidth = $('#epicThumbs').width();
    var maxLeft = -(thumbWidth - divWidth);
    var left = parseInt($('#epicThumbs').css('left'));
    $('#epicThumbsLeft').show();
 //If the thumbs reached its final position where it shouldnt move further the 
 //arrow to scroll further is hidden
    if (left <= maxLeft) {
        $('#epicThumbs').css('left', maxLeft);
        $('#epicThumbsRight').hide();
    } else if (isHover) {
        $('#epicThumbs').css('left', "-=75");
        if ($('#epicThumbs').width() > $('#epicGallery').width()) {
            $('#epicThumbsRight').show();
        }
        setTimeout(moveThumbsLeft, 200);
    }
}

//moves the thumbs right
function moveThumbsRight() {
    var left = parseInt($('#epicThumbs').css('left'));
    $('#epicThumbsRight').show();
 //If the thumbs reached its final position where it shouldnt move further the 
 //arrow to scroll further is hidden
    if (left >= 0) {
        $('#epicThumbs').css('left', 0);
        $('#epicThumbsLeft').hide();
    } else if (isHover) {
        $('#epicThumbs').css('left', "+=75");
        if ($('#epicThumbs').width() > $('#epicGallery').width()) {
            $('#epicThumbsLeft').show();
        }
        setTimeout(moveThumbsRight, 200);
    }
}
The code for the popup
//This method is used to create the popup we want to happen if we click the image.
function epicPopup() {
 //fades out the gallery so that you dont see the gallery in the background of the popup
    $('#epicGallery').fadeOut('fast');
 //create a div
    jQuery('
', { id: 'epicBackground' }).appendTo('body'); $('#epicBackground').hide(); //Load the template into the div $('#epicBackground').load('epicPopup.html', function() { $('#epicFullscreenImage').attr('src', $('#epicImage').attr('src')); }); //Fade the popup in $('#epicBackground').fadeIn(200); //Close the popup if the background is clicked $('#epicBackground').click(function(e) { var noclose = (e.target === document.getElementById('epicFullscreenImage')) || (e.target === document.getElementById('epicPopupPreviousImage')) || (e.target === document.getElementById('epicPopupNextImage')); //Be sure that the background is clicked and not any children of the background if (noclose) { return false; } else { $('#epicBackground').fadeOut(200, function() { $('#epicBackground').remove(); $('#epicGallery').fadeIn('fast'); }); } }); }
We did it. We finally did it. Well... Not really. We are missing a short piece of HTML. You remember that template for the popup i talked about earlier? Here it is:

<div id="epicFullscreenContainer">
    <span class="epic-helper"></span><img id="epicFullscreenImage" src="" alt=""/>
</div>
<!-- The same navigation as every year
  and some helping spans aswell -->
<div class="epic-popup-nav" id="epicPopupNext">
    <span class="epic-helper"></span><img id="epicPopupNextImage" class="epic-nav-image" src="images/epicgallery/right_black.png" onclick="epicNext();" alt=""/>
</div>
<div class="epic-popup-nav" id="epicPopupPrevious">
    <span class="epic-helper"></span><img id="epicPopupPreviousImage" class="epic-nav-image" src="images/epicgallery/left_black.png" onclick="epicPrevious();" alt=""/>
</div>
Finally. That is all the magic needed to develop a gallery like I did. Now you can add images to your gallery by inserting lines like this one in your epicThumbs container

<img class="epic-thumb" src="some/path/11.jpg" alt="this could be your advertisement"/>

I hope you had fun and understood what I did. If you liked this post please recommend it to some other people. Have a nice day! :)

Keine Kommentare:

Kommentar veröffentlichen