I've created a JavaScript image slideshow, using only JavaScript (no jQuery). I want to become more familiar with JavaScript, which is why I didn't use jQuery.
My four requirements were:
- It must work if JavaScript is disabled.
- It must be responsive.
- It cannot use jQuery.
- It must work in IE 8.
The code works - I'm just looking to see if I could make it more efficient.
// Get array with photos
var photos = document.getElementsByTagName("figure"); // Returns object of photos
var numPhotos = photos.length;
var shownPhotoIndex;
// Hide all photos except first by giving class of "hide" (if JS is not enabled, all photos will show)
function hidePhotos() {
for (var i = 0; i < numPhotos; i++) {
if (photos[i] !== photos[0]) {
photos[i].className += " hide";
} // end if statement
} // end for statement
} // end hidePhotos
function positionButtons() {
var getImage = photos[0].children[0]; // IE 8 does not support photos[0].firstElementChild;
var imageHeight = (getImage.height);
var imageWidth = (getImage.width);
var paddingTop = (imageHeight / imageWidth) * 100;
paddingTop = +paddingTop.toFixed(2);
var percent = paddingTop + "%";
document.getElementById("previous").style.paddingBottom = percent;
document.getElementById("next").style.paddingBottom = percent;
}
// Add controls (if JS is not enabled; controls will not be present)
function addControls() {
var slideshow = document.getElementById("slideshow");
// Create buttons
var spanNext = document.createElement("span");
var spanPrevious = document.createElement("span");
// Give buttons IDs
spanNext.setAttribute("id", "next");
spanPrevious.setAttribute("id", "previous");
// Add buttons to slideshow div
slideshow.appendChild(spanNext);
slideshow.appendChild(spanPrevious);
// Add content to buttons
document.getElementById("next").innerHTML = "<p>>></p>";
document.getElementById("previous").innerHTML = "<p><<</p>";
// Calculate position of buttons
positionButtons();
} // end addControls
// Find curently shown photo
function findShownPhoto() {
for (var i = 0; i < numPhotos; i++) {
// if the image does not contain a class of "hide"
if (photos[i].className.indexOf("hide") == -1) {
shownPhotoIndex = i;
} // end if statement
} // end for statement
} // end findShownPhoto
function progressSlides() {
var next = document.getElementById("next");
// When the next button is clicked, show next photo
next.onclick = function() {
var nextPhoto;
findShownPhoto();
// If current photo is last photo, go to first photo
if (shownPhotoIndex === (numPhotos - 1)) {
nextPhoto = photos[0];
} else {
nextPhoto = photos[shownPhotoIndex + 1];
}
// Hide current photo
// Add the "hide" class to the list of existing classes
photos[shownPhotoIndex].className += " hide";
// Show next photo by removing "hide" class
// Create a new string with classes that removes "hide"
var newClass = nextPhoto.className.replace("hide", "");
nextPhoto.className = newClass;
}; // end next click
var previous = document.getElementById("previous");
previous.onclick = function() {
var prevPhoto;
findShownPhoto();
// If current photo is first photo, go to last photo
if (shownPhotoIndex === 0) {
prevPhoto = photos[numPhotos - 1];
} else {
prevPhoto = photos[shownPhotoIndex - 1];
}
// Hide current photo
photos[shownPhotoIndex].className += " hide";
// Show previous photo
var newClass = prevPhoto.className.replace("hide", "");
prevPhoto.className = newClass;
}; // end previous click
} // end progressSlides
// Run JS after images have downloaded
window.onload = function() {
addControls();
progressSlides();
};
hidePhotos();
/* INSTRUCTIONS
All photos should be wrapped in figure elements and should be the same size
Compress photos before uploading (save originals)
*/
body {
box-sizing:border-box
}
figure {
margin:0
}
#slideshow {
display:inline-block;
padding:0;
position:relative;
/* To position slideshow buttons */
max-width:920px
}
.photo {
margin:0;
position: relative;
/* To position captions */
}
.hide {
display:none
}
#slideshow img {
width:100%;
border-top-left-radius:10px;
border-top-right-radius:10px
}
#slideshow figcaption {
background-color:#000;
color:#fff;
padding:1em;
border-bottom-right-radius:10px;
border-bottom-left-radius:10px;
font-family:Helvetica,Arial,Tahoma,sans-serif;
font-size:15px;
line-height:150%;
margin-top:-5px
}
#previous,#next {
height:0;
/* Padding-bottom is added via JS; calculates based on height of image */
position:absolute;
top:0
}
#previous p,#next p {
margin:0;
display:table;
padding:1em 10px;
color:#fff;
font-family:Arial;
font-size:24px;
background-color:#000;
text-align:center;
font-weight:700;
opacity:.8;
position:absolute;
/* positioned in relation to the #previous and #next spans */
top:50%;
margin-top:-1.6em
/* previously used transformY(-50%) to bring arrow up half the width of itself; not supported in IE 8 */
}
#previous p {
left:0;
border-radius:0 5px 5px 0
}
#next p {
right:0;
/*moves button to right corner of span instead of left */
border-radius:5px 0 0 5px
}
#previous {
left:0
}
#next {
right:0
}
#previous:hover,#next:hover {
opacity:.5;
cursor:pointer;
cursor:hand
}
<div id="slideshow">
<figure class="image">
<img src="https://c1.staticflickr.com/9/8584/16136057529_e7b64928d0_z.jpg" />
<figcaption>This is an example of a really long caption. Here I go. Do I wrap to a second line? Wrap wrap wrap wrap. Wrap Wrap Wrap Wrap Wrap Wrap Wrap Wrap Wrap Wrap Wrap</figcaption>
</figure>
<figure class="image">
<img src="https://c4.staticflickr.com/8/7495/16322256485_08ee0ee36f_z.jpg" />
<figcaption>Insert caption</figcaption>
</figure>
<figure class="image">
<img src="https://c2.staticflickr.com/8/7474/16120961661_8dc12962dd_z.jpg" />
<figcaption>Insert caption</figcaption>
</figure>