This article was inspired by one of my continuing education students, who delivered a final project with the effect you see above. His version used JavaScript, but I realized the same result could be achieved in pure CSS.
This effect is best suited to a group of two dozen items or less. The goal is to filter the items by type, just as a true database would, only visually. In the example above, I’ve used travel photographs by Trey Radcliff.
The gallery images could be organized in almost any way you wish: I’ve contained the photographs in a figure
element, but an unordered list or div
could work equally well. Each image receives a class
that identifies it as being a member of a particular set. As the class
is only used as a CSS reference, and not as an actual style: an HTML5 data
attribute could be equally effective.
The interesting part of the code lies immediately above the images. HTML5 allows form elements to be placed anywhere, so we can add a series of radio buttons with matching <label>
tags immediately above the <img>
elements. The for
attribute on each <label>
will turn the associated radio button with a matching id
value on and off; as the buttons all share the same name
value, activation of one button will turn the others off.
<input type="radio" name="zoom" id="france">
<label for="france">France</label>
<input type="radio" name="zoom" id="japan">
<label for="japan">Japan</label>
<input type="radio" name="zoom" id="us">
<label for="us">United States</label>
<figure id="zoom-gallery">
<img src="central-park-in-fall.jpg" alt="Central Park In Fall" class="us">
<img src="kyoto-bamboo-walk.jpg" alt="Kyoto bamboo walk" class="japan">
<img src="kyoto-forest-walk.jpg" alt="Kyoto forest walk" class="japan">
<img src="paris-reflected.jpg" alt="Paris reflected" class="france">
<img src="paris-skyline.jpg" alt="Paris skyline" class="france">
<img src="yosemite-clouds.jpg"" alt="Yosemite clouds" class="us">
</figure>
Now for the CSS. We’ll start with a basic setup:
figure#zoom-gallery {
margin: 0;
padding: 0;
}
figure#zoom-gallery img {
width: 40%;
max-width: 300px;
margin: 3%;
transition: .7s all ease-in-out;
}
label {
color: #fff;
font-family: Futura, Arial, sans-serif;
padding: 1em;
}
(I’ve removed vendor prefixes from the code to keep it clean.)
Starting with a variation of the :checked
CSS I have talked about previously, we add a sibling selector to zoom images in a particular set. I’ll show one example, for the photographs taken in Japan:
input#japan:checked ~ figure img.japan {
transform: scale(1.1);
}
At the same time, we want to diminish any images in the gallery that are not in that particular set. Appropriately enough, we use the :not
selector. Again, for the photographs from taken of Japan:
input#japan:checked ~ figure img:not(.japan) {
transform: scale(0.9);
opacity: 0.6;
}
Optionally, you can hide the radio buttons by setting them to display: none
, leveraging the accessibility of the label
elements to allow the :checked
declarations to operate regardless. If you add this, it makes sense to place a :hover
effect on the labels to make it clear that they act as links:
input[type="radio"] {
display: none;
}
label:hover {
cursor: pointer;
}
While there are many possible improvements that could be made – I’ve added an animated box-shadow
to the image elements – that’s essentially it. The only downside to this approach versus a JavaScript solution is that it does not scale, but that’s not an issue when the number of elements is small and unchanging.
Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/fGmrw