Context: Anastas, LLC has a standing relationship with Einhorn Design, a graphics design studio based in Pittsburgh, PA. Although we focus on consulting work, we do offer web development. Einhorn Design came to us with a design that they wanted us to implement (using a custom WordPress and Bootstrap combination that will be the subject of another blog post) whose index page was to feature a rather simple slideshow.
Generally, reinventing the wheel is unnecessary if an open sourced solution whose licensing allows commercial use can be found, so our first reaction was to start Googling. However, about 15 minutes of searching yielded no usable solution for one simple reason: the buttons.
Motivation: Simply, the design that we were asked to implement required that the next/back buttons for the slideshow were to lie on the edge of the slideshow, i.e. with half lying on top of the current image and half lying outside the container. All of the solutions that we found were either too fully-featured to justify the entailed loading time or used overflow:hidden on the container div, preventing the next/back buttons from being visible outside the container element. For that reason, we decided to develop a simple slideshow in jQuery that allows this protrusion of buttons and that is lightweight enough to load very quickly.
(It should be made clear that since the client did not ask for a custom gallery but simply a gallery and we then created created this software at our expense, outside the budget of the commissioned work, and implemented it for this design, leaving it our intellectual property – which gives us the right to open-source it ourselves.)
HTML/CSS: We wanted to keep its usage as simple as possible for the future, so the HTML is simple.
- div.gallery contains a slideshow and is given position: relative for positioning its descendants. This is a container element that is not itself visible.
- img.left and img.right, the “back” and “next” buttons, respectively, are inside div.gallery; they are positioned absolutely relative to their parent, div.gallery, so that they are not limited to being entirely on top of the images.
- div.viewport is inside div.gallery and is the div in which images are displayed. It is given overflow: hidden so that the list of images before and after the current image are not visible. It is given position: absolute with left: 0; right: 0; top: 0; bottom:0; so as to fill div.gallery.
- div.viewport contains a simple ul, one li element for each image. It is given position:relative; and given width:100%; height:100% so as to fill div.viewport.
- Each li, which is given display: inline-block; so as to be inline but be subject to sizing manipulations, contains an img tag for an image in the slideshow and a p element to contain a caption. Each li is positioned absolutely, the image is positioned absolutely using the top/bottom/left/right: 0; trick so as to fill its container, and the p element is positioned absolutely with bottom/left/right: 0; and no height value so that its height stretches to fill its contents without overflowing div.viewport and being clipped.
Those are the basics. It is as simple as possible – a couple nested divs and a list of slides that each contain an image and a caption. It is very barebones and will not suffice for more sophisticated needs, but it perfectly suited our purposes and is very lightweight.
jQuery: As for the functionality, we simply used jQuery and $.animate() on clicking the next/back buttons to transition between slides by altering the absolute positioning of the li elements modulo the total width of all of the images.
Looping: There was only one issue with our barebones gallery: looping. At first, clicking the “next” button on the last slide would pan leftwards to the first slide. The client didn’t like this.
The solution that we chose was to use jQuery’s $.clone(), $.prepend(), and $.append() methods to add a copy of the first image to the end of the list and a copy of the (originally) last image to the beginning of the list. Clicking “next” on the last slide would pan to the duplicate of the first slide and then reset all slide’s absolute positioning to match being at the first element without a transition.
Duplication of the image created no overhead issues because we configured the server for aggressive caching of static resources (as should be done normally), so cloning existing images did not result in a new HTTP request due to browser caching. The result was an apparently infinitely looping gallery without too much overhead and an implementation that matched client specifications.
Shortcomings: There is one clear shortcoming to STHG. Clicking the “next” button very quickly can end up panning past the last (cloned) image and then panning all the way left. We found that this was not something that a regular user would do and we had a contractual deadline for the project, so the issue remains unresolved.
We plan on correcting this issue before reusing the code (and on deploying the update to our client when we do update it). If you would like to implement a fix yourself, we’d be happy to merge a good pull request to the GitHub repository.
The name: STHG stands for “Simple Trivial Hamiltonian Gallery”. In graph theory, a path in a graph that visits each vertex exactly once is a Hamiltonian path. (A Hamiltonian cycle is a Hamiltonian path that ends at its starting vertex, but the extra letter seemed a bit much.) Since this gallery simply loops in the same order, it is functionally equivalent to traversing a Hamiltonian cycle around a simple loop (a connected 2-regular graph), which is a trivial case of finding a Hamiltonian. Finally, the gallery was intended to be very simple, and hence Simple Trivial Hamiltonian Gallery, or STHG for short.