Ai Santos

@asantos3026

Creating a Carousel Using Only Jade(Pug), Javascript, jQuery and CSS

STEP 1: Create divs inside of your page that will contain the carousel elements

.gallery
.gallery-main
.gallery-main-image
img(src=”/images/gallery3.jpg”)
.gallery-filmstrip
a(href=””)
img(src=”/images/gallery1.jpg”)
a(href=””)
img(src=”/images/gallery2.jpg”)
a(href=””)
img(src=”/images/gallery3.jpg”)
a(href=””)
img(src=”/images/gallery4.jpg”)
a(href=””)
img(src=”/images/gallery5.jpg”)

STEP 2: Set the styles for all of the elements inside of your carousel:

The Displayed Image Gallery:

  • The div around the display for the selected image
/*set styles for the wrapper around the image that will be displayed on click*/
.gallery { 
background-color: black;
}
.gallery > .gallery-main { 
position: relative;
height: 400px;
overflow: hidden;
}
  • The div that contains the div that contains the image itself
/*set styles for the inner container for the image that will be displayed on click*/
.gallery > .gallery-main > .gallery-main-image { 
position: absolute;
top: 0; bottom: 0;
right: 0; left: 0;
}
  • The image itself
/*set styles for the image itself*/
.gallery > .gallery-main > .gallery-main-image > img { 
display: block;
margin: 0 auto;
max-height: 100%;
max-width: 100%;
height: 400px;
}

The Filmstrip that contains thumbnails of the images to be displayed:

  • The container for the filmstrip
/*set styles for the filmstrip container*/
.gallery > .gallery-filmstrip { 
position: relative;
height: 280px;
margin-top: 10px;
}
  • Everything inside of the filmstrip
/*set styles for everything inside the filmstrip container*/
.gallery > .gallery-filmstrip > * { 
position: absolute;
top: 0;
left: 0;
}
  • Position everything inside of the filmstrip in the center
/*position everything inside the filmstrip in the center*/
.gallery > .gallery-filmstrip > * {
position: absolute;
top: 0;
left: 0;
}
  • Animation for the images in the filmstrip
/*set animation class to the filmstrip on click*/
.gallery > .gallery-filmstrip-animated > * {
transition: transform 1s, opacity 1s;
}
  • Set a height and width for all images in the container
/*set a height and width for the gallery filmstrip images*/
.gallery > .gallery-filmstrip img {
height: 200px;
width: 200px;
}

STEP 3: Create functions using jQuery and Javascript that will allow you to iterate through your images using the styles and animations you just created.

  • Initialize the Gallery
const initializeGallery = function() {
positionGalleryFilmstrip(0, false)
$(‘.gallery-filmstrip > *’).on(‘click’, function(event) {
event.preventDefault();
const cell = $(this);
const index = cell.index()
console.log(‘CLICKED’, index)
positionGalleryFilmstrip(index-2)
})
}
initializeGallery()
  • Determine the indices that will be visible in the filmstrip and use an offset to to ensure that whatever index we are on gives us either a result of 0, 1, 2, 3, 4. How do we do this by using a for loop and modulo
const visibleIndicies = function(totalNumberOfCells, numberOfVisibleCells, offset){
let visible = []
for (let index = 0; index < numberOfVisibleCells; index++) {
visible[index] = (index+offset) % totalNumberOfCells
}
return visible
}
  • Determine the Z Index, Opacity, and Transform for each position depending on where it is on the filmstrip
const zIndexForPosition = function(position){
return (
(position === 0 || position === 4) ? 1 :
(position === 1 || position === 3) ? 2 :
3
)
}

const opacityForPosition = function(position){
return (
(position === 0 || position === 4) ? 0.4 :
(position === 1 || position === 3) ? 0.7 :
1
)
}

const transformForPosition = function(position){
return ({
0: ‘translateX(160px) translateY(31px) scale(.8)’,
1: ‘translateX(300px) translateY(31px) scale(1)’,
2: ‘translateX(500px) translateY(31px) scale(1.3)’,
3: ‘translateX(700px) translateY(31px) scale(1)’,
4: ‘translateX(860px) translateY(31px) scale(.8)’,
})[position]
}
  • Determine the index of the image (cell) based on its location in the filmstrip (array)
const visibleIndicies = function(totalNumberOfCells, numberOfVisibleCells, offset) {
let visible = []
for (let index = 0; index < numberOfVisibleCells; index++) {
visible[index] = (index+offset) % totalNumberOfCells
}
return visible
}
  • the most complex part of the function — positioning the image so that it applies the css styles to that specific index to be displayed within an array that contains 5 image elements
const positionGalleryFilmstrip = function(offset, animate=true){
const filmstrip = $(‘.gallery-filmstrip’)
const numberOfCells = 5;
const cells = filmstrip.children()
if (offset < 0) offset += cells.length
const visibleCells = visibleIndicies(cells.length, numberOfCells,
offset)
if (animate){
filmstrip.addClass(‘gallery-filmstrip-animated’)
}else{
filmstrip.removeClass(‘gallery-filmstrip-animated’)
}
cells.each(function(index){
const cell = $(this)
let position = visibleCells.indexOf(index)
if (isBefore(index, visibleCells, cells.length)){
cell.css({
display: ‘block’,
zIndex: ‘0’,
opacity: ‘0’,
transform: ‘translateX(100px) translateY(31px) scale(.6)’,
})
}else if (isAfter(index, visibleCells, cells.length)){
cell.css({
display: ‘block’,
zIndex: ‘0’,
opacity: ‘0’,
transform: ‘translateX(890px) translateY(31px) scale(.6)’,
})
}else if (position === -1){
cell.css({
display: ‘none’,
zIndex: ‘0’,
opacity: ‘1’,
transform: ‘’,
})
}else{
cell.css({
display: ‘block’,
zIndex: zIndexForPosition(position),
opacity: opacityForPosition(position),
transform: transformForPosition(position),
})
}
if (position === 2){
const src = cell.find(‘> img’).attr(‘src’)
const image = $(‘<img>’).attr(‘src’, src)
const gallery = filmstrip.closest(‘.gallery’)
const galleryMain = gallery.find(‘> .gallery-main’)
const currentImageWrapper = galleryMain.find(‘.gallery-main-
image:first’)
const nextImageWrapper = currentImageWrapper.clone()
const nextImage = nextImageWrapper.find(‘> img’)
if (nextImage.attr(‘src’) === src) return;
nextImage.attr(‘src’, src)
galleryMain.prepend(nextImageWrapper)
currentImageWrapper.fadeOut(function(){
currentImageWrapper.remove()
})
}
})
}

Whoa!! What is happening here? Let’s break it out and go over it step by step:

  • create a function that positions the gallery filmstrip and set that to animate=true
  • assign some variables that will contain the filmstrip element, the number of cells, and the children of the filmstrip
const positionGalleryFilmstrip = function(offset, animate=true){
const filmstrip = $(‘.gallery-filmstrip’)
const numberOfCells = 5;
const cells = filmstrip.children()
}
  • if the offset is less than zero then we want to add the total number of cells to that amount. For example if we are at offset -1 and we have an array of images with the length 39, our new offset value will be 38.
if (offset < 0) offset += cells.length
const visibleCells = visibleIndicies(cells.length, numberOfCells, offset)
  • if the above condition is true, which means the cell is visible then pass the new offset, length, and number of cells into the function visibleIndices. We will then store the value of this function into visibleCells
  • if animate is true then we will add the animated class to the filmstrip, otherwise do not add that class
if (animate){
filmstrip.addClass(‘gallery-filmstrip-animated’)
}else{
filmstrip.removeClass(‘gallery-filmstrip-animated’)
}
  • now apply the following css styles to each cell which will give it the opacity, zIndex, and transform functions we need for each cell depending on its position in the filmstrip
cells.each(function(index){
const cell = $(this)
let position = visibleCells.indexOf(index)
if (isBefore(index, visibleCells, cells.length)){
cell.css({
display: ‘block’,
zIndex: ‘0’,
opacity: ‘0’,
transform: ‘translateX(100px) translateY(31px) scale(.6)’,
})
} else if (isAfter(index, visibleCells, cells.length)){
cell.css({
display: ‘block’,
zIndex: ‘0’,
opacity: ‘0’,
transform: ‘translateX(890px) translateY(31px) scale(.6)’,
})
}else if (position === -1){
cell.css({
display: ‘none’,
zIndex: ‘0’,
opacity: ‘1’,
transform: ‘’,
})
}else{
cell.css({
display: ‘block’,
zIndex: zIndexForPosition(position),
opacity: opacityForPosition(position),
transform: transformForPosition(position),
})
}
  • Now we need to assign the attribute to the images that will allow us to fade it out and in
if (position === 2){
const src = cell.find(‘> img’).attr(‘src’)
const image = $(‘<img>’).attr(‘src’, src)
const gallery = filmstrip.closest(‘.gallery’)
const galleryMain = gallery.find(‘> .gallery-main’)
const currentImageWrapper = galleryMain.find(‘.gallery-main-image:first’)
const nextImageWrapper = currentImageWrapper.clone()
const nextImage = nextImageWrapper.find(‘> img’)
if (nextImage.attr(‘src’) === src) return;
nextImage.attr(‘src’, src)
galleryMain.prepend(nextImageWrapper)
currentImageWrapper.fadeOut(function(){
currentImageWrapper.remove()
})
}
})
}
  • last but not least we need to determine if a cell is before or after the cell
const isBefore = function(index, visibleCells, cellsLength){
let beforeFirstIndex = visibleCells[0]-1
if (beforeFirstIndex < 0) beforeFirstIndex += cellsLength
return index === beforeFirstIndex
}
const isAfter = function(index, visibleCells, cellsLength){
let afterLastIndex = visibleCells[visibleCells.length-1]+1
if (afterLastIndex > cellsLength) afterLastIndex -= cellsLength
return index === afterLastIndex
}

More by Ai Santos

Topics of interest

More Related Stories