The Simple CSS Gallery I demonstrated on this blog several years ago is an easy and popular means of creating an image portfolio without the complications of JavaScript or PHP. There are just two issues with the technique: the gallery first appears without a large default “hero” image, and it takes the user hovering over a thumbnail to present one.
In response to a recent request in comments, I’ve written a tutorial showing how to create a similar gallery using :target to produce a default image with on-click interaction. As promised, today’s entry demonstrates another method. This technique is slightly more advanced, but has the benefit of not requiring a JavaScript fallback.
The Trick
The technique uses a variation of a “CSS hack” I’ve discussed in two previous articles, Window Toggle Events and A Visual Database Gallery. It exploits five features of HTML5:
inputelements can appear anywhere on a page, and do not need to be associated with a forma
labelwith the correct attribute value will function as a surrogate control for theradiobutton it is paired witha
radiobutton does not have to be visible for this relationship to be valid, so long as the markup is validlabelelements can have images as content, rather than textCSS can monitor the status of a radio button via the
:checkedpseudo-selector
To make all of this work, the HTML for the page must be correct and valid, so that’s what I’ll concentrate on first.
The Thumbnails
<label for=vallbona><img src="thumbnails/vallbona-de-les-monges.jpg" alt="Vallbona de les Monges" ></label>
<input type="radio" id="vallbona" name="churchy">
<label for="woodward"><img src="thumbnails/woodward-avenue-presbyterian.jpg" alt="Woodward Avenue Presbyterian "></label>
<input type="radio" id="woodward" name="churchy">
<label for="woodward2"><img src="thumbnails/woodward-avenue-presbyterian2.jpg" alt="Woodward Avenue Presbyterian"></label>
<input type="radio" id="woodward2" name="churchy">
For ease of use, the thumbnail images are all relatively small and share the same aspect ratio.
There are just three rules to follow in the markup above:
The
forattribute value in eachlabelmust match theidvalue of the associated radioinput, just like an ordinary formEach
idvalue must be uniqueAll the radio button
inputelements must share the samenamevalue so that they work to switch each other off.
It’s a good idea to add the thumbnail markup to your page first in order to check that the radio buttons (still visible at this stage) switch each other off as they are selected.
The Hero Images
The markup of the large images is even simpler. On your page, it immediately follows the code above:
<div id="churches">
<img src="vallbona-de-les-monges.jpg" id="monges" alt>
<img src="woodward-avenue-presbyterian.jpg" id="presby" alt>
<img src="woodward-avenue-presbyterian2.jpg" id="presby2" alt>
</div>
I’ve left the alt values blank for these images to keep things simple for the purpose of this example: the only requirement is that each image must have a unique id. The images I’ve used are two photographs by Rick Harris of the Woodward Avenue Presbyterian Church, in Detroit, and the Vallbona de les Monges Monastery in Catalonia, Spain by José Luis Mieza.
The CSS
The base CSS is also fairly simple:
input[type=radio] { display: none; }
label img { width: 15%; display: block; float: left; clear: left; border-right: 40px solid #111; }
label:hover { cursor: pointer; }
div#churches { width: 70%; position: relative; }
div#churches img { position: absolute; max-width: 100%; opacity: 0; transform: scale(0.8); transition: .5s all linear; }
The declarations hide the radio buttons and set the images to be responsive, with the thumbnail images to the left. I’ve added a border-right to push the large images away from the thumbnails, but there are a number of other possible ways to achieve the same result. The large images are invisible by default, and 80% of their normal size. (Note that you’d have to add vendor prefixes for older versions of Firefox and other browsers).
Now to add the interactivity:
#vallbona:checked ~ #churches img#monges { opacity: 1; transform: scale(1); }
#woodward:checked ~ #churches img#presby { opacity: 1; transform: scale(1); }
#woodward2:checked ~ #churches img#presby2 { opacity: 1; transform: scale(1); }
The selectors here are a little more complicated: I’ve removed the optional element components from before most of the ids to keep things simpler. Translated into plain English, the declarations would read as “if a radio button with a particular id is selected by the user (either by clicking on the button or its associated label) then look inside an element that follows with an id of churches. If that element contains an image with a particular id, set that final element’s opacity to 1 and its scale to normal.”
While this approach forces a CSS declaration to be written for each thumbnail-hero pair, the fact that the applied styles are always the same means that you could make things more efficient with a group combinator:
#vallbona:checked ~ #churches img#monges, #woodward:checked ~ #churches img#presby, #woodward2:checked ~ #churches img#presby2 { opacity: 1; transform: scale(1); }
Wrapping Up
How do we present one of the hero images by default? By setting a checked value in the code of its associated radio button:
<input type="radio" id="woodward" name="churchy" checked>
That’s it. A large-scale image will always be presented by default, and the user can switch to viewing another if they wish by clicking on a thumbnail label. A further advantage of this system is that the page will survive a reset and revisit, as form options are remembered by the browser.
This could, of course, be taken a lot further: I’ve enhanced the code used in the demo above by adding slide-on image captions, based in part on the CSS presented in an earlier article. Inspect the code for this gallery on CodePen
Pro CSS3 Animation, Apress, 2013
Massive Head Canon
The New Defaults
CSSslidy